From 7b83100beae4e089e5237b56d82362d4cc8a896c Mon Sep 17 00:00:00 2001 From: Leonardo Alminana Date: Wed, 14 Jun 2023 19:45:30 +0200 Subject: [PATCH 001/315] build: added android and solaris detection Signed-off-by: Leonardo Alminana --- CMakeLists.txt | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index b048ad81c47..8f910f3a31f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,6 +32,12 @@ if(CMAKE_SYSTEM_NAME MATCHES "Linux") add_definitions(-DFLB_SYSTEM_LINUX) endif() +# Define macro to identify Android system +if(CMAKE_SYSTEM_NAME MATCHES "Android") + set(FLB_SYSTEM_ANDROID On) + add_definitions(-DFLB_SYSTEM_ANDROID) +endif() + # Update CFLAGS if (MSVC) add_definitions(-D_CRT_SECURE_NO_WARNINGS) @@ -613,6 +619,23 @@ if(FLB_METRICS) FLB_DEFINITION(FLB_HAVE_METRICS) endif() +# Solaris detection +check_c_source_compiles(" + int main() { +#if !defined(__SVR4) || \ + !defined (__sun) + THIS SHOULD + CAUSE THIS CODE + NOT TO COMPILE +#endif + return 0; + }" FLB_SYSTEM_SOLARIS) + +if (FLB_SYSTEM_SOLARIS) + set(FLB_SYSTEM_SOLARIS On) + add_definitions(-DFLB_SYSTEM_SOLARIS) +endif() + # WASM if(FLB_WASM) if (FLB_SYSTEM_LINUX) From eacd823bb6fb991a027c99f36ed90fd72dabf513 Mon Sep 17 00:00:00 2001 From: Leonardo Alminana Date: Wed, 14 Jun 2023 19:46:34 +0200 Subject: [PATCH 002/315] build: added the file access abstraction files Signed-off-by: Leonardo Alminana --- src/CMakeLists.txt | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b6233d9f721..641917199d9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -80,6 +80,36 @@ set(src flb_reload.c ) +# File access abstraction layer +if(FLB_SYSTEM_WINDOWS) + set(src + ${src} + flb_file_win32.c + ) +else() + if(FLB_SYSTEM_LINUX) + set(src + ${src} + flb_file_linux.c + ) + elseif(FLB_SYSTEM_MACOS) + set(src + ${src} + flb_file_macos.c + ) + elseif(FLB_SYSTEM_FREEBSD) + set(src + ${src} + flb_file_freebsd.c + ) + endif() + + set(src + ${src} + flb_file_unix.c + ) +endif() + # Config format set(src ${src} From 3967b5abe355d06dceeb2ed5c5ff10a5938f31c1 Mon Sep 17 00:00:00 2001 From: Leonardo Alminana Date: Wed, 14 Jun 2023 19:48:37 +0200 Subject: [PATCH 003/315] file: renamed flb_file_read Signed-off-by: Leonardo Alminana --- src/flb_file.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/flb_file.c b/src/flb_file.c index 2225bc3c927..b4e11bb9bd0 100644 --- a/src/flb_file.c +++ b/src/flb_file.c @@ -18,14 +18,16 @@ * limitations under the License. */ +#include #include #include #include #include +#include #include -flb_sds_t flb_file_read(const char *path) +flb_sds_t flb_file_read_contents(const char *path) { long flen; FILE *f = NULL; From 8b2f75a84a352269143226df27801d4be2382570 Mon Sep 17 00:00:00 2001 From: Leonardo Alminana Date: Wed, 14 Jun 2023 19:49:52 +0200 Subject: [PATCH 004/315] file: initial commit of the platform specific file abstraction layer Signed-off-by: Leonardo Alminana --- include/fluent-bit/flb_file.h | 77 ++- include/fluent-bit/flb_file_unix.h | 43 ++ include/fluent-bit/flb_file_win32.h | 44 ++ src/flb_file_freebsd.c | 63 ++ src/flb_file_linux.c | 62 ++ src/flb_file_macos.c | 59 ++ src/flb_file_unix.c | 386 ++++++++++++ src/flb_file_win32.c | 911 ++++++++++++++++++++++++++++ 8 files changed, 1643 insertions(+), 2 deletions(-) create mode 100644 include/fluent-bit/flb_file_unix.h create mode 100644 include/fluent-bit/flb_file_win32.h create mode 100644 src/flb_file_freebsd.c create mode 100644 src/flb_file_linux.c create mode 100644 src/flb_file_macos.c create mode 100644 src/flb_file_unix.c create mode 100644 src/flb_file_win32.c diff --git a/include/fluent-bit/flb_file.h b/include/fluent-bit/flb_file.h index 0fbb357bcfb..61eb6acbe30 100644 --- a/include/fluent-bit/flb_file.h +++ b/include/fluent-bit/flb_file.h @@ -22,8 +22,81 @@ #define FLB_FILE_H #include +#include +#include -flb_sds_t flb_file_read(const char *path); -// TODO int flb_file_write(const char *path, flb_sds_t contents); +#ifdef FLB_SYSTEM_WINDOWS +#include +#else +#include +#endif + +#define FLB_FILE_GLOB_ABORT_ON_ERROR (((uint64_t) 1) << 0) +#define FLB_FILE_GLOB_MARK_DIRECTORIES (((uint64_t) 1) << 1) +#define FLB_FILE_GLOB_DO_NOT_SORT (((uint64_t) 1) << 2) +#define FLB_FILE_GLOB_EXPAND_TILDE (((uint64_t) 1) << 3) + +#define FLB_FILE_GLOB_ERROR_SUCCESS 0 +#define FLB_FILE_GLOB_ERROR_ABORTED 1 +#define FLB_FILE_GLOB_ERROR_NO_MEMORY 2 +#define FLB_FILE_GLOB_ERROR_NO_FILE 3 +#define FLB_FILE_GLOB_ERROR_NO_ACCESS 4 +#define FLB_FILE_GLOB_ERROR_NO_MATCHES 5 +#define FLB_FILE_GLOB_ERROR_NO_MORE_RESULTS 6 +#define FLB_FILE_GLOB_ERROR_OVERSIZED_PATH 7 +#define FLB_FILE_GLOB_ERROR_INVALID_ARGUMENT 8 + +struct flb_file_glob_inner_context; + +struct flb_file_glob_context { + struct flb_file_glob_inner_context *inner_context; + uint64_t flags; + char *path; +}; + +struct flb_file_stat { + uint64_t device; + uint64_t inode; + uint16_t mode; + int64_t modification_time; + int16_t hard_link_count; + int64_t size; +}; + +int flb_file_glob_start(struct flb_file_glob_context *context, + const char *path, + uint64_t flags); + +void flb_file_glob_clean(struct flb_file_glob_context *context); + +int flb_file_glob_fetch(struct flb_file_glob_context *context, + char **result); + +flb_file_handle flb_file_open(const char *path, + unsigned int flags); + +void flb_file_close(flb_file_handle handle); + +ssize_t flb_file_read(flb_file_handle handle, + void *output_buffer, + size_t byte_count); + +int64_t flb_file_lseek(flb_file_handle handle, + int64_t offset, + int reference_point); + +int flb_file_stat(const char *path, + struct flb_file_stat *output_buffer); + +int flb_file_lstat(const char *path, + struct flb_file_stat *output_buffer); + +int flb_file_fstat(flb_file_handle handle, + struct flb_file_stat *output_buffer); + +char *flb_file_get_path(flb_file_handle handle); + +char *flb_file_basename(const char *path); +flb_sds_t flb_file_read_contents(const char *path); #endif diff --git a/include/fluent-bit/flb_file_unix.h b/include/fluent-bit/flb_file_unix.h new file mode 100644 index 00000000000..d01ed48192a --- /dev/null +++ b/include/fluent-bit/flb_file_unix.h @@ -0,0 +1,43 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Fluent Bit + * ========== + * Copyright (C) 2019-2021 The Fluent Bit Authors + * Copyright (C) 2015-2018 Treasure Data Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLB_FILE_UNIX_H +#define FLB_FILE_UNIX_H + +#define FLB_FILE_IFMT S_IFMT +#define FLB_FILE_IFIFO S_IFIFO +#define FLB_FILE_IFCHR S_IFCHR +#define FLB_FILE_IFDIR S_IFDIR +#define FLB_FILE_IFBLK S_IFBLK +#define FLB_FILE_IFREG S_IFREG +#define FLB_FILE_IFLNK S_IFLNK + +#define FLB_FILE_ISDIR(m) S_ISDIR(m) +#define FLB_FILE_ISCHR(m) S_ISCHR(m) +#define FLB_FILE_ISFIFO(m) S_ISFIFO(m) +#define FLB_FILE_ISREG(m) S_ISREG(m) +#define FLB_FILE_ISLNK(m) S_ISLNK(m) + +#define FLB_FILE_INVALID_HANDLE (-1) +#define FLB_FILE_MAX_PATH_LENGTH PATH_MAX + +typedef int flb_file_handle; + +#endif diff --git a/include/fluent-bit/flb_file_win32.h b/include/fluent-bit/flb_file_win32.h new file mode 100644 index 00000000000..88fd5745a57 --- /dev/null +++ b/include/fluent-bit/flb_file_win32.h @@ -0,0 +1,44 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Fluent Bit + * ========== + * Copyright (C) 2019-2021 The Fluent Bit Authors + * Copyright (C) 2015-2018 Treasure Data Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLB_FILE_WIN32_H +#define FLB_FILE_WIN32_H + +#define FLB_FILE_IFMT 0170000 +#define FLB_FILE_IFIFO 0010000 +#define FLB_FILE_IFCHR 0020000 +#define FLB_FILE_IFDIR 0040000 +#define FLB_FILE_IFBLK 0060000 +#define FLB_FILE_IFREG 0100000 +#define FLB_FILE_IFLNK 0120000 + +#define FLB_FILE_ISTYPE(m, t) (((m) & FLB_FILE_IFMT) == t) +#define FLB_FILE_ISDIR(m) (FLB_FILE_ISTYPE(m, FLB_FILE_IFDIR)) +#define FLB_FILE_ISCHR(m) (FLB_FILE_ISTYPE(m, FLB_FILE_IFCHR)) +#define FLB_FILE_ISFIFO(m) (FLB_FILE_ISTYPE(m, FLB_FILE_IFIFO)) +#define FLB_FILE_ISREG(m) (FLB_FILE_ISTYPE(m, FLB_FILE_IFREG)) +#define FLB_FILE_ISLNK(m) (FLB_FILE_ISTYPE(m, FLB_FILE_IFLNK)) + +#define FLB_FILE_INVALID_HANDLE (INVALID_HANDLE_VALUE) +#define FLB_FILE_MAX_PATH_LENGTH MAX_PATH + +typedef HANDLE flb_file_handle; + +#endif diff --git a/src/flb_file_freebsd.c b/src/flb_file_freebsd.c new file mode 100644 index 00000000000..266f3f63b59 --- /dev/null +++ b/src/flb_file_freebsd.c @@ -0,0 +1,63 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Fluent Bit + * ========== + * Copyright (C) 2019-2021 The Fluent Bit Authors + * Copyright (C) 2015-2018 Treasure Data Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +char *flb_file_get_path(flb_file_handle handle) +{ + char *buf; + struct kinfo_file *file_entries; + int file_count; + int file_index; + + buf = flb_calloc(sizeof(char), PATH_MAX); + + if (buf == NULL) { + flb_errno(); + return NULL; + } + + if ((file_entries = kinfo_getfile(getpid(), &file_count)) == NULL) { + flb_free(buf); + return NULL; + } + + for (file_index=0; file_index < file_count; file_index++) { + if (file_entries[file_index].kf_fd == handle) { + strncpy(buf, file_entries[file_index].kf_path, PATH_MAX - 1); + buf[PATH_MAX - 1] = 0; + break; + } + } + + free(file_entries); + + return buf; +} diff --git a/src/flb_file_linux.c b/src/flb_file_linux.c new file mode 100644 index 00000000000..55cfa310a57 --- /dev/null +++ b/src/flb_file_linux.c @@ -0,0 +1,62 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Fluent Bit + * ========== + * Copyright (C) 2019-2021 The Fluent Bit Authors + * Copyright (C) 2015-2018 Treasure Data Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include + +#include + +char *flb_file_get_path(flb_file_handle handle) +{ + int ret; + char *buf; + ssize_t s; + char tmp[128]; + + buf = flb_calloc(sizeof(char), PATH_MAX); + + if (buf == NULL) { + flb_errno(); + return NULL; + } + + ret = snprintf(tmp, sizeof(tmp) - 1, "/proc/%i/fd/%i", getpid(), handle); + if (ret == -1) { + flb_errno(); + flb_free(buf); + return NULL; + } + + s = readlink(tmp, buf, PATH_MAX); + + if (s == -1) { + flb_free(buf); + flb_errno(); + return NULL; + } + + buf[s] = '\0'; + + return buf; +} diff --git a/src/flb_file_macos.c b/src/flb_file_macos.c new file mode 100644 index 00000000000..6aaa0f12735 --- /dev/null +++ b/src/flb_file_macos.c @@ -0,0 +1,59 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Fluent Bit + * ========== + * Copyright (C) 2019-2021 The Fluent Bit Authors + * Copyright (C) 2015-2018 Treasure Data Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include + +#include + +char *flb_file_get_path(flb_file_handle handle) +{ + int ret; + char *buf; + char path[PATH_MAX]; + int len; + + buf = flb_calloc(sizeof(char), PATH_MAX); + + if (buf == NULL) { + flb_errno(); + return NULL; + } + + ret = fcntl(handle, F_GETPATH, path); + + if (ret == -1) { + flb_errno(); + flb_free(buf); + return NULL; + } + + len = strlen(path); + + memcpy(buf, path, len); + + buf[len] = '\0'; + + return buf; +} diff --git a/src/flb_file_unix.c b/src/flb_file_unix.c new file mode 100644 index 00000000000..d8e48840eb3 --- /dev/null +++ b/src/flb_file_unix.c @@ -0,0 +1,386 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Fluent Bit + * ========== + * Copyright (C) 2019-2021 The Fluent Bit Authors + * Copyright (C) 2015-2018 Treasure Data Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#ifndef GLOB_TILDE +static char *expand_tilde(const char *path, + int *expansion_attempted) +{ + int len; + char user[256]; + char *p = NULL; + char *dir = NULL; + char *tmp = NULL; + struct passwd *uinfo = NULL; + + if (expansion_attempted != NULL) { + expansion_attempted = FLB_TRUE; + } + + if (path[0] == '~') { + p = strchr(path, '/'); + + if (p) { + /* check case '~/' */ + if ((p - path) == 1) { + dir = getenv("HOME"); + if (!dir) { + return flb_strdup(path); + } + } + else { + /* + * it refers to a different user: ~user/abc, first step grab + * the user name. + */ + len = (p - path) - 1; + memcpy(user, path + 1, len); + user[len] = '\0'; + + /* use getpwnam() to resolve user information */ + uinfo = getpwnam(user); + if (!uinfo) { + return flb_strdup(path); + } + + dir = uinfo->pw_dir; + } + } + else { + dir = getenv("HOME"); + if (!dir) { + return path; + } + } + + if (p) { + tmp = flb_malloc(PATH_MAX); + if (!tmp) { + flb_errno(); + return NULL; + } + snprintf(tmp, PATH_MAX - 1, "%s%s", dir, p); + } + else { + dir = getenv("HOME"); + if (!dir) { + return flb_strdup(path); + } + + tmp = flb_strdup(dir); + if (!tmp) { + return flb_strdup(path); + } + } + + return tmp; + } + + return flb_strdup(path); +} +#else +static char *expand_tilde(const char *path, + int *expansion_attempted) +{ + if (expansion_attempted != NULL) { + expansion_attempted = FLB_FALSE; + } + + return flb_strdup(path); +} +#endif + +static void convert_stat_buffer(struct flb_file_stat *output_buffer, + struct stat *input_buffer) +{ + output_buffer->device = (uint64_t) input_buffer->st_dev; + output_buffer->inode = (uint64_t) input_buffer->st_ino; + output_buffer->mode = (uint16_t) input_buffer->st_mode; + output_buffer->hard_link_count = (uint16_t) input_buffer->st_nlink; + output_buffer->size = (uint64_t) input_buffer->st_size; + +#if (defined(FLB_SYSTEM_MACOS) && !defined(_POSIX_C_SOURCE)) + output_buffer->modification_time = + (int64_t) input_buffer->st_mtimespec.tv_sec; + +#elif (defined(FLB_SYSTEM_LINUX) || \ + defined(FLB_SYSTEM_FREEBSD) || \ + defined(FLB_SYSTEM_ANDROID) || \ + defined(FLB_SYSTEM_SOLARIS) || \ + _POSIX_C_SOURCE >= 200809L || \ + defined(_BSD_SOURCE) || \ + defined(_SVID_SOURCE)) + + output_buffer->modification_time = + (int64_t) input_buffer->st_mtim.tv_sec; +#else + output_buffer->modification_time = + (int64_t) input_buffer->st_mtime; +#endif +} + +flb_file_handle flb_file_open(const char *path, unsigned int flags) +{ + return open(path, flags); +} + +void flb_file_close(flb_file_handle handle) +{ + if (handle != FLB_FILE_INVALID_HANDLE) { + close(handle); + } +} + +ssize_t flb_file_read(flb_file_handle handle, + void *output_buffer, + size_t byte_count) +{ + return read(handle, output_buffer, byte_count); +} + +int64_t flb_file_lseek(flb_file_handle handle, + int64_t offset, + int reference_point) +{ + return (int64_t) lseek(handle, (off_t) offset, reference_point); +} + +int flb_file_stat(const char *path, + struct flb_file_stat *output_buffer) +{ + struct stat stat_buffer; + int result; + + result = stat(path, &stat_buffer); + + if (result != -1) { + convert_stat_buffer(output_buffer, &stat_buffer); + } + + return result; +} + +int flb_file_lstat(const char *path, + struct flb_file_stat *output_buffer) +{ + struct stat stat_buffer; + int result; + + result = lstat(path, &stat_buffer); + + if (result != -1) { + convert_stat_buffer(output_buffer, &stat_buffer); + } + + return result; +} + +int flb_file_fstat(flb_file_handle handle, + struct flb_file_stat *output_buffer) +{ + struct stat stat_buffer; + int result; + + result = fstat(handle, &stat_buffer); + + if (result != -1) { + convert_stat_buffer(output_buffer, &stat_buffer); + } + + return result; +} + +char *flb_file_basename(const char *path) +{ + char *mutable_path; + char *result; + char *name; + + mutable_path = NULL; + result = NULL; + name = NULL; + + mutable_path = flb_strdup(path); + + if (mutable_path != NULL) { + name = basename(mutable_path); + + if (name != NULL) { + result = flb_strdup(name); + + if (result == NULL) { + flb_errno(); + } + } + else { + flb_errno(); + } + + flb_free(mutable_path); + } + else { + flb_errno(); + } + + return result; +} + +struct flb_file_glob_inner_context { + glob_t results; + size_t index; + uint64_t flags; +}; + +int flb_file_glob_start(struct flb_file_glob_context *context, + const char *path, + uint64_t flags) +{ + int tilde_expansion_attempted; + struct flb_file_stat path_stat; + int result; + + if (context == NULL) { + return -1; + } + + memset(context, 0, sizeof(struct flb_file_glob_context)); + + context->inner_context = + flb_calloc(1, sizeof(struct flb_file_glob_inner_context)); + + if (context->inner_context == NULL) { + return -2; + } + + context->inner_context->flags = 0; + context->flags = flags; + + if (flags & FLB_FILE_GLOB_ABORT_ON_ERROR) { + context->inner_context->flags |= GLOB_ERR; + } + + if (flags & FLB_FILE_GLOB_EXPAND_TILDE) { + tilde_expansion_attempted = FLB_FALSE; + + context->path = expand_tilde(path, &tilde_expansion_attempted); + + if (tilde_expansion_attempted == FLB_FALSE) { + context->inner_context->flags |= GLOB_TILDE; + } + } + else { + context->path = flb_strdup(path); + } + + if (context->path == NULL) { + flb_file_glob_clean(context); + + return -3; + } + + result = glob(context->path, + context->inner_context->flags, + NULL, + &context->inner_context->results); + + if (result == GLOB_ABORTED) { + result = FLB_FILE_GLOB_ERROR_ABORTED; + } + else if (result == GLOB_NOSPACE) { + result = FLB_FILE_GLOB_ERROR_NO_MEMORY; + } + else if (result == GLOB_NOMATCH) { + result = flb_file_stat(context->path, &path_stat); + + if (result == -1) { + result = FLB_FILE_GLOB_ERROR_NO_FILE; + } + else { + result = access(context->path, R_OK); + + if (result == -1 && errno == EACCES) { + result = FLB_FILE_GLOB_ERROR_NO_ACCESS; + } + else { + result = FLB_FILE_GLOB_ERROR_NO_MATCHES; + } + } + } + else { + result = FLB_FILE_GLOB_ERROR_SUCCESS; + } + + return result; +} + +void flb_file_glob_clean(struct flb_file_glob_context *context) +{ + if (context != NULL) { + if (context->path != NULL) { + flb_free(context->path); + } + + if (context->inner_context != NULL) { + globfree(&context->inner_context->results); + + flb_free(context->inner_context); + } + + memset(context, 0, sizeof(struct flb_file_glob_context)); + } +} + +int flb_file_glob_fetch(struct flb_file_glob_context *context, + char **result) +{ + if (context == NULL) { + return FLB_FILE_GLOB_ERROR_NO_MEMORY; + } + + if (result == NULL) { + return FLB_FILE_GLOB_ERROR_NO_MEMORY; + } + + *result = NULL; + + if (context->inner_context->index >= + context->inner_context->results.gl_pathc) { + return FLB_FILE_GLOB_ERROR_NO_MORE_RESULTS; + } + + *result = context->inner_context->results.gl_pathv[ + context->inner_context->index]; + + context->inner_context->index++; + + return FLB_FILE_GLOB_ERROR_SUCCESS; +} diff --git a/src/flb_file_win32.c b/src/flb_file_win32.c new file mode 100644 index 00000000000..d54e28c10a9 --- /dev/null +++ b/src/flb_file_win32.c @@ -0,0 +1,911 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Fluent Bit + * ========== + * Copyright (C) 2019-2021 The Fluent Bit Authors + * Copyright (C) 2015-2018 Treasure Data Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* + * NTFS stat(2) emulation tailored for in_tail's usage. + * + * (1) Support st_ino (inode) for Windows NTFS. + * (2) Support NTFS symlinks. + * (3) Support large files >= 2GB. + * + * To use it, include "win32.h" and it will transparently + * replace stat(), lstat() and fstat(). + */ + +#define WINDOWS_TICKS_TO_SECONDS_RATIO 10000000 +#define WINDOWS_EPOCH_TO_UNIX_EPOCH_DELTA 11644473600 + +/* + * FILETIME timestamps are represented in 100-nanosecond intervals, + * because of this, that's why we need to divide the number by 10000000 + * in order to convert it to seconds. + * + * While UNIX timestamps use January 1, 1970 as epoch Windows FILETIME + * timestamps use January 1, 1601. Because of this we need to subtract + * 11644473600 seconds to account for it. + * + * Note: Even though this does not account for leap seconds it should be + * accurate enough. + */ + +static uint64_t filetime_to_epoch(FILETIME *ft) +{ + ULARGE_INTEGER timestamp; + + if (ft == NULL) { + return 0; + } + + timestamp.HighPart = ft->dwHighDateTime; + timestamp.LowPart = ft->dwLowDateTime; + + timestamp.QuadPart /= WINDOWS_TICKS_TO_SECONDS_RATIO; + timestamp.QuadPart -= WINDOWS_EPOCH_TO_UNIX_EPOCH_DELTA; + + return timestamp.QuadPart; +} + +static void reset_errno() +{ + errno = 0; +} + +static void propagate_last_error_to_errno() +{ + DWORD error_code; + + error_code = GetLastError(); + + switch (error_code) { + case ERROR_INVALID_TARGET_HANDLE: + case ERROR_INVALID_HANDLE: + errno = EBADF; + break; + + case ERROR_TOO_MANY_OPEN_FILES: + errno = EMFILE; + break; + + case ERROR_INVALID_FLAG_NUMBER: + case ERROR_INVALID_PARAMETER: + errno = EINVAL; + break; + + case ERROR_NOT_ENOUGH_MEMORY: + case ERROR_OUTOFMEMORY: + errno = ENOMEM; + break; + + case ERROR_SHARING_VIOLATION: + case ERROR_LOCK_VIOLATION: + case ERROR_PATH_BUSY: + case ERROR_BUSY: + errno = EBUSY; + break; + + case ERROR_HANDLE_DISK_FULL: + case ERROR_DISK_FULL: + errno = ENOSPC; + break; + + case ERROR_INVALID_ADDRESS: + errno = EFAULT; + break; + + case ERROR_FILE_TOO_LARGE: + errno = EFBIG; + break; + + case ERROR_ALREADY_EXISTS: + case ERROR_FILE_EXISTS: + errno = EEXIST; + break; + + case ERROR_FILE_NOT_FOUND: + case ERROR_PATH_NOT_FOUND: + case ERROR_INVALID_DRIVE: + case ERROR_BAD_PATHNAME: + case ERROR_INVALID_NAME: + case ERROR_BAD_UNIT: + errno = ENOENT; + break; + + case ERROR_SEEK_ON_DEVICE: + errno = ESPIPE; + break; + + case ERROR_NEGATIVE_SEEK: + errno = EINVAL; + break; + + case ERROR_ACCESS_DENIED: + errno = EACCES; + break; + + case ERROR_DIR_NOT_EMPTY: + errno = ENOTEMPTY; + break; + + case ERROR_BROKEN_PIPE: + errno = EPIPE; + break; + + case ERROR_GEN_FAILURE: + errno = EIO; + break; + + case ERROR_OPEN_FAILED: + errno = EIO; + break; + + case ERROR_SUCCESS: + errno = 0; + break; + + default: + /* This is just a canary, if you find this + * error then it means we need to expand the + * translation list. + */ + + errno = EOWNERDEAD; + break; + } +} + +static int is_symlink(const char *path) +{ + WIN32_FIND_DATA data; + HANDLE h; + + SetLastError(0); + reset_errno(); + + h = FindFirstFileA(path, &data); + + if (h == INVALID_HANDLE_VALUE) { + propagate_last_error_to_errno(); + + return 0; + } + + FindClose(h); + + /* + * A NTFS symlink is a file with a bit of metadata ("reparse point"), + * So (1) check if the file has metadata and then (2) confirm that + * it is indeed a symlink. + */ + if (data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { + if (data.dwReserved0 == IO_REPARSE_TAG_SYMLINK) { + return 1; + } + } + + return 0; +} + +flb_file_handle flb_file_open(const char *path, unsigned int flags) +{ + DWORD creation_disposition; + DWORD sharing_disposition; + DWORD desired_access; + HANDLE handle; + + creation_disposition = OPEN_EXISTING; + sharing_disposition = FILE_SHARE_READ | + FILE_SHARE_WRITE | + FILE_SHARE_DELETE; + desired_access = 0; + + if (flags == O_RDONLY) { + desired_access |= FILE_READ_DATA; + } + else if (flags == O_WRONLY) { + desired_access |= FILE_WRITE_DATA; + } + else if (flags == O_RDWR) { + desired_access |= FILE_READ_DATA; + desired_access |= FILE_WRITE_DATA; + } + + if ((flags & O_APPEND) != 0) { + desired_access |= FILE_APPEND_DATA; + } + + if ((flags & O_CREAT) != 0) { + if ((flags & O_EXCL) != 0) { + creation_disposition = CREATE_NEW; + } + else { + if ((flags & O_TRUNC) != 0) { + creation_disposition = CREATE_ALWAYS; + } + else { + creation_disposition = OPEN_ALWAYS; + } + } + } + else if ((flags & O_TRUNC) != 0) { + creation_disposition = TRUNCATE_EXISTING; + } + + handle = CreateFileA(path, + desired_access, + sharing_disposition, + NULL, + creation_disposition, + 0, + NULL); + + if (handle == INVALID_HANDLE_VALUE) { + return FLB_FILE_INVALID_HANDLE; + } + + return handle; +} + +void flb_file_close(flb_file_handle handle) +{ + if (handle != FLB_FILE_INVALID_HANDLE) { + CloseHandle(handle); + } +} + +ssize_t flb_file_read(flb_file_handle handle, + void *output_buffer, + size_t byte_count) +{ + DWORD bytes_read; + DWORD result; + + bytes_read = 0; + + result = ReadFile(handle, + output_buffer, + byte_count, + &bytes_read, + NULL); + + if (result == 0) { + propagate_last_error_to_errno(); + + return -1; + } + + return (ssize_t) bytes_read; +} + +int64_t flb_file_lseek(flb_file_handle handle, + int64_t offset, + int reference_point) +{ + LONG distance_high; + LONG distance_low; + DWORD result; + + distance_high = (LONG) ((offset & 0xFFFFFFFF00000000) >> 32); + distance_low = (LONG) ((offset & 0x00000000FFFFFFFF)); + + if (reference_point == SEEK_SET) { + reference_point = FILE_BEGIN; + } + else if (reference_point == SEEK_CUR) { + reference_point = FILE_CURRENT; + } + else if (reference_point == SEEK_END) { + reference_point = FILE_END; + } + else { + return -1; + } + + result = SetFilePointer(handle, + distance_low, + &distance_high, + reference_point); + + if (result == INVALID_SET_FILE_POINTER) { + propagate_last_error_to_errno(); + + return -1; + } + + offset = (int64_t) (((uint64_t) distance_high) << 32); + offset |= (int64_t) (((uint64_t) result)); + + return offset; +} + +static int flb_file_hstat(HANDLE handle, + struct flb_file_stat *output_buffer) +{ + FILE_STANDARD_INFO standard_info; + BY_HANDLE_FILE_INFORMATION handle_info; + DWORD result; + + SetLastError(0); + reset_errno(); + + result = GetFileInformationByHandle(handle, &handle_info); + + if (result == 0) { + propagate_last_error_to_errno(); + + return -1; + } + + result = GetFileInformationByHandleEx(handle, + FileStandardInfo, + &standard_info, + sizeof(standard_info)); + + if (result == 0) { + propagate_last_error_to_errno(); + + return -1; + } + + memset(output_buffer, 0, sizeof(struct flb_file_stat)); + + if (standard_info.DeletePending == 0) { + output_buffer->hard_link_count = standard_info.NumberOfLinks; + } + else { + output_buffer->hard_link_count = 0; + } + + output_buffer->mode = 0; + + if ((handle_info.dwFileAttributes & + FILE_ATTRIBUTE_DIRECTORY) != 0) { + output_buffer->mode = FLB_FILE_IFDIR; + } + else if ((handle_info.dwFileAttributes & + FILE_ATTRIBUTE_REPARSE_POINT) != 0) { + output_buffer->mode = FLB_FILE_IFLNK; + } + else { + output_buffer->mode = FLB_FILE_IFREG; + } + + output_buffer->size = (uint64_t) handle_info.nFileSizeHigh; + output_buffer->size <<= 32; + output_buffer->size |= (uint64_t) handle_info.nFileSizeLow; + + output_buffer->inode = (uint64_t) handle_info.nFileIndexHigh; + output_buffer->inode <<= 32; + output_buffer->inode |= (uint64_t) handle_info.nFileIndexLow; + + output_buffer->modification_time = + filetime_to_epoch(&handle_info.ftLastWriteTime); + + return 0; +} + +int flb_file_stat(const char *path, + struct flb_file_stat *output_buffer) +{ + HANDLE handle; + int result; + + SetLastError(0); + reset_errno(); + + handle = CreateFileA(path, + GENERIC_READ, + FILE_SHARE_READ | + FILE_SHARE_WRITE | + FILE_SHARE_DELETE, + NULL, + OPEN_EXISTING, + 0, + NULL); + + if (handle == INVALID_HANDLE_VALUE) { + propagate_last_error_to_errno(); + + return -1; + } + + result = flb_file_hstat(handle, output_buffer); + + CloseHandle(handle); + + return result; +} + +int flb_file_lstat(const char *path, + struct flb_file_stat *output_buffer) +{ + HANDLE handle; + int result; + + SetLastError(0); + reset_errno(); + + handle = CreateFileA(path, + GENERIC_READ, + FILE_SHARE_READ | + FILE_SHARE_WRITE | + FILE_SHARE_DELETE, + NULL, + OPEN_EXISTING, + FILE_FLAG_OPEN_REPARSE_POINT, + NULL); + + if (handle == INVALID_HANDLE_VALUE) { + propagate_last_error_to_errno(); + + return -1; + } + + result = flb_file_hstat(handle, output_buffer); + + CloseHandle(handle); + + if (result != 0) { + return -1; + } + + if (is_symlink(path)) { + output_buffer->mode = FLB_FILE_IFLNK; + } + + return 0; +} + +int flb_file_fstat(flb_file_handle handle, + struct flb_file_stat *output_buffer) +{ + return flb_file_hstat(handle, output_buffer); +} + +char *flb_file_get_path(flb_file_handle handle) +{ + char *buf; + int len; + + buf = flb_calloc(sizeof(char), PATH_MAX); + + if (buf == NULL) { + flb_errno(); + return NULL; + } + + /* This function returns the length of the string excluding "\0" + * and the resulting path has a "\\?\" prefix. + */ + len = GetFinalPathNameByHandleA(handle, buf, PATH_MAX, FILE_NAME_NORMALIZED); + + if (len == 0 || len >= PATH_MAX) { + flb_free(buf); + return NULL; + } + + if (strstr(buf, "\\\\?\\")) { + memmove(buf, buf + 4, len + 1); + } + + return buf; +} + +char *flb_file_basename(const char *path) +{ + char *mutable_path; + char *result; + char *name; + + mutable_path = NULL; + result = NULL; + name = NULL; + + mutable_path = flb_strdup(path); + + if (mutable_path != NULL) { + name = basename(mutable_path); + + if (name != NULL) { + result = flb_strdup(name); + + if (result == NULL) { + flb_errno(); + } + } + else { + flb_errno(); + } + + flb_free(mutable_path); + } + else { + flb_errno(); + } + + return result; +} + + +struct flb_file_glob_inner_entry { + char *path; + struct cfl_list _head; +}; + +struct flb_file_glob_inner_context { + struct flb_file_glob_inner_entry *current_entry; + struct cfl_list results; + size_t entries; + size_t index; + uint64_t flags; +}; + +static int limited_win32_glob_append_entry( + struct flb_file_glob_inner_context *context, + char *path, + uint16_t mode_filter) +{ + char entry_path_buffer[FLB_FILE_MAX_PATH_LENGTH]; + char *entry_path; + struct flb_file_stat entry_info; + int result; + struct flb_file_glob_inner_entry *entry; + + result = flb_file_stat(path, &entry_info); + + if (result != 0) { + result = FLB_FILE_GLOB_ERROR_NO_FILE; + } + else { + result = FLB_FILE_GLOB_ERROR_SUCCESS; + + if (mode_filter != 0) { + if (!FLB_FILE_ISTYPE(entry_info.mode, mode_filter)) { + result = FLB_FILE_GLOB_ERROR_NO_MATCHES; + } + } + } + + if (result == FLB_FILE_GLOB_ERROR_SUCCESS) { + entry_path = _fullpath(entry_path_buffer, + path, + FLB_FILE_MAX_PATH_LENGTH); + + if (entry_path == NULL) { + result = FLB_FILE_GLOB_ERROR_OVERSIZED_PATH; + } + } + + if (result == FLB_FILE_GLOB_ERROR_SUCCESS) { + entry = flb_calloc(1, sizeof(struct flb_file_glob_inner_entry)); + + if (entry == NULL) { + return FLB_FILE_GLOB_ERROR_NO_MEMORY; + } + + entry->path = flb_strdup(entry_path); + + if (entry->path == NULL) { + flb_free(entry); + + return FLB_FILE_GLOB_ERROR_NO_MEMORY; + } + + cfl_list_append(&entry->_head, &context->results); + + context->entries++; + } + + return result; +} + +/* + * Perform patern match on the given path string. This function + * supports patterns with "nested" wildcards like below. + * + * tail_scan_pattern("C:\fluent-bit\*\*.txt", ctx); + * + * On success, the number of files found is returned (zero indicates + * "no file found"). On error, -1 is returned. + */ +static int limited_win32_glob(struct flb_file_glob_inner_context *context, + char *path) +{ + char *star, *p0, *p1; + char pattern[FLB_FILE_MAX_PATH_LENGTH]; + char buf[FLB_FILE_MAX_PATH_LENGTH]; + int ret; + int n_added = 0; + time_t now; + int64_t mtime; + HANDLE h; + WIN32_FIND_DATA data; + struct flb_file_glob_inner_entry *entry; + int transverse_directory; + struct flb_file_stat entry_info; + + if (strlen(path) >= FLB_FILE_MAX_PATH_LENGTH) { + return FLB_FILE_GLOB_ERROR_OVERSIZED_PATH; + } + + star = strchr(path, '*'); + + if (star == NULL) { + return limited_win32_glob_append_entry(context, path, 0); + } + + /* + * C:\data\tmp\input_*.conf + * 0<-----| + */ + p0 = star; + while (path <= p0 && *p0 != '\\') { + p0--; + } + + /* + * C:\data\tmp\input_*.conf + * |---->1 + */ + p1 = star; + while (*p1 && *p1 != '\\') { + p1++; + } + + memcpy(pattern, path, (p1 - path)); + pattern[p1 - path] = '\0'; + + h = FindFirstFileA(pattern, &data); + + if (h == INVALID_HANDLE_VALUE) { + return FLB_FILE_GLOB_ERROR_NO_MATCHES; + } + + ret = FLB_FILE_GLOB_ERROR_SUCCESS; + + do { + /* Ignore the current and parent dirs */ + if (!strcmp(".", data.cFileName) || + !strcmp("..", data.cFileName)) { + continue; + } + + /* Avoid an infinite loop */ + if (strchr(data.cFileName, '*')) { + continue; + } + + /* Create a path (prefix + filename + suffix) */ + memcpy(buf, path, p0 - path + 1); + buf[p0 - path + 1] = '\0'; + + if ((strlen(buf) + + strlen(data.cFileName) + + strlen(p1)) >= FLB_FILE_MAX_PATH_LENGTH) { + if (context->flags & + FLB_FILE_GLOB_ABORT_ON_ERROR) { + ret = FLB_FILE_GLOB_ERROR_OVERSIZED_PATH; + + break; + } + else { + continue; + } + } + + strcat(buf, data.cFileName); + + if (strchr(p1, '*')) { + transverse_directory = FLB_FALSE; + + if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + transverse_directory = FLB_TRUE; + } + else if (data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { + ret = flb_file_stat(data.cFileName, + &entry_info); + + if (ret != 0) { + if (context->flags & + FLB_FILE_GLOB_ABORT_ON_ERROR) { + ret = FLB_FILE_GLOB_ERROR_NO_FILE; + + break; + } + } + + if (FLB_FILE_ISDIR(entry_info.mode)) { + transverse_directory = FLB_TRUE; + } + } + + if (transverse_directory) { + strcat(buf, p1); + + ret = limited_win32_glob(context, buf); + + if (ret != FLB_FILE_GLOB_ERROR_SUCCESS && + ret != FLB_FILE_GLOB_ERROR_NO_FILE && + ret != FLB_FILE_GLOB_ERROR_NO_MATCHES) { + if (context->flags & + FLB_FILE_GLOB_ABORT_ON_ERROR) { + break; + } + } + + continue; + } + } + + strcat(buf, p1); + + ret = limited_win32_glob_append_entry(context, buf, 0); + + if (ret != FLB_FILE_GLOB_ERROR_SUCCESS && + ret != FLB_FILE_GLOB_ERROR_NO_FILE) { + if (context->flags & + FLB_FILE_GLOB_ABORT_ON_ERROR) { + break; + } + } + + ret = FLB_FILE_GLOB_ERROR_SUCCESS; + } while (FindNextFileA(h, &data) != 0); + + FindClose(h); + + if (!(context->flags & + FLB_FILE_GLOB_ABORT_ON_ERROR)) { + ret = FLB_FILE_GLOB_ERROR_SUCCESS; + } + + return ret; +} + +int flb_file_glob_start(struct flb_file_glob_context *context, + const char *path, + uint64_t flags) +{ + + int tilde_expansion_attempted; + struct flb_file_stat path_stat; + int result; + + if (context == NULL) { + return -1; + } + + memset(context, 0, sizeof(struct flb_file_glob_context)); + + context->inner_context = + flb_calloc(1, sizeof(struct flb_file_glob_inner_context)); + + if (context->inner_context == NULL) { + return -2; + } + + cfl_list_init(&context->inner_context->results); + + context->inner_context->flags = 0; + context->flags = flags; + + if (flags & FLB_FILE_GLOB_ABORT_ON_ERROR) { + context->inner_context->flags |= FLB_FILE_GLOB_ABORT_ON_ERROR; + } + + context->path = flb_strdup(path); + + if (context->path == NULL) { + flb_file_glob_clean(context); + + return -3; + } + + return limited_win32_glob(context->inner_context, + context->path); +} + +void flb_file_glob_clean(struct flb_file_glob_context *context) +{ + struct cfl_list *iterator_backup; + struct cfl_list *iterator; + struct flb_file_glob_inner_entry *entry; + + if (context != NULL) { + if (context->path != NULL) { + flb_free(context->path); + } + + if (context->inner_context != NULL) { + cfl_list_foreach_safe(iterator, + iterator_backup, + &context->inner_context->results) { + entry = cfl_list_entry(iterator, + struct flb_file_glob_inner_entry, + _head); + + if (entry->path != NULL) { + flb_free(entry->path); + } + + cfl_list_del(&entry->_head); + + flb_free(entry); + } + + flb_free(context->inner_context); + } + + memset(context, 0, sizeof(struct flb_file_glob_context)); + } + +} + +int flb_file_glob_fetch(struct flb_file_glob_context *context, + char **result) +{ + + if (context == NULL) { + return FLB_FILE_GLOB_ERROR_NO_MEMORY; + } + + if (result == NULL) { + return FLB_FILE_GLOB_ERROR_NO_MEMORY; + } + + *result = NULL; + + if (context->inner_context->index >= + context->inner_context->entries) { + return FLB_FILE_GLOB_ERROR_NO_MORE_RESULTS; + } + + if (context->inner_context->current_entry == NULL) { + context->inner_context->current_entry = + cfl_list_entry_first(&context->inner_context->results, + struct flb_file_glob_inner_entry, + _head); + } + else { + context->inner_context->current_entry = + cfl_list_entry_next(&context->inner_context->current_entry->_head, + struct flb_file_glob_inner_entry, + _head, + &context->inner_context->results); + } + + *result = context->inner_context->current_entry->path; + + context->inner_context->index++; + + return FLB_FILE_GLOB_ERROR_SUCCESS; +} From 68b55c5c0ecd3a8a6c933ef70a0beec972a3683e Mon Sep 17 00:00:00 2001 From: Leonardo Alminana Date: Wed, 14 Jun 2023 19:50:40 +0200 Subject: [PATCH 005/315] tests: internal: file: updated references to renamed function Signed-off-by: Leonardo Alminana --- tests/internal/file.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/internal/file.c b/tests/internal/file.c index 974c266873e..730e2c5ceea 100644 --- a/tests/internal/file.c +++ b/tests/internal/file.c @@ -22,21 +22,21 @@ static void check_equals(flb_sds_t result, const char *expected) static void test_file_read_text_file() { - flb_sds_t result = flb_file_read(TEXT_FILE); + flb_sds_t result = flb_file_read_contents(TEXT_FILE); check_equals(result, "Some text file\n\nline 3\n\nline 5\n"); flb_sds_destroy(result); } static void test_file_read_empty_file() { - flb_sds_t result = flb_file_read(EMPTY_FILE); + flb_sds_t result = flb_file_read_contents(EMPTY_FILE); check_equals(result, ""); flb_sds_destroy(result); } static void test_file_read_missing() { - flb_sds_t result = flb_file_read(TEXT_FILE ".missing"); + flb_sds_t result = flb_file_read_contents(TEXT_FILE ".missing"); TEST_CHECK(result == NULL); } From 0646fa0cb98d9a3e6a3fe73c161946fe02f3118c Mon Sep 17 00:00:00 2001 From: Leonardo Alminana Date: Wed, 14 Jun 2023 19:51:17 +0200 Subject: [PATCH 006/315] in_tail: removed unnecessary win32 compatibility code Signed-off-by: Leonardo Alminana --- plugins/in_tail/win32.h | 67 ------ plugins/in_tail/win32/interface.h | 44 ---- plugins/in_tail/win32/io.c | 47 ----- plugins/in_tail/win32/stat.c | 332 ------------------------------ 4 files changed, 490 deletions(-) delete mode 100644 plugins/in_tail/win32.h delete mode 100644 plugins/in_tail/win32/interface.h delete mode 100644 plugins/in_tail/win32/io.c delete mode 100644 plugins/in_tail/win32/stat.c diff --git a/plugins/in_tail/win32.h b/plugins/in_tail/win32.h deleted file mode 100644 index a9414f89259..00000000000 --- a/plugins/in_tail/win32.h +++ /dev/null @@ -1,67 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -/* Fluent Bit - * ========== - * Copyright (C) 2015-2022 The Fluent Bit Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * This is the interface file that replaces POSIX functions - * with our own custom implementation. - */ - -#ifndef FLB_TAIL_WIN32_H -#define FLB_TAIL_WIN32_H - -#include "win32/interface.h" - -#undef open -#undef stat -#undef lstat -#undef fstat -#undef lseek - -#undef S_IFDIR -#undef S_IFCHR -#undef S_IFIFO -#undef S_IFREG -#undef S_IFLNK -#undef S_IFMT -#undef S_ISDIR -#undef S_ISCHR -#undef S_ISFIFO -#undef S_ISREG -#undef S_ISLNK - -#define open win32_open -#define stat win32_stat -#define lstat win32_lstat -#define fstat win32_fstat - -#define lseek _lseeki64 - -#define S_IFDIR WIN32_S_IFDIR -#define S_IFCHR WIN32_S_IFCHR -#define S_IFIFO WIN32_S_IFIFO -#define S_IFREG WIN32_S_IFREG -#define S_IFLNK WIN32_S_IFLNK -#define S_IFMT WIN32_S_IFMT - -#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) -#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) -#define S_ISIFO(m) (((m) & S_IFMT) == S_IFIFO) -#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) -#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) -#endif diff --git a/plugins/in_tail/win32/interface.h b/plugins/in_tail/win32/interface.h deleted file mode 100644 index 73b2ef233d1..00000000000 --- a/plugins/in_tail/win32/interface.h +++ /dev/null @@ -1,44 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -/* Fluent Bit - * ========== - * Copyright (C) 2015-2022 The Fluent Bit Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef FLB_TAIL_WIN32_INTERFACE_H -#define FLB_TAIL_WIN32_INTERFACE_H - -struct win32_stat { - uint64_t st_ino; - uint16_t st_mode; - int64_t st_mtime; - int16_t st_nlink; - int64_t st_size; -}; - -int win32_stat(const char *path, struct win32_stat *wst); -int win32_lstat(const char *path, struct win32_stat *wst); -int win32_fstat(int fd, struct win32_stat *wst); - -int win32_open(const char *path, int flags); - -#define WIN32_S_IFDIR 0x1000 -#define WIN32_S_IFCHR 0x2000 -#define WIN32_S_IFIFO 0x4000 -#define WIN32_S_IFREG 0x8000 -#define WIN32_S_IFLNK 0xc000 -#define WIN32_S_IFMT 0xf000 - -#endif diff --git a/plugins/in_tail/win32/io.c b/plugins/in_tail/win32/io.c deleted file mode 100644 index 45928b04a6b..00000000000 --- a/plugins/in_tail/win32/io.c +++ /dev/null @@ -1,47 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -/* Fluent Bit - * ========== - * Copyright (C) 2015-2022 The Fluent Bit Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include -#include -#include "interface.h" - -/* - * POSIX IO emulation tailored for in_tail's usage. - * - * open(2) that does not acquire an exclusive lock. - */ - -int win32_open(const char *path, int flags) -{ - HANDLE h; - h = CreateFileA(path, - GENERIC_READ, - FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, - NULL, /* lpSecurityAttributes */ - OPEN_EXISTING, /* dwCreationDisposition */ - 0, /* dwFlagsAndAttributes */ - NULL); /* hTemplateFile */ - if (h == INVALID_HANDLE_VALUE) { - return -1; - } - return _open_osfhandle((intptr_t) h, _O_RDONLY); -} diff --git a/plugins/in_tail/win32/stat.c b/plugins/in_tail/win32/stat.c deleted file mode 100644 index bce80274960..00000000000 --- a/plugins/in_tail/win32/stat.c +++ /dev/null @@ -1,332 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ - -/* Fluent Bit - * ========== - * Copyright (C) 2015-2022 The Fluent Bit Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include -#include "interface.h" - -/* - * NTFS stat(2) emulation tailored for in_tail's usage. - * - * (1) Support st_ino (inode) for Windows NTFS. - * (2) Support NTFS symlinks. - * (3) Support large files >= 2GB. - * - * To use it, include "win32.h" and it will transparently - * replace stat(), lstat() and fstat(). - */ - -#define UINT64(high, low) ((uint64_t) (high) << 32 | (low)) -#define WINDOWS_TICKS_TO_SECONDS_RATIO 10000000 -#define WINDOWS_EPOCH_TO_UNIX_EPOCH_DELTA 11644473600 - -/* - * FILETIME timestamps are represented in 100-nanosecond intervals, - * because of this, that's why we need to divide the number by 10000000 - * in order to convert it to seconds. - * - * While UNIX timestamps use January 1, 1970 as epoch Windows FILETIME - * timestamps use January 1, 1601. Because of this we need to subtract - * 11644473600 seconds to account for it. - * - * Note: Even though this does not account for leap seconds it should be - * accurate enough. - */ - -static uint64_t filetime_to_epoch(FILETIME *ft) -{ - ULARGE_INTEGER timestamp; - - if (ft == NULL) { - return 0; - } - - timestamp.HighPart = ft->dwHighDateTime; - timestamp.LowPart = ft->dwLowDateTime; - - timestamp.QuadPart /= WINDOWS_TICKS_TO_SECONDS_RATIO; - timestamp.QuadPart -= WINDOWS_EPOCH_TO_UNIX_EPOCH_DELTA; - - return timestamp.QuadPart; -} - -static void reset_errno() -{ - errno = 0; -} - -static void propagate_last_error_to_errno() -{ - DWORD error_code; - - error_code = GetLastError(); - - switch (error_code) { - case ERROR_INVALID_TARGET_HANDLE: - case ERROR_INVALID_HANDLE: - errno = EBADF; - break; - - case ERROR_TOO_MANY_OPEN_FILES: - errno = EMFILE; - break; - - case ERROR_INVALID_FLAG_NUMBER: - case ERROR_INVALID_PARAMETER: - errno = EINVAL; - break; - - case ERROR_NOT_ENOUGH_MEMORY: - case ERROR_OUTOFMEMORY: - errno = ENOMEM; - break; - - case ERROR_SHARING_VIOLATION: - case ERROR_LOCK_VIOLATION: - case ERROR_PATH_BUSY: - case ERROR_BUSY: - errno = EBUSY; - break; - - case ERROR_HANDLE_DISK_FULL: - case ERROR_DISK_FULL: - errno = ENOSPC; - break; - - case ERROR_INVALID_ADDRESS: - errno = EFAULT; - break; - - case ERROR_FILE_TOO_LARGE: - errno = EFBIG; - break; - - case ERROR_ALREADY_EXISTS: - case ERROR_FILE_EXISTS: - errno = EEXIST; - break; - - case ERROR_FILE_NOT_FOUND: - case ERROR_PATH_NOT_FOUND: - case ERROR_INVALID_DRIVE: - case ERROR_BAD_PATHNAME: - case ERROR_INVALID_NAME: - case ERROR_BAD_UNIT: - errno = ENOENT; - break; - - case ERROR_SEEK_ON_DEVICE: - case ERROR_NEGATIVE_SEEK: - errno = ESPIPE; - break; - - case ERROR_ACCESS_DENIED: - errno = EACCES; - break; - - case ERROR_DIR_NOT_EMPTY: - errno = ENOTEMPTY; - break; - - case ERROR_BROKEN_PIPE: - errno = EPIPE; - break; - - case ERROR_GEN_FAILURE: - errno = EIO; - break; - - case ERROR_OPEN_FAILED: - errno = EIO; - break; - - case ERROR_SUCCESS: - errno = 0; - break; - - default: - /* This is just a canary, if you find this - * error then it means we need to expand the - * translation list. - */ - - errno = EOWNERDEAD; - break; - } -} - -static int get_mode(unsigned int attr) -{ - if (attr & FILE_ATTRIBUTE_DIRECTORY) { - return WIN32_S_IFDIR; - } - return WIN32_S_IFREG; -} - - - -static int is_symlink(const char *path) -{ - WIN32_FIND_DATA data; - HANDLE h; - - SetLastError(0); - reset_errno(); - - h = FindFirstFileA(path, &data); - - if (h == INVALID_HANDLE_VALUE) { - propagate_last_error_to_errno(); - - return 0; - } - - FindClose(h); - - /* - * A NTFS symlink is a file with a bit of metadata ("reparse point"), - * So (1) check if the file has metadata and then (2) confirm that - * it is indeed a symlink. - */ - if (data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { - if (data.dwReserved0 == IO_REPARSE_TAG_SYMLINK) { - return 1; - } - } - - return 0; -} - -static int hstat(HANDLE h, struct win32_stat *wst) -{ - BY_HANDLE_FILE_INFORMATION info; - FILE_STANDARD_INFO std; - - SetLastError(0); - reset_errno(); - - if (!GetFileInformationByHandle(h, &info)) { - propagate_last_error_to_errno(); - - return -1; - } - - if (!GetFileInformationByHandleEx(h, FileStandardInfo, - &std, sizeof(std))) { - propagate_last_error_to_errno(); - - return -1; - } - - wst->st_nlink = std.NumberOfLinks; - if (std.DeletePending) { - wst->st_nlink = 0; - } - - wst->st_mode = get_mode(info.dwFileAttributes); - wst->st_size = UINT64(info.nFileSizeHigh, info.nFileSizeLow); - wst->st_ino = UINT64(info.nFileIndexHigh, info.nFileIndexLow); - wst->st_mtime = filetime_to_epoch(&info.ftLastWriteTime); - - return 0; -} - -int win32_stat(const char *path, struct win32_stat *wst) -{ - HANDLE h; - - SetLastError(0); - reset_errno(); - - h = CreateFileA(path, - GENERIC_READ, - FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, - NULL, /* lpSecurityAttributes */ - OPEN_EXISTING, /* dwCreationDisposition */ - 0, /* dwFlagsAndAttributes */ - NULL); /* hTemplateFile */ - - if (h == INVALID_HANDLE_VALUE) { - propagate_last_error_to_errno(); - - return -1; - } - - if (hstat(h, wst)) { - CloseHandle(h); - return -1; - } - - CloseHandle(h); - return 0; -} - -int win32_lstat(const char *path, struct win32_stat *wst) -{ - HANDLE h; - - SetLastError(0); - reset_errno(); - - h = CreateFileA(path, - GENERIC_READ, - FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, - NULL, /* lpSecurityAttributes */ - OPEN_EXISTING, /* dwCreationDisposition */ - FILE_FLAG_OPEN_REPARSE_POINT, - NULL); /* hTemplateFile */ - - if (h == INVALID_HANDLE_VALUE) { - propagate_last_error_to_errno(); - - return -1; - } - - if (hstat(h, wst)) { - CloseHandle(h); - return -1; - } - - if (is_symlink(path)) { - wst->st_mode = WIN32_S_IFLNK; - } - - CloseHandle(h); - return 0; -} - -int win32_fstat(int fd, struct win32_stat *wst) -{ - HANDLE h; - - SetLastError(0); - reset_errno(); - - h = (HANDLE) _get_osfhandle(fd); - - if (h == INVALID_HANDLE_VALUE) { - propagate_last_error_to_errno(); - - return -1; - } - - return hstat(h, wst); -} From 7f0a33a0e55ba28519da146ee724bb89406e128c Mon Sep 17 00:00:00 2001 From: Leonardo Alminana Date: Wed, 14 Jun 2023 19:51:28 +0200 Subject: [PATCH 007/315] in_tail: removed unnecessary win32 compatibility code Signed-off-by: Leonardo Alminana --- plugins/in_tail/CMakeLists.txt | 5 ----- 1 file changed, 5 deletions(-) diff --git a/plugins/in_tail/CMakeLists.txt b/plugins/in_tail/CMakeLists.txt index 31d865218d5..f2790a955bc 100644 --- a/plugins/in_tail/CMakeLists.txt +++ b/plugins/in_tail/CMakeLists.txt @@ -26,11 +26,6 @@ if(FLB_PARSER) endif() if(MSVC) - set(src - ${src} - win32/stat.c - win32/io.c - ) FLB_PLUGIN(in_tail "${src}" "Shlwapi") else() FLB_PLUGIN(in_tail "${src}" "") From bca07e1e2ca88f47dd5b7ca2fbe5347159c79512 Mon Sep 17 00:00:00 2001 From: Leonardo Alminana Date: Wed, 14 Jun 2023 19:54:30 +0200 Subject: [PATCH 008/315] in_tail: replaced platform specific code with file abstraction layer use Signed-off-by: Leonardo Alminana --- plugins/in_tail/tail.c | 17 +- plugins/in_tail/tail_file.c | 241 +++++++----------------- plugins/in_tail/tail_file.h | 88 ++------- plugins/in_tail/tail_file_internal.h | 3 +- plugins/in_tail/tail_fs_inotify.c | 2 +- plugins/in_tail/tail_fs_stat.c | 37 ++-- plugins/in_tail/tail_scan_glob.c | 238 ++++++------------------ plugins/in_tail/tail_scan_win32.c | 269 ++++++++++++--------------- 8 files changed, 294 insertions(+), 601 deletions(-) diff --git a/plugins/in_tail/tail.c b/plugins/in_tail/tail.c index 56da323e87d..18e4ce30e01 100644 --- a/plugins/in_tail/tail.c +++ b/plugins/in_tail/tail.c @@ -31,6 +31,7 @@ #include #include #include +#include #include "tail.h" #include "tail_fs.h" @@ -67,7 +68,7 @@ static int in_tail_collect_pending(struct flb_input_instance *ins, struct mk_list *head; struct flb_tail_config *ctx = in_context; struct flb_tail_file *file; - struct stat st; + struct flb_file_stat st; uint64_t pre; uint64_t total_processed = 0; @@ -77,17 +78,17 @@ static int in_tail_collect_pending(struct flb_input_instance *ins, if (file->watch_fd == -1) { /* Gather current file size */ - ret = fstat(file->fd, &st); + ret = flb_file_fstat(file->fd, &st); if (ret == -1) { flb_errno(); flb_tail_file_remove(file); continue; } - file->size = st.st_size; + file->size = st.size; file->pending_bytes = (file->size - file->offset); } else { - memset(&st, 0, sizeof(struct stat)); + memset(&st, 0, sizeof(struct flb_file_stat)); } if (file->pending_bytes <= 0) { @@ -120,8 +121,8 @@ static int in_tail_collect_pending(struct flb_input_instance *ins, * Adjust counter to verify if we need a further read(2) later. * For more details refer to tail_fs_inotify.c:96. */ - if (file->offset < st.st_size) { - file->pending_bytes = (st.st_size - file->offset); + if (file->offset < st.size) { + file->pending_bytes = (st.size - file->offset); active++; } else { @@ -319,10 +320,10 @@ static int in_tail_watcher_callback(struct flb_input_instance *ins, int in_tail_collect_event(void *file, struct flb_config *config) { int ret; - struct stat st; + struct flb_file_stat st; struct flb_tail_file *f = file; - ret = fstat(f->fd, &st); + ret = flb_file_fstat(f->fd, &st); if (ret == -1) { flb_tail_file_remove(f); return 0; diff --git a/plugins/in_tail/tail_file.c b/plugins/in_tail/tail_file.c index 4b2bfb00346..5dc69230800 100644 --- a/plugins/in_tail/tail_file.c +++ b/plugins/in_tail/tail_file.c @@ -44,10 +44,6 @@ #include "tail_multiline.h" #include "tail_scan.h" -#ifdef FLB_SYSTEM_WINDOWS -#include "win32.h" -#endif - #include static inline void consume_bytes(char *buf, int bytes, int length) @@ -55,36 +51,26 @@ static inline void consume_bytes(char *buf, int bytes, int length) memmove(buf, buf + bytes, length - bytes); } -static uint64_t stat_get_st_dev(struct stat *st) -{ -#ifdef FLB_SYSTEM_WINDOWS - /* do you want to contribute with a way to extract volume serial number ? */ - return 0; -#else - return st->st_dev; -#endif -} - -static int stat_to_hash_bits(struct flb_tail_config *ctx, struct stat *st, +static int stat_to_hash_bits(struct flb_tail_config *ctx, struct flb_file_stat *st, uint64_t *out_hash) { int len; - uint64_t st_dev; char tmp[64]; - st_dev = stat_get_st_dev(st); - - len = snprintf(tmp, sizeof(tmp) - 1, "%" PRIu64 ":%" PRIu64, - st_dev, (uint64_t)st->st_ino); + len = snprintf(tmp, + sizeof(tmp) - 1, + "%" PRIu64 ":%" PRIu64, + (uint64_t) st->device, + (uint64_t) st->inode); *out_hash = cfl_hash_64bits(tmp, len); + return 0; } -static int stat_to_hash_key(struct flb_tail_config *ctx, struct stat *st, +static int stat_to_hash_key(struct flb_tail_config *ctx, struct flb_file_stat *st, flb_sds_t *key) { - uint64_t st_dev; flb_sds_t tmp; flb_sds_t buf; @@ -93,15 +79,17 @@ static int stat_to_hash_key(struct flb_tail_config *ctx, struct stat *st, return -1; } - st_dev = stat_get_st_dev(st); - tmp = flb_sds_printf(&buf, "%" PRIu64 ":%" PRIu64, - st_dev, (uint64_t)st->st_ino); + tmp = flb_sds_printf(&buf, + "%" PRIu64 ":%" PRIu64, + (uint64_t) st->device, + (uint64_t) st->inode); if (!tmp) { flb_sds_destroy(buf); return -1; } *key = buf; + return 0; } @@ -791,7 +779,7 @@ static int tag_compose(char *tag, char *fname, char *out_buf, size_t *out_size, return 0; } -static inline int flb_tail_file_exists(struct stat *st, +static inline int flb_tail_file_exists(struct flb_file_stat *st, struct flb_tail_config *ctx) { int ret; @@ -833,14 +821,14 @@ static int set_file_position(struct flb_tail_config *ctx, ret = flb_tail_db_file_set(file, ctx); if (ret == 0) { if (file->offset > 0) { - ret = lseek(file->fd, file->offset, SEEK_SET); + ret = flb_file_lseek(file->fd, file->offset, SEEK_SET); if (ret == -1) { flb_errno(); return -1; } } else if (ctx->read_from_head == FLB_FALSE) { - ret = lseek(file->fd, 0, SEEK_END); + ret = flb_file_lseek(file->fd, 0, SEEK_END); if (ret == -1) { flb_errno(); return -1; @@ -859,7 +847,7 @@ static int set_file_position(struct flb_tail_config *ctx, } /* tail... */ - ret = lseek(file->fd, 0, SEEK_END); + ret = flb_file_lseek(file->fd, 0, SEEK_END); if (ret == -1) { flb_errno(); return -1; @@ -908,10 +896,12 @@ static int ml_flush_callback(struct flb_ml_parser *parser, return 0; } -int flb_tail_file_append(char *path, struct stat *st, int mode, +int flb_tail_file_append(char *path, + struct flb_file_stat *st, + int mode, struct flb_tail_config *ctx) { - int fd; + flb_file_handle fd; int ret; uint64_t stream_id; uint64_t ts; @@ -922,10 +912,10 @@ int flb_tail_file_append(char *path, struct stat *st, int mode, char *name; size_t tag_len; struct flb_tail_file *file; - struct stat lst; + struct flb_file_stat lst; flb_sds_t inode_str; - if (!S_ISREG(st->st_mode)) { + if (!FLB_FILE_ISREG(st->mode)) { return -1; } @@ -933,8 +923,8 @@ int flb_tail_file_append(char *path, struct stat *st, int mode, return -1; } - fd = open(path, O_RDONLY); - if (fd == -1) { + fd = flb_file_open(path, O_RDONLY); + if (fd == FLB_FILE_INVALID_HANDLE) { flb_errno(); flb_plg_error(ctx->ins, "cannot open %s", path); return -1; @@ -951,11 +941,11 @@ int flb_tail_file_append(char *path, struct stat *st, int mode, file->fd = fd; /* On non-windows environments check if the original path is a link */ - ret = lstat(path, &lst); + ret = flb_file_lstat(path, &lst); if (ret == 0) { - if (S_ISLNK(lst.st_mode)) { + if (FLB_FILE_ISLNK(lst.mode)) { file->is_link = FLB_TRUE; - file->link_inode = lst.st_ino; + file->link_inode = lst.inode; } } @@ -975,9 +965,9 @@ int flb_tail_file_append(char *path, struct stat *st, int mode, } file->hash_key = hash_key; - file->inode = st->st_ino; + file->inode = st->inode; file->offset = 0; - file->size = st->st_size; + file->size = st->size; file->buf_len = 0; file->parsed = 0; file->config = ctx; @@ -1189,7 +1179,8 @@ int flb_tail_file_append(char *path, struct stat *st, int mode, } flb_free(file); } - close(fd); + + flb_file_close(fd); return -1; } @@ -1240,8 +1231,8 @@ void flb_tail_file_remove(struct flb_tail_file *file) flb_tail_fs_remove(ctx, file); /* avoid deleting file with -1 fd */ - if (file->fd != -1) { - close(file->fd); + if (file->fd != FLB_FILE_INVALID_HANDLE) { + flb_file_close(file->fd); } if (file->tag_buf) { flb_free(file->tag_buf); @@ -1295,17 +1286,17 @@ static int adjust_counters(struct flb_tail_config *ctx, struct flb_tail_file *fi { int ret; int64_t offset; - struct stat st; + struct flb_file_stat st; - ret = fstat(file->fd, &st); + ret = flb_file_fstat(file->fd, &st); if (ret == -1) { flb_errno(); return FLB_TAIL_ERROR; } /* Check if the file was truncated */ - if (file->offset > st.st_size) { - offset = lseek(file->fd, 0, SEEK_SET); + if (file->offset > st.size) { + offset = flb_file_lseek(file->fd, 0, SEEK_SET); if (offset == -1) { flb_errno(); return FLB_TAIL_ERROR; @@ -1324,8 +1315,8 @@ static int adjust_counters(struct flb_tail_config *ctx, struct flb_tail_file *fi #endif } else { - file->size = st.st_size; - file->pending_bytes = (st.st_size - file->offset); + file->size = st.size; + file->pending_bytes = (st.size - file->offset); } return FLB_TAIL_OK; @@ -1397,7 +1388,7 @@ int flb_tail_file_chunk(struct flb_tail_file *file) capacity = (file->buf_size - file->buf_len) - 1; } - bytes = read(file->fd, file->buf_data + file->buf_len, capacity); + bytes = flb_file_read(file->fd, file->buf_data + file->buf_len, capacity); if (bytes > 0) { /* we read some data, let the content processor take care of it */ file->buf_len += bytes; @@ -1461,7 +1452,7 @@ int flb_tail_file_is_rotated(struct flb_tail_config *ctx, { int ret; char *name; - struct stat st; + struct flb_file_stat st; /* * Do not double-check already rotated files since the caller of this @@ -1473,7 +1464,7 @@ int flb_tail_file_is_rotated(struct flb_tail_config *ctx, /* Check if the 'original monitored file' is a link and rotated */ if (file->is_link == FLB_TRUE) { - ret = lstat(file->name, &st); + ret = flb_file_lstat(file->name, &st); if (ret == -1) { /* Broken link or missing file */ if (errno == ENOENT) { @@ -1491,14 +1482,14 @@ int flb_tail_file_is_rotated(struct flb_tail_config *ctx, } else { /* The file name is there, check if the same that we have */ - if (st.st_ino != file->link_inode) { + if (st.inode != file->link_inode) { return FLB_TRUE; } } } /* Retrieve the real file name, operating system lookup */ - name = flb_tail_file_name(file); + name = flb_file_get_path(file->fd); if (!name) { flb_plg_error(ctx->ins, "inode=%"PRIu64" cannot detect if file was rotated: %s", @@ -1508,7 +1499,7 @@ int flb_tail_file_is_rotated(struct flb_tail_config *ctx, /* Get stats from the file name */ - ret = stat(name, &st); + ret = flb_file_stat(name, &st); if (ret == -1) { flb_errno(); flb_free(name); @@ -1516,7 +1507,7 @@ int flb_tail_file_is_rotated(struct flb_tail_config *ctx, } /* Compare inodes and names */ - if (file->inode == st.st_ino && + if (file->inode == st.inode && flb_tail_target_file_name_cmp(name, file) == 0) { flb_free(name); return FLB_FALSE; @@ -1526,6 +1517,7 @@ int flb_tail_file_is_rotated(struct flb_tail_config *ctx, file->inode, file->name, name); flb_free(name); + return FLB_TRUE; } @@ -1533,18 +1525,18 @@ int flb_tail_file_is_rotated(struct flb_tail_config *ctx, int flb_tail_file_to_event(struct flb_tail_file *file) { int ret; - struct stat st; + struct flb_file_stat st; struct flb_tail_config *ctx = file->config; /* Check if the file promoted have pending bytes */ - ret = fstat(file->fd, &st); + ret = flb_file_fstat(file->fd, &st); if (ret != 0) { flb_errno(); return -1; } - if (file->offset < st.st_size) { - file->pending_bytes = (st.st_size - file->offset); + if (file->offset < st.size) { + file->pending_bytes = (st.size - file->offset); tail_signal_pending(file->config); } else { @@ -1577,103 +1569,6 @@ int flb_tail_file_to_event(struct flb_tail_file *file) return 0; } -/* - * Given an open file descriptor, return the filename. This function is a - * bit slow and it aims to be used only when a file is rotated. - */ -char *flb_tail_file_name(struct flb_tail_file *file) -{ - int ret; - char *buf; -#ifdef __linux__ - ssize_t s; - char tmp[128]; -#elif defined(__APPLE__) - char path[PATH_MAX]; -#elif defined(FLB_SYSTEM_WINDOWS) - HANDLE h; -#elif defined(FLB_SYSTEM_FREEBSD) - struct kinfo_file *file_entries; - int file_count; - int file_index; -#endif - - buf = flb_malloc(PATH_MAX); - if (!buf) { - flb_errno(); - return NULL; - } - -#ifdef __linux__ - ret = snprintf(tmp, sizeof(tmp) - 1, "/proc/%i/fd/%i", getpid(), file->fd); - if (ret == -1) { - flb_errno(); - flb_free(buf); - return NULL; - } - - s = readlink(tmp, buf, PATH_MAX); - if (s == -1) { - flb_free(buf); - flb_errno(); - return NULL; - } - buf[s] = '\0'; - -#elif __APPLE__ - int len; - - ret = fcntl(file->fd, F_GETPATH, path); - if (ret == -1) { - flb_errno(); - flb_free(buf); - return NULL; - } - - len = strlen(path); - memcpy(buf, path, len); - buf[len] = '\0'; - -#elif defined(FLB_SYSTEM_WINDOWS) - int len; - - h = (HANDLE) _get_osfhandle(file->fd); - if (h == INVALID_HANDLE_VALUE) { - flb_errno(); - flb_free(buf); - return NULL; - } - - /* This function returns the length of the string excluding "\0" - * and the resulting path has a "\\?\" prefix. - */ - len = GetFinalPathNameByHandleA(h, buf, PATH_MAX, FILE_NAME_NORMALIZED); - if (len == 0 || len >= PATH_MAX) { - flb_free(buf); - return NULL; - } - - if (strstr(buf, "\\\\?\\")) { - memmove(buf, buf + 4, len + 1); - } -#elif defined(FLB_SYSTEM_FREEBSD) - if ((file_entries = kinfo_getfile(getpid(), &file_count)) == NULL) { - flb_free(buf); - return NULL; - } - - for (file_index=0; file_index < file_count; file_index++) { - if (file_entries[file_index].kf_fd == file->fd) { - strncpy(buf, file_entries[file_index].kf_path, PATH_MAX - 1); - buf[PATH_MAX - 1] = 0; - break; - } - } - free(file_entries); -#endif - return buf; -} - int flb_tail_file_name_dup(char *path, struct flb_tail_file *file) { file->name = flb_strdup(path); @@ -1687,7 +1582,7 @@ int flb_tail_file_name_dup(char *path, struct flb_tail_file *file) flb_free(file->real_name); } - file->real_name = flb_tail_file_name(file); + file->real_name = flb_file_get_path(file->fd); if (!file->real_name) { flb_errno(); flb_free(file->name); @@ -1706,11 +1601,11 @@ int flb_tail_file_rotated(struct flb_tail_file *file) char *name; char *i_name; char *tmp; - struct stat st; + struct flb_file_stat st; struct flb_tail_config *ctx = file->config; /* Get the new file name */ - name = flb_tail_file_name(file); + name = flb_file_get_path(file->fd); if (!name) { return -1; } @@ -1749,8 +1644,8 @@ int flb_tail_file_rotated(struct flb_tail_file *file) #endif /* Check if a new file has been created */ - ret = stat(tmp, &st); - if (ret == 0 && st.st_ino != file->inode) { + ret = flb_file_stat(tmp, &st); + if (ret == 0 && st.inode != file->inode) { if (flb_tail_file_exists(&st, ctx) == FLB_FALSE) { ret = flb_tail_file_append(tmp, &st, FLB_TAIL_STATIC, ctx); if (ret == -1) { @@ -1773,16 +1668,16 @@ static int check_purge_deleted_file(struct flb_tail_config *ctx, { int ret; int64_t mtime; - struct stat st; + struct flb_file_stat st; - ret = fstat(file->fd, &st); + ret = flb_file_fstat(file->fd, &st); if (ret == -1) { flb_plg_debug(ctx->ins, "error stat(2) %s, removing", file->name); flb_tail_file_remove(file); return FLB_TRUE; } - if (st.st_nlink == 0) { + if (st.hard_link_count == 0) { flb_plg_debug(ctx->ins, "purge: monitored file has been deleted: %s", file->name); #ifdef FLB_HAVE_SQLDB @@ -1797,7 +1692,8 @@ static int check_purge_deleted_file(struct flb_tail_config *ctx, } if (ctx->ignore_older > 0) { - mtime = flb_tail_stat_mtime(&st); + mtime = st.modification_time; + if (mtime > 0) { if ((ts - ctx->ignore_older) > mtime) { flb_plg_debug(ctx->ins, "purge: monitored file (ignore older): %s", @@ -1822,21 +1718,26 @@ int flb_tail_file_purge(struct flb_input_instance *ins, struct flb_tail_file *file; struct flb_tail_config *ctx = context; time_t now; - struct stat st; + struct flb_file_stat st; /* Rotated files */ now = time(NULL); mk_list_foreach_safe(head, tmp, &ctx->files_rotated) { file = mk_list_entry(head, struct flb_tail_file, _rotate_head); if ((file->rotated + ctx->rotate_wait) <= now) { - ret = fstat(file->fd, &st); + ret = flb_file_fstat(file->fd, &st); if (ret == 0) { flb_plg_debug(ctx->ins, "inode=%"PRIu64" purge rotated file %s " \ "(offset=%"PRId64" / size = %"PRIu64")", - file->inode, file->name, file->offset, (uint64_t)st.st_size); + file->inode, + file->name, + file->offset, + (uint64_t) st.size); + if (file->pending_bytes > 0 && flb_input_buf_paused(ins)) { - flb_plg_warn(ctx->ins, "purged rotated file while data " + flb_plg_warn(ctx->ins, + "purged rotated file while data " "ingestion is paused, consider increasing " "rotate_wait"); } diff --git a/plugins/in_tail/tail_file.h b/plugins/in_tail/tail_file.h index 796224c37c9..7d5caa0b76b 100644 --- a/plugins/in_tail/tail_file.h +++ b/plugins/in_tail/tail_file.h @@ -25,92 +25,41 @@ #include #include +#include #include "tail.h" #include "tail_fs.h" #include "tail_config.h" #include "tail_file_internal.h" -#ifdef FLB_SYSTEM_WINDOWS -#include "win32.h" -#endif - #ifdef FLB_HAVE_REGEX #define FLB_HASH_TABLE_SIZE 50 #endif -/* return the file modification time in seconds since epoch */ -static inline int64_t flb_tail_stat_mtime(struct stat *st) -{ -#if defined(FLB_HAVE_WINDOWS) - return (int64_t) st->st_mtime; -#elif defined(__APPLE__) && !defined(_POSIX_C_SOURCE) - return (int64_t) st->st_mtimespec.tv_sec; -#elif (_POSIX_C_SOURCE >= 200809L || \ - defined(_BSD_SOURCE) || defined(_SVID_SOURCE) || \ - defined(__BIONIC__) || (defined (__SVR4) && defined (__sun)) || \ - defined(__FreeBSD__) || defined (__linux__)) - return (int64_t) st->st_mtim.tv_sec; -#elif defined(_AIX) - return (int64_t) st->st_mtime; -#else - return (int64_t) st->st_mtime; -#endif - - /* backend unsupported: submit a PR :) */ - return -1; -} - static inline int flb_tail_target_file_name_cmp(char *name, struct flb_tail_file *file) { - int ret; - char *name_a = NULL; - char *name_b = NULL; - char *base_a = NULL; - char *base_b = NULL; - - name_a = flb_strdup(name); - if (!name_a) { - flb_errno(); - ret = -1; - goto out; - } + char *base_a; + char *base_b; + int ret; - base_a = flb_strdup(basename(name_a)); - if (!base_a) { - flb_errno(); - ret = -1; - goto out; - } + base_a = NULL; + base_b = NULL; + ret = -1; -#if defined(FLB_SYSTEM_WINDOWS) - name_b = flb_strdup(file->real_name); - if (!name_b) { - flb_errno(); - ret = -1; - goto out; - } + base_a = flb_file_basename(name); - base_b = basename(name_b); - ret = _stricmp(base_a, base_b); -#else - name_b = flb_strdup(file->real_name); - if (!name_b) { - flb_errno(); - ret = -1; - goto out; - } - base_b = basename(name_b); - ret = strcmp(base_a, base_b); -#endif + if (base_a != NULL) { + base_b = flb_file_basename(file->real_name); + + if (base_b != NULL) { + ret = strcasecmp(base_a, base_b); - out: - flb_free(name_a); - flb_free(name_b); - flb_free(base_a); + flb_free(base_b); + } - /* FYI: 'base_b' never points to a new allocation, no flb_free is needed */ + flb_free(base_a); + } return ret; } @@ -118,11 +67,10 @@ static inline int flb_tail_target_file_name_cmp(char *name, int flb_tail_file_name_dup(char *path, struct flb_tail_file *file); int flb_tail_file_to_event(struct flb_tail_file *file); int flb_tail_file_chunk(struct flb_tail_file *file); -int flb_tail_file_append(char *path, struct stat *st, int mode, +int flb_tail_file_append(char *path, struct flb_file_stat *st, int mode, struct flb_tail_config *ctx); void flb_tail_file_remove(struct flb_tail_file *file); int flb_tail_file_remove_all(struct flb_tail_config *ctx); -char *flb_tail_file_name(struct flb_tail_file *file); int flb_tail_file_is_rotated(struct flb_tail_config *ctx, struct flb_tail_file *file); int flb_tail_file_rotated(struct flb_tail_file *file); diff --git a/plugins/in_tail/tail_file_internal.h b/plugins/in_tail/tail_file_internal.h index 6d95c87c195..d7226702b94 100644 --- a/plugins/in_tail/tail_file_internal.h +++ b/plugins/in_tail/tail_file_internal.h @@ -21,6 +21,7 @@ #define FLB_TAIL_INTERNAL_H #include +#include #include #include #include @@ -37,7 +38,7 @@ struct flb_tail_file { /* Inotify */ int watch_fd; /* file lookup info */ - int fd; + flb_file_handle fd; int64_t size; int64_t offset; int64_t last_line; diff --git a/plugins/in_tail/tail_fs_inotify.c b/plugins/in_tail/tail_fs_inotify.c index 42213a0a14c..b2b36744536 100644 --- a/plugins/in_tail/tail_fs_inotify.c +++ b/plugins/in_tail/tail_fs_inotify.c @@ -132,7 +132,7 @@ static int tail_fs_add(struct flb_tail_file *file, int check_rotated) * 6. conflict: inotify_add_watch() receives the path 'a.log', */ - name = flb_tail_file_name(file); + name = flb_file_get_path(file->fd); if (!name) { flb_plg_error(ctx->ins, "inode=%"PRIu64" cannot get real filename for inotify", file->inode); diff --git a/plugins/in_tail/tail_fs_stat.c b/plugins/in_tail/tail_fs_stat.c index 6b312c9bd43..3738e16547b 100644 --- a/plugins/in_tail/tail_fs_stat.c +++ b/plugins/in_tail/tail_fs_stat.c @@ -20,6 +20,7 @@ #define _DEFAULT_SOURCE #include +#include #include #include @@ -30,16 +31,12 @@ #include "tail_config.h" #include "tail_signal.h" -#ifdef FLB_SYSTEM_WINDOWS -#include "win32.h" -#endif - struct fs_stat { /* last time check */ time_t checked; /* previous status */ - struct stat st; + struct flb_file_stat st; }; static int tail_fs_event(struct flb_input_instance *ins, @@ -51,7 +48,7 @@ static int tail_fs_event(struct flb_input_instance *ins, struct flb_tail_config *ctx = in_context; struct flb_tail_file *file = NULL; struct fs_stat *fst; - struct stat st; + struct flb_file_stat st; time_t t; t = time(NULL); @@ -62,17 +59,17 @@ static int tail_fs_event(struct flb_input_instance *ins, fst = file->fs_backend; /* Check current status of the file */ - ret = fstat(file->fd, &st); + ret = flb_file_fstat(file->fd, &st); if (ret == -1) { flb_errno(); continue; } /* Check if the file was modified */ - if ((fst->st.st_mtime != st.st_mtime) || - (fst->st.st_size != st.st_size)) { + if ((fst->st.modification_time != st.modification_time) || + (fst->st.size != st.size)) { /* Update stat info and trigger the notification */ - memcpy(&fst->st, &st, sizeof(struct stat)); + memcpy(&fst->st, &st, sizeof(struct flb_file_stat)); fst->checked = t; in_tail_collect_event(file, config); } @@ -92,14 +89,14 @@ static int tail_fs_check(struct flb_input_instance *ins, struct flb_tail_config *ctx = in_context; struct flb_tail_file *file = NULL; struct fs_stat *fst; - struct stat st; + struct flb_file_stat st; /* Lookup watched file */ mk_list_foreach_safe(head, tmp, &ctx->files_event) { file = mk_list_entry(head, struct flb_tail_file, _head); fst = file->fs_backend; - ret = fstat(file->fd, &st); + ret = flb_file_fstat(file->fd, &st); if (ret == -1) { flb_plg_debug(ctx->ins, "error stat(2) %s, removing", file->name); flb_tail_file_remove(file); @@ -107,7 +104,7 @@ static int tail_fs_check(struct flb_input_instance *ins, } /* Check if the file have been deleted */ - if (st.st_nlink == 0) { + if (st.hard_link_count == 0) { flb_plg_debug(ctx->ins, "file has been deleted: %s", file->name); #ifdef FLB_HAVE_SQLDB if (ctx->db) { @@ -120,8 +117,8 @@ static int tail_fs_check(struct flb_input_instance *ins, } /* Check if the file was truncated */ - if (file->offset > st.st_size) { - offset = lseek(file->fd, 0, SEEK_SET); + if (file->offset > st.size) { + offset = flb_file_lseek(file->fd, 0, SEEK_SET); if (offset == -1) { flb_errno(); return -1; @@ -130,7 +127,7 @@ static int tail_fs_check(struct flb_input_instance *ins, flb_plg_debug(ctx->ins, "file truncated %s", file->name); file->offset = offset; file->buf_len = 0; - memcpy(&fst->st, &st, sizeof(struct stat)); + memcpy(&fst->st, &st, sizeof(struct flb_file_stat)); #ifdef FLB_HAVE_SQLDB /* Update offset in database file */ @@ -140,8 +137,8 @@ static int tail_fs_check(struct flb_input_instance *ins, #endif } - if (file->offset < st.st_size) { - file->pending_bytes = (st.st_size - file->offset); + if (file->offset < st.size) { + file->pending_bytes = (st.size - file->offset); tail_signal_pending(ctx); } else { @@ -150,7 +147,7 @@ static int tail_fs_check(struct flb_input_instance *ins, /* Discover the current file name for the open file descriptor */ - name = flb_tail_file_name(file); + name = flb_file_get_path(file->fd); if (!name) { flb_plg_debug(ctx->ins, "could not resolve %s, removing", file->name); flb_tail_file_remove(file); @@ -227,7 +224,7 @@ int flb_tail_fs_stat_add(struct flb_tail_file *file) } fst->checked = time(NULL); - ret = stat(file->name, &fst->st); + ret = flb_file_stat(file->name, &fst->st); if (ret == -1) { flb_errno(); flb_free(fst); diff --git a/plugins/in_tail/tail_scan_glob.c b/plugins/in_tail/tail_scan_glob.c index b330b7c3b23..ed7f19335e2 100644 --- a/plugins/in_tail/tail_scan_glob.c +++ b/plugins/in_tail/tail_scan_glob.c @@ -25,6 +25,7 @@ #include #include #include +#include #include "tail.h" #include "tail_file.h" @@ -32,88 +33,6 @@ #include "tail_scan.h" #include "tail_config.h" -/* Define missing GLOB_TILDE if not exists */ -#ifndef GLOB_TILDE -#define GLOB_TILDE 1<<2 /* use GNU Libc value */ -#define UNSUP_TILDE 1 - -/* we need these extra headers for path resolution */ -#include -#include -#include - -static char *expand_tilde(const char *path) -{ - int len; - char user[256]; - char *p = NULL; - char *dir = NULL; - char *tmp = NULL; - struct passwd *uinfo = NULL; - - if (path[0] == '~') { - p = strchr(path, '/'); - - if (p) { - /* check case '~/' */ - if ((p - path) == 1) { - dir = getenv("HOME"); - if (!dir) { - return path; - } - } - else { - /* - * it refers to a different user: ~user/abc, first step grab - * the user name. - */ - len = (p - path) - 1; - memcpy(user, path + 1, len); - user[len] = '\0'; - - /* use getpwnam() to resolve user information */ - uinfo = getpwnam(user); - if (!uinfo) { - return path; - } - - dir = uinfo->pw_dir; - } - } - else { - dir = getenv("HOME"); - if (!dir) { - return path; - } - } - - if (p) { - tmp = flb_malloc(PATH_MAX); - if (!tmp) { - flb_errno(); - return NULL; - } - snprintf(tmp, PATH_MAX - 1, "%s%s", dir, p); - } - else { - dir = getenv("HOME"); - if (!dir) { - return path; - } - - tmp = flb_strdup(dir); - if (!tmp) { - return path; - } - } - - return tmp; - } - - return path; -} -#endif - static int tail_is_excluded(char *path, struct flb_tail_config *ctx) { struct mk_list *head; @@ -133,146 +52,105 @@ static int tail_is_excluded(char *path, struct flb_tail_config *ctx) return FLB_FALSE; } -static inline int do_glob(const char *pattern, int flags, - void *not_used, glob_t *pglob) -{ - int ret; - int new_flags; - char *tmp = NULL; - int tmp_needs_free = FLB_FALSE; - (void) not_used; - - /* Save current values */ - new_flags = flags; - - if (flags & GLOB_TILDE) { -#ifdef UNSUP_TILDE - /* - * Some libc libraries like Musl do not support GLOB_TILDE for tilde - * expansion. A workaround is to use wordexp(3) but looking at it - * implementation in Musl it looks quite expensive: - * - * http://git.musl-libc.org/cgit/musl/tree/src/misc/wordexp.c - * - * the workaround is to do our own tilde expansion in a temporary buffer. - */ - - /* Look for a tilde */ - tmp = expand_tilde(pattern); - if (tmp != pattern) { - /* the path was expanded */ - pattern = tmp; - tmp_needs_free = FLB_TRUE; - } - - /* remove unused flag */ - new_flags &= ~GLOB_TILDE; -#endif - } - - /* invoke glob with new parameters */ - ret = glob(pattern, new_flags, NULL, pglob); - - /* remove temporary buffer, if allocated by expand_tilde above. - * Note that this buffer is only used for libc implementations - * that do not support the GLOB_TILDE flag, like musl. */ - if ((tmp != NULL) && (tmp_needs_free == FLB_TRUE)) { - flb_free(tmp); - } - - return ret; -} - /* Scan a path, register the entries and return how many */ static int tail_scan_path(const char *path, struct flb_tail_config *ctx) { - int i; int ret; - int count = 0; - glob_t globbuf; + int count; time_t now; int64_t mtime; - struct stat st; + struct flb_file_stat st; + struct flb_file_glob_context glob_context; + uint64_t glob_flags; + char *file_path; flb_plg_debug(ctx->ins, "scanning path %s", path); - /* Safe reset for globfree() */ - globbuf.gl_pathv = NULL; + glob_flags = FLB_FILE_GLOB_ABORT_ON_ERROR | FLB_FILE_GLOB_EXPAND_TILDE; - /* Scan the given path */ - ret = do_glob(path, GLOB_TILDE | GLOB_ERR, NULL, &globbuf); - if (ret != 0) { - switch (ret) { - case GLOB_NOSPACE: + ret = flb_file_glob_start(&glob_context, path, glob_flags ); + + if (ret != FLB_FILE_GLOB_ERROR_SUCCESS) { + if (ret == FLB_FILE_GLOB_ERROR_NO_MEMORY) { flb_plg_error(ctx->ins, "no memory space available"); - return -1; - case GLOB_ABORTED: + } + else if (ret == FLB_FILE_GLOB_ERROR_ABORTED) { flb_plg_error(ctx->ins, "read error, check permissions: %s", path); - return -1; - case GLOB_NOMATCH: - ret = stat(path, &st); - if (ret == -1) { - flb_plg_debug(ctx->ins, "cannot read info from: %s", path); - } - else { - ret = access(path, R_OK); - if (ret == -1 && errno == EACCES) { - flb_plg_error(ctx->ins, "NO read access for path: %s", path); - } - else { - flb_plg_debug(ctx->ins, "NO matches for path: %s", path); - } - } - return 0; } - } + else if (ret == FLB_FILE_GLOB_ERROR_NO_FILE) { + flb_plg_debug(ctx->ins, "cannot read info from: %s", path); + } + else if (ret == FLB_FILE_GLOB_ERROR_NO_ACCESS) { + flb_plg_error(ctx->ins, "no read access for path: %s", path); + } + else if (ret == FLB_FILE_GLOB_ERROR_NO_MATCHES) { + flb_plg_debug(ctx->ins, "no matches for path: %s", path); + } + else if (ret == FLB_FILE_GLOB_ERROR_OVERSIZED_PATH) { + flb_plg_debug(ctx->ins, "oversized path or entry: %s", path); + } + flb_file_glob_clean(&glob_context); + + return -1; + } - /* For every entry found, generate an output list */ now = time(NULL); - for (i = 0; i < globbuf.gl_pathc; i++) { - ret = stat(globbuf.gl_pathv[i], &st); - if (ret == 0 && S_ISREG(st.st_mode)) { + count = 0; + + while (flb_file_glob_fetch(&glob_context, &file_path) == + FLB_FILE_GLOB_ERROR_SUCCESS) { + ret = flb_file_stat(file_path, &st); + + if (ret == 0 && FLB_FILE_ISREG(st.mode)) { /* Check if this file is blacklisted */ - if (tail_is_excluded(globbuf.gl_pathv[i], ctx) == FLB_TRUE) { - flb_plg_debug(ctx->ins, "excluded=%s", globbuf.gl_pathv[i]); + if (tail_is_excluded(file_path, ctx) == FLB_TRUE) { + flb_plg_debug(ctx->ins, "excluded=%s", file_path); continue; } if (ctx->ignore_older > 0) { - mtime = flb_tail_stat_mtime(&st); + mtime = st.modification_time; if (mtime > 0) { if ((now - ctx->ignore_older) > mtime) { flb_plg_debug(ctx->ins, "excluded=%s (ignore_older)", - globbuf.gl_pathv[i]); + file_path); continue; } } } /* Append file to list */ - ret = flb_tail_file_append(globbuf.gl_pathv[i], &st, + ret = flb_tail_file_append(file_path, &st, FLB_TAIL_STATIC, ctx); if (ret == 0) { - flb_plg_debug(ctx->ins, "scan_glob add(): %s, inode %li", - globbuf.gl_pathv[i], st.st_ino); + flb_plg_debug(ctx->ins, + "scan_glob add(): %s, inode %"PRIu64, + file_path, + (uint64_t) st.inode); + count++; } else { - flb_plg_debug(ctx->ins, "scan_blog add(): dismissed: %s, inode %li", - globbuf.gl_pathv[i], st.st_ino); + flb_plg_debug(ctx->ins, + "scan_blog add(): dismissed: %s, inode %"PRIu64, + file_path, + (uint64_t) st.inode); } } else { flb_plg_debug(ctx->ins, "skip (invalid) entry=%s", - globbuf.gl_pathv[i]); + file_path); } } - if (count > 0) { - tail_signal_manager(ctx); - } +/* + I removed the call to tail_signal_manager because flb_tail_file_append + does emit a signal when the file is appended with FLB_TAIL_STATIC as its + mode. +*/ + + flb_file_glob_clean(&glob_context); - globfree(&globbuf); return count; } diff --git a/plugins/in_tail/tail_scan_win32.c b/plugins/in_tail/tail_scan_win32.c index 94733f06536..1fa95fe9be6 100644 --- a/plugins/in_tail/tail_scan_win32.c +++ b/plugins/in_tail/tail_scan_win32.c @@ -26,6 +26,7 @@ #include #include #include +#include #include @@ -34,8 +35,6 @@ #include "tail_signal.h" #include "tail_config.h" -#include "win32.h" - static int tail_is_excluded(char *path, struct flb_tail_config *ctx) { struct mk_list *head; @@ -55,45 +54,6 @@ static int tail_is_excluded(char *path, struct flb_tail_config *ctx) return FLB_FALSE; } -/* - * This function is a thin wrapper over flb_tail_file_append(), - * adding normalization and sanity checks on top of it. - */ -static int tail_register_file(const char *target, struct flb_tail_config *ctx, - time_t ts) -{ - int64_t mtime; - struct stat st; - char path[MAX_PATH]; - - if (_fullpath(path, target, MAX_PATH) == NULL) { - flb_plg_error(ctx->ins, "cannot get absolute path of %s", target); - return -1; - } - - if (stat(path, &st) != 0 || !S_ISREG(st.st_mode)) { - return -1; - } - - if (ctx->ignore_older > 0) { - mtime = flb_tail_stat_mtime(&st); - if (mtime > 0) { - if ((ts - ctx->ignore_older) > mtime) { - flb_plg_debug(ctx->ins, "excluded=%s (ignore_older)", - target); - return -1; - } - } - } - - if (tail_is_excluded(path, ctx) == FLB_TRUE) { - flb_plg_trace(ctx->ins, "skip '%s' (excluded)", path); - return -1; - } - - return flb_tail_file_append(path, &st, FLB_TAIL_STATIC, ctx); -} - /* * Perform patern match on the given path string. This function * supports patterns with "nested" wildcards like below. @@ -105,141 +65,148 @@ static int tail_register_file(const char *target, struct flb_tail_config *ctx, */ static int tail_scan_pattern(const char *path, struct flb_tail_config *ctx) { - char *star, *p0, *p1; - char pattern[MAX_PATH]; - char buf[MAX_PATH]; - int ret; - int n_added = 0; - time_t now; - int64_t mtime; - HANDLE h; - WIN32_FIND_DATA data; - - if (strlen(path) > MAX_PATH - 1) { - flb_plg_error(ctx->ins, "path too long '%s'"); - return -1; - } + struct flb_file_glob_context glob_context; + char *filename; + int count; + time_t now; + int ret; + + ret = flb_file_glob_start(&glob_context, + path, + FLB_FILE_GLOB_ABORT_ON_ERROR); + + if (ret != FLB_FILE_GLOB_ERROR_SUCCESS) { + if (ret == FLB_FILE_GLOB_ERROR_NO_MEMORY) { + flb_plg_error(ctx->ins, "no memory space available"); + } + else if (ret == FLB_FILE_GLOB_ERROR_ABORTED) { + flb_plg_error(ctx->ins, "read error, check permissions: %s", path); + } + else if (ret == FLB_FILE_GLOB_ERROR_NO_FILE) { + flb_plg_debug(ctx->ins, "cannot read info from: %s", path); + } + else if (ret == FLB_FILE_GLOB_ERROR_NO_ACCESS) { + flb_plg_error(ctx->ins, "no read access for path: %s", path); + } + else if (ret == FLB_FILE_GLOB_ERROR_NO_MATCHES) { + flb_plg_debug(ctx->ins, "no matches for path: %s", path); + } - star = strchr(path, '*'); - if (star == NULL) { - return -1; - } + flb_file_glob_clean(&glob_context); - /* - * C:\data\tmp\input_*.conf - * 0<-----| - */ - p0 = star; - while (path <= p0 && *p0 != '\\') { - p0--; + return -1; } - /* - * C:\data\tmp\input_*.conf - * |---->1 - */ - p1 = star; - while (*p1 && *p1 != '\\') { - p1++; - } + now = time(NULL); + count = 0; - memcpy(pattern, path, (p1 - path)); - pattern[p1 - path] = '\0'; + while(flb_file_glob_fetch(&glob_context, + &filename) == FLB_FILE_GLOB_ERROR_SUCCESS) { - h = FindFirstFileA(pattern, &data); - if (h == INVALID_HANDLE_VALUE) { - return 0; /* none matched */ - } + /* Try to register the target file */ + ret = tail_register_file(filename, ctx, now); - now = time(NULL); - do { - /* Ignore the current and parent dirs */ - if (!strcmp(".", data.cFileName) || !strcmp("..", data.cFileName)) { - continue; + if (ret == 0) { + count++; } + } - /* Avoid an infinite loop */ - if (strchr(data.cFileName, '*')) { - continue; - } + flb_file_glob_clean(&glob_context); - /* Create a path (prefix + filename + suffix) */ - memcpy(buf, path, p0 - path + 1); - buf[p0 - path + 1] = '\0'; + return count; +} - if (strlen(buf) + strlen(data.cFileName) + strlen(p1) > MAX_PATH - 1) { - flb_plg_warn(ctx->ins, "'%s%s%s' is too long", buf, data.cFileName, p1); - continue; +static int tail_scan_path(const char *path, struct flb_tail_config *ctx) +{ + struct flb_file_glob_context glob_context; + char *file_path; + int64_t mtime; + int count; + time_t now; + int ret; + struct flb_file_stat st; + + ret = flb_file_glob_start(&glob_context, + path, + FLB_FILE_GLOB_ABORT_ON_ERROR); + + if (ret != FLB_FILE_GLOB_ERROR_SUCCESS) { + if (ret == FLB_FILE_GLOB_ERROR_NO_MEMORY) { + flb_plg_error(ctx->ins, "no memory space available"); } - strcat(buf, data.cFileName); - strcat(buf, p1); - - if (strchr(p1, '*')) { - ret = tail_scan_pattern(buf, ctx); /* recursive */ - if (ret >= 0) { - n_added += ret; - } - continue; + else if (ret == FLB_FILE_GLOB_ERROR_ABORTED) { + flb_plg_error(ctx->ins, "read error, check permissions: %s", path); } - - /* Try to register the target file */ - ret = tail_register_file(buf, ctx, now); - if (ret == 0) { - n_added++; + else if (ret == FLB_FILE_GLOB_ERROR_NO_FILE) { + flb_plg_debug(ctx->ins, "cannot read info from: %s", path); + } + else if (ret == FLB_FILE_GLOB_ERROR_NO_ACCESS) { + flb_plg_error(ctx->ins, "no read access for path: %s", path); + } + else if (ret == FLB_FILE_GLOB_ERROR_NO_MATCHES) { + flb_plg_debug(ctx->ins, "no matches for path: %s", path); + } + else if (ret == FLB_FILE_GLOB_ERROR_OVERSIZED_PATH) { + flb_plg_debug(ctx->ins, "oversized path or entry: %s", path); } - } while (FindNextFileA(h, &data) != 0); - FindClose(h); - return n_added; -} + flb_file_glob_clean(&glob_context); -static int tail_filepath(char *buf, int len, const char *basedir, const char *filename) -{ - char drive[_MAX_DRIVE]; - char dir[_MAX_DIR]; - char fname[_MAX_FNAME]; - char ext[_MAX_EXT]; - char tmp[MAX_PATH]; - int ret; - - ret = _splitpath_s(basedir, drive, _MAX_DRIVE, dir, _MAX_DIR, NULL, 0, NULL, 0); - if (ret) { return -1; } - ret = _splitpath_s(filename, NULL, 0, NULL, 0, fname, _MAX_FNAME, ext, _MAX_EXT); - if (ret) { - return -1; - } + now = time(NULL); + count = 0; - ret = _makepath_s(tmp, MAX_PATH, drive, dir, fname, ext); - if (ret) { - return -1; - } - if (_fullpath(buf, tmp, len) == NULL) { - return -1; - } + while(flb_file_glob_fetch(&glob_context, &file_path) == + FLB_FILE_GLOB_ERROR_SUCCESS) { - return 0; -} + ret = flb_file_stat(file_path, &st); -static int tail_scan_path(const char *path, struct flb_tail_config *ctx) -{ - int ret; - int n_added = 0; - time_t now; + if (ret == 0 && FLB_FILE_ISREG(st.mode)) { + /* Check if this file is blacklisted */ + if (tail_is_excluded(file_path, ctx) == FLB_TRUE) { + flb_plg_debug(ctx->ins, "excluded=%s", file_path); + continue; + } - if (strchr(path, '*')) { - return tail_scan_pattern(path, ctx); - } + if (ctx->ignore_older > 0) { + mtime = st.modification_time; + if (mtime > 0) { + if ((now - ctx->ignore_older) > mtime) { + flb_plg_debug(ctx->ins, "excluded=%s (ignore_older)", + file_path); + continue; + } + } + } - /* No wildcard involved. Let's just handle the file... */ - now = time(NULL); - ret = tail_register_file(path, ctx, now); - if (ret == 0) { - n_added++; + /* Append file to list */ + ret = flb_tail_file_append(file_path, &st, + FLB_TAIL_STATIC, ctx); + if (ret == 0) { + flb_plg_debug(ctx->ins, + "scan_glob add(): %s, inode %"PRIu64, + file_path, + (uint64_t) st.inode); + + count++; + } + else { + flb_plg_debug(ctx->ins, + "scan_blog add(): dismissed: %s, inode %"PRIu64, + file_path, + (uint64_t) st.inode); + } + } + else { + flb_plg_debug(ctx->ins, "skip (invalid) entry=%s", + file_path); + } } - return n_added; + flb_file_glob_clean(&glob_context); + + return count; } From 25e2df54661f5c4b63705a0fabdf30c471fc89c3 Mon Sep 17 00:00:00 2001 From: Leonardo Alminana Date: Wed, 14 Jun 2023 19:54:48 +0200 Subject: [PATCH 009/315] in_node_exporter_metrics: updated renamed function reference Signed-off-by: Leonardo Alminana --- plugins/in_node_exporter_metrics/ne_textfile_linux.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/in_node_exporter_metrics/ne_textfile_linux.c b/plugins/in_node_exporter_metrics/ne_textfile_linux.c index 589322af528..8d66bc58fec 100644 --- a/plugins/in_node_exporter_metrics/ne_textfile_linux.c +++ b/plugins/in_node_exporter_metrics/ne_textfile_linux.c @@ -143,7 +143,7 @@ static int textfile_update(struct flb_ne *ctx) mk_list_foreach(head, &list) { entry = mk_list_entry(head, struct flb_slist_entry, _head); /* Update metrics from text file */ - contents = flb_file_read(entry->str); + contents = flb_file_read_contents(entry->str); if (flb_sds_len(contents) == 0) { flb_plg_debug(ctx->ins, "skip empty payload of prometheus: %s", entry->str); From 8e7c08e7a10804d67a511a832e54d699576d4bc3 Mon Sep 17 00:00:00 2001 From: Kushal Azim Ekram Date: Wed, 14 Jun 2023 11:09:57 -0700 Subject: [PATCH 010/315] out_azure_logs_ingestion: Implementing Azure Logs Ingestion (with DCR, DCE) output plugin (#7155) Signed-off-by: Kushal Azim Ekram --- CMakeLists.txt | 1 + plugins/CMakeLists.txt | 1 + .../out_azure_logs_ingestion/CMakeLists.txt | 6 + .../azure_logs_ingestion.c | 445 ++++++++++++++++++ .../azure_logs_ingestion.h | 74 +++ .../azure_logs_ingestion_conf.c | 172 +++++++ .../azure_logs_ingestion_conf.h | 29 ++ 7 files changed, 728 insertions(+) create mode 100644 plugins/out_azure_logs_ingestion/CMakeLists.txt create mode 100644 plugins/out_azure_logs_ingestion/azure_logs_ingestion.c create mode 100644 plugins/out_azure_logs_ingestion/azure_logs_ingestion.h create mode 100644 plugins/out_azure_logs_ingestion/azure_logs_ingestion_conf.c create mode 100644 plugins/out_azure_logs_ingestion/azure_logs_ingestion_conf.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 1e8711200c2..f36ad1aead0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -212,6 +212,7 @@ option(FLB_IN_ELASTICSEARCH "Enable Elasticsearch (Bulk API) input pl option(FLB_IN_CALYPTIA_FLEET "Enable Calyptia Fleet input plugin" Yes) option(FLB_OUT_AZURE "Enable Azure output plugin" Yes) option(FLB_OUT_AZURE_BLOB "Enable Azure output plugin" Yes) +option(FLB_OUT_AZURE_LOGS_INGESTION "Enable Azure Logs Ingestion output plugin" Yes) option(FLB_OUT_AZURE_KUSTO "Enable Azure Kusto output plugin" Yes) option(FLB_OUT_BIGQUERY "Enable BigQuery output plugin" Yes) option(FLB_OUT_CALYPTIA "Enable Calyptia monitoring plugin" Yes) diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index ce5b697e7d6..3c1b66b7d1c 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -283,6 +283,7 @@ REGISTER_PROCESSOR_PLUGIN("processor_attributes") # ======= REGISTER_OUT_PLUGIN("out_azure") REGISTER_OUT_PLUGIN("out_azure_blob") +REGISTER_OUT_PLUGIN("out_azure_logs_ingestion") REGISTER_OUT_PLUGIN("out_azure_kusto") REGISTER_OUT_PLUGIN("out_bigquery") REGISTER_OUT_PLUGIN("out_calyptia") diff --git a/plugins/out_azure_logs_ingestion/CMakeLists.txt b/plugins/out_azure_logs_ingestion/CMakeLists.txt new file mode 100644 index 00000000000..b51308c70d0 --- /dev/null +++ b/plugins/out_azure_logs_ingestion/CMakeLists.txt @@ -0,0 +1,6 @@ +set(src + azure_logs_ingestion.c + azure_logs_ingestion_conf.c + ) + +FLB_PLUGIN(out_azure_logs_ingestion "${src}" "") diff --git a/plugins/out_azure_logs_ingestion/azure_logs_ingestion.c b/plugins/out_azure_logs_ingestion/azure_logs_ingestion.c new file mode 100644 index 00000000000..d2731cfe134 --- /dev/null +++ b/plugins/out_azure_logs_ingestion/azure_logs_ingestion.c @@ -0,0 +1,445 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Fluent Bit + * ========== + * Copyright (C) 2015-2022 The Fluent Bit Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "azure_logs_ingestion.h" +#include "azure_logs_ingestion_conf.h" + +static int cb_azure_logs_ingestion_init(struct flb_output_instance *ins, + struct flb_config *config, void *data) +{ + struct flb_az_li *ctx; + (void) config; + (void) ins; + (void) data; + + /* Allocate and initialize a context from configuration */ + ctx = flb_az_li_ctx_create(ins, config); + if (!ctx) { + flb_plg_error(ctx->ins, "configuration failed"); + return -1; + } + + return 0; +} + +/* A duplicate function copied from the azure log analytics plugin. + allocates sds string */ +static int az_li_format(const void *in_buf, size_t in_bytes, + char **out_buf, size_t *out_size, + struct flb_az_li *ctx) +{ + int i; + int array_size = 0; + int map_size; + size_t off = 0; + double t; + struct flb_time tm; + msgpack_unpacked result; + msgpack_object root; + msgpack_object *obj; + msgpack_object map; + msgpack_object k; + msgpack_object v; + msgpack_sbuffer mp_sbuf; + msgpack_packer mp_pck; + msgpack_sbuffer tmp_sbuf; + msgpack_packer tmp_pck; + flb_sds_t record; + char time_formatted[32]; + size_t s; + struct tm tms; + int len; + + /* Count number of items */ + array_size = flb_mp_count(in_buf, in_bytes); + msgpack_unpacked_init(&result); + + /* Create temporary msgpack buffer */ + msgpack_sbuffer_init(&mp_sbuf); + msgpack_packer_init(&mp_pck, &mp_sbuf, msgpack_sbuffer_write); + msgpack_pack_array(&mp_pck, array_size); + + off = 0; + while (msgpack_unpack_next(&result, in_buf, in_bytes, &off) == MSGPACK_UNPACK_SUCCESS) { + root = result.data; + + /* Get timestamp */ + flb_time_pop_from_msgpack(&tm, &result, &obj); + + /* Create temporary msgpack buffer */ + msgpack_sbuffer_init(&tmp_sbuf); + msgpack_packer_init(&tmp_pck, &tmp_sbuf, msgpack_sbuffer_write); + + map = root.via.array.ptr[1]; + map_size = map.via.map.size; + + msgpack_pack_map(&mp_pck, map_size + 1); + + /* Append the time key */ + msgpack_pack_str(&mp_pck, flb_sds_len(ctx->time_key)); + msgpack_pack_str_body(&mp_pck, + ctx->time_key, + flb_sds_len(ctx->time_key)); + + if (ctx->time_generated == FLB_TRUE) { + /* Append the time value as ISO 8601 */ + gmtime_r(&tm.tm.tv_sec, &tms); + s = strftime(time_formatted, sizeof(time_formatted) - 1, + FLB_PACK_JSON_DATE_ISO8601_FMT, &tms); + + len = snprintf(time_formatted + s, + sizeof(time_formatted) - 1 - s, + ".%03" PRIu64 "Z", + (uint64_t) tm.tm.tv_nsec / 1000000); + s += len; + msgpack_pack_str(&mp_pck, s); + msgpack_pack_str_body(&mp_pck, time_formatted, s); + } + else { + /* Append the time value as millis.nanos */ + t = flb_time_to_double(&tm); + msgpack_pack_double(&mp_pck, t); + } + + /* Append original map k/v */ + for (i = 0; i < map_size; i++) { + k = map.via.map.ptr[i].key; + v = map.via.map.ptr[i].val; + + msgpack_pack_object(&tmp_pck, k); + msgpack_pack_object(&tmp_pck, v); + } + msgpack_sbuffer_write(&mp_sbuf, tmp_sbuf.data, tmp_sbuf.size); + msgpack_sbuffer_destroy(&tmp_sbuf); + } + + record = flb_msgpack_raw_to_json_sds(mp_sbuf.data, mp_sbuf.size); + if (!record) { + flb_errno(); + msgpack_sbuffer_destroy(&mp_sbuf); + msgpack_unpacked_destroy(&result); + return -1; + } + + msgpack_sbuffer_destroy(&mp_sbuf); + msgpack_unpacked_destroy(&result); + + *out_buf = record; + *out_size = flb_sds_len(record); + + return 0; +} + +/* Gets OAuth token; (allocates sds string everytime, must deallocate) */ +flb_sds_t get_az_li_token(struct flb_az_li *ctx) +{ + int ret = 0; + char* token; + size_t token_len; + flb_sds_t token_return = NULL; + + if (pthread_mutex_lock(&ctx->token_mutex)) { + flb_plg_error(ctx->ins, "error locking mutex"); + return NULL; + } + /* Retrieve access token only if expired */ + if (flb_oauth2_token_expired(ctx->u_auth) == FLB_TRUE) { + flb_plg_debug(ctx->ins, "token expired. getting new token"); + /* Clear any previous oauth2 payload content */ + flb_oauth2_payload_clear(ctx->u_auth); + + ret = flb_oauth2_payload_append(ctx->u_auth, "grant_type", 10, + "client_credentials", 18); + if (ret == -1) { + flb_plg_error(ctx->ins, "error appending oauth2 params"); + goto token_cleanup; + } + + ret = flb_oauth2_payload_append(ctx->u_auth, "scope", 5, FLB_AZ_LI_AUTH_SCOPE, + sizeof(FLB_AZ_LI_AUTH_SCOPE) - 1); + if (ret == -1) { + flb_plg_error(ctx->ins, "error appending oauth2 params"); + goto token_cleanup; + } + + ret = flb_oauth2_payload_append(ctx->u_auth, "client_id", 9, + ctx->client_id, -1); + if (ret == -1) { + flb_plg_error(ctx->ins, "error appending oauth2 params"); + goto token_cleanup; + } + + ret = flb_oauth2_payload_append(ctx->u_auth, "client_secret", 13, + ctx->client_secret, -1); + if (ret == -1) { + flb_plg_error(ctx->ins, "error appending oauth2 params"); + goto token_cleanup; + } + + token = flb_oauth2_token_get(ctx->u_auth); + + /* Copy string to prevent race conditions */ + if (!token) { + flb_plg_error(ctx->ins, "error retrieving oauth2 access token"); + goto token_cleanup; + } + flb_plg_debug(ctx->ins, "got azure token"); + } + + /* Reached this code-block means, got new token or token not expired */ + /* Either way we copy the token to a new string */ + token_len = flb_sds_len(ctx->u_auth->token_type) + 2 + + flb_sds_len(ctx->u_auth->access_token); + flb_plg_debug(ctx->ins, "create token header string"); + /* Now create */ + token_return = flb_sds_create_size(token_len); + if (!token_return) { + flb_plg_error(ctx->ins, "error creating token buffer"); + goto token_cleanup; + } + flb_sds_snprintf(&token_return, flb_sds_alloc(token_return), "%s %s", + ctx->u_auth->token_type, ctx->u_auth->access_token); + +token_cleanup: + if (pthread_mutex_unlock(&ctx->token_mutex)) { + flb_plg_error(ctx->ins, "error unlocking mutex"); + return NULL; + } + + return token_return; +} + +static void cb_azure_logs_ingestion_flush(struct flb_event_chunk *event_chunk, + struct flb_output_flush *out_flush, + struct flb_input_instance *i_ins, + void *out_context, + struct flb_config *config) +{ + int ret; + int flush_status; + size_t b_sent; + size_t json_payload_size; + void* final_payload; + size_t final_payload_size; + flb_sds_t token; + struct flb_connection *u_conn; + struct flb_http_client *c; + int is_compressed = FLB_FALSE; + flb_sds_t json_payload = NULL; + struct flb_az_li *ctx = out_context; + (void) i_ins; + (void) config; + + /* Get upstream connection */ + u_conn = flb_upstream_conn_get(ctx->u_dce); + if (!u_conn) { + FLB_OUTPUT_RETURN(FLB_RETRY); + } + + /* Convert binary logs into a JSON payload */ + ret = az_li_format(event_chunk->data, event_chunk->size, + &json_payload, &json_payload_size, ctx); + if (ret == -1) { + flb_upstream_conn_release(u_conn); + FLB_OUTPUT_RETURN(FLB_ERROR); + } + + /* Get OAuth2 token */ + token = get_az_li_token(ctx); + if (!token) { + flush_status = FLB_RETRY; + goto cleanup; + } + + /* Map buffer */ + final_payload = json_payload; + final_payload_size = json_payload_size; + if (ctx->compress_enabled == FLB_TRUE) { + ret = flb_gzip_compress((void *) json_payload, json_payload_size, + &final_payload, &final_payload_size); + if (ret == -1) { + flb_plg_error(ctx->ins, + "cannot gzip payload, disabling compression"); + } + else { + is_compressed = FLB_TRUE; + flb_plg_debug(ctx->ins, "enabled payload gzip compression"); + /* JSON buffer will be cleared at cleanup: */ + } + } + + /* Compose HTTP Client request */ + c = flb_http_client(u_conn, FLB_HTTP_POST, ctx->dce_u_url, + final_payload, final_payload_size, NULL, 0, NULL, 0); + + if (!c) { + flb_plg_warn(ctx->ins, "retrying payload bytes=%lu", final_payload_size); + flush_status = FLB_RETRY; + goto cleanup; + } + + /* Append headers */ + flb_http_add_header(c, "User-Agent", 10, "Fluent-Bit", 10); + flb_http_add_header(c, "Content-Type", 12, "application/json", 16); + if (is_compressed) { + flb_http_add_header(c, "Content-Encoding", 16, "gzip", 4); + } + flb_http_add_header(c, "Authorization", 13, token, flb_sds_len(token)); + flb_http_buffer_size(c, FLB_HTTP_DATA_SIZE_MAX); + + /* Execute rest call */ + ret = flb_http_do(c, &b_sent); + if (ret != 0) { + flb_plg_warn(ctx->ins, "http_do=%i", ret); + flush_status = FLB_RETRY; + goto cleanup; + } + else { + if (c->resp.status >= 200 && c->resp.status <= 299) { + flb_plg_info(ctx->ins, "http_status=%i, dcr_id=%s, table=%s", + c->resp.status, ctx->dcr_id, ctx->table_name); + flush_status = FLB_OK; + goto cleanup; + } + else { + if (c->resp.payload_size > 0) { + flb_plg_warn(ctx->ins, "http_status=%i:\n%s", + c->resp.status, c->resp.payload); + } + else { + flb_plg_warn(ctx->ins, "http_status=%i", c->resp.status); + } + flb_plg_debug(ctx->ins, "retrying payload bytes=%lu", final_payload_size); + flush_status = FLB_RETRY; + goto cleanup; + } + } + +cleanup: + /* cleanup */ + if (json_payload) { + flb_sds_destroy(json_payload); + } + + /* release compressed payload */ + if (is_compressed == FLB_TRUE) { + flb_free(final_payload); + } + + if (c) { + flb_http_client_destroy(c); + } + if (u_conn) { + flb_upstream_conn_release(u_conn); + } + + /* destory token at last after HTTP call has finished */ + if (token) { + flb_sds_destroy(token); + } + FLB_OUTPUT_RETURN(flush_status); +} + +static int cb_azure_logs_ingestion_exit(void *data, struct flb_config *config) +{ + struct flb_az_li *ctx = data; + flb_plg_debug(ctx->ins, "exiting logs ingestion plugin"); + flb_az_li_ctx_destroy(ctx); + return 0; +} + +/* Configuration properties map */ +static struct flb_config_map config_map[] = { + { + FLB_CONFIG_MAP_STR, "tenant_id", (char *)NULL, + 0, FLB_TRUE, offsetof(struct flb_az_li, tenant_id), + "Set the tenant ID of the AAD application" + }, + { + FLB_CONFIG_MAP_STR, "client_id", (char *)NULL, + 0, FLB_TRUE, offsetof(struct flb_az_li, client_id), + "Set the client/app ID of the AAD application" + }, + { + FLB_CONFIG_MAP_STR, "client_secret", (char *)NULL, + 0, FLB_TRUE, offsetof(struct flb_az_li, client_secret), + "Set the client secret of the AAD application" + }, + { + FLB_CONFIG_MAP_STR, "dce_url", (char *)NULL, + 0, FLB_TRUE, offsetof(struct flb_az_li, dce_url), + "Data Collection Endpoint(DCE) URI (e.g. " + "https://la-endpoint-q12a.eastus-1.ingest.monitor.azure.com)" + }, + { + FLB_CONFIG_MAP_STR, "dcr_id", (char *)NULL, + 0, FLB_TRUE, offsetof(struct flb_az_li, dcr_id), + "Data Collection Rule (DCR) immutable ID" + }, + { + FLB_CONFIG_MAP_STR, "table_name", (char *)NULL, + 0, FLB_TRUE, offsetof(struct flb_az_li, table_name), + "The name of the custom log table, including '_CL' suffix" + }, + /* optional params */ + { + FLB_CONFIG_MAP_STR, "time_key", FLB_AZ_LI_TIME_KEY, + 0, FLB_TRUE, offsetof(struct flb_az_li, time_key), + "[Optional] Specify the key name where the timestamp will be stored." + }, + { + FLB_CONFIG_MAP_BOOL, "time_generated", "false", + 0, FLB_TRUE, offsetof(struct flb_az_li, time_generated), + "If enabled, will generate a timestamp and append it to JSON. " + "The key name is set by the 'time_key' parameter" + }, + { + FLB_CONFIG_MAP_BOOL, "compress", "false", + 0, FLB_TRUE, offsetof(struct flb_az_li, compress_enabled), + "Enable HTTP payload compression (gzip)." + }, + /* EOF */ + {0} +}; + +struct flb_output_plugin out_azure_logs_ingestion_plugin = { + .name = "azure_logs_ingestion", + .description = "Send logs to Log Analytics with Log Ingestion API", + .cb_init = cb_azure_logs_ingestion_init, + .cb_flush = cb_azure_logs_ingestion_flush, + .cb_exit = cb_azure_logs_ingestion_exit, + + /* Configuration */ + .config_map = config_map, + + /* Plugin flags */ + .flags = FLB_OUTPUT_NET | FLB_IO_TLS, +}; diff --git a/plugins/out_azure_logs_ingestion/azure_logs_ingestion.h b/plugins/out_azure_logs_ingestion/azure_logs_ingestion.h new file mode 100644 index 00000000000..15b2420b87e --- /dev/null +++ b/plugins/out_azure_logs_ingestion/azure_logs_ingestion.h @@ -0,0 +1,74 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Fluent Bit + * ========== + * Copyright (C) 2015-2022 The Fluent Bit Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLB_OUT_AZURE_LOGS_INGESTION +#define FLB_OUT_AZURE_LOGS_INGESTION + +#define FLB_AZ_LI_API_VERSION "api-version=2021-11-01-preview" +#define FLB_AZ_LI_TIME_KEY "@timestamp" +#define FLB_AZ_LI_AUTH_SCOPE "https://monitor.azure.com/.default" +/* auth url needs tenant_id */ +#define FLB_AZ_LI_AUTH_URL_TMPLT "https://login.microsoftonline.com/"\ + "%s/oauth2/v2.0/token" +/* DCE Full URL needs: dce_url, dcr_id, Log Analytics custom table name */ +#define FLB_AZ_LI_DCE_URL_TMPLT "%s/dataCollectionRules/%s/streams/"\ + "Custom-%s?"FLB_AZ_LI_API_VERSION +/* TLS Modes for upstream connection = FLB_IO_TLS or FLB_IO_OPT_TLS*/ +#define FLB_AZ_LI_TLS_MODE FLB_IO_TLS +/* refresh token every 60 minutes */ +#define FLB_AZ_LI_TOKEN_TIMEOUT 3600 + +#include +#include +#include + +/* Context structure for Azure Logs Ingestion API */ +struct flb_az_li { + /* log ingestion account setup */ + flb_sds_t tenant_id; + flb_sds_t client_id; + flb_sds_t client_secret; + flb_sds_t dce_url; + flb_sds_t dcr_id; + flb_sds_t table_name; + + /* time_generated: on/off */ + int time_generated; + /* time key name */ + flb_sds_t time_key; + + /* compress payload */ + int compress_enabled; + + /* mangement auth */ + flb_sds_t auth_url; + struct flb_oauth2 *u_auth; + /* mutex for acquiring tokens */ + pthread_mutex_t token_mutex; + + /* upstream connection to the data collection endpoint */ + struct flb_upstream *u_dce; + flb_sds_t dce_u_url; + + /* plugin output and config instance reference */ + struct flb_output_instance *ins; + struct flb_config *config; +}; + +#endif diff --git a/plugins/out_azure_logs_ingestion/azure_logs_ingestion_conf.c b/plugins/out_azure_logs_ingestion/azure_logs_ingestion_conf.c new file mode 100644 index 00000000000..344a7f5ff12 --- /dev/null +++ b/plugins/out_azure_logs_ingestion/azure_logs_ingestion_conf.c @@ -0,0 +1,172 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Fluent Bit + * ========== + * Copyright (C) 2015-2022 The Fluent Bit Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include + +#include "azure_logs_ingestion.h" +#include "azure_logs_ingestion_conf.h" + +struct flb_az_li* flb_az_li_ctx_create(struct flb_output_instance *ins, + struct flb_config *config) +{ + int ret; + struct flb_az_li *ctx; + (void) ins; + (void) config; + + /* Allocate a new context object for this output instance */ + ctx = flb_calloc(1, sizeof(struct flb_az_li)); + if (!ctx) { + flb_errno(); + return NULL; + } + + /* Set the conext in output_instance so that we can retrieve it later */ + ctx->ins = ins; + ctx->config = config; + /* Set context */ + flb_output_set_context(ins, ctx); + + /* Load config map */ + ret = flb_output_config_map_set(ins, (void *) ctx); + if (ret == -1) { + flb_plg_error(ins, "unable to load configuration"); + return NULL; + } + + /* config: 'client_id' */ + if (!ctx->client_id) { + flb_plg_error(ins, "property 'client_id' is not defined"); + flb_az_li_ctx_destroy(ctx); + return NULL; + } + /* config: 'tenant_id' */ + if (!ctx->tenant_id) { + flb_plg_error(ins, "property 'tenant_id' is not defined"); + flb_az_li_ctx_destroy(ctx); + return NULL; + } + /* config: 'client_secret' */ + if (!ctx->client_secret) { + flb_plg_error(ins, "property 'client_secret' is not defined"); + flb_az_li_ctx_destroy(ctx); + return NULL; + } + /* config: 'dce_url' */ + if (!ctx->dce_url) { + flb_plg_error(ins, "property 'dce_url' is not defined"); + flb_az_li_ctx_destroy(ctx); + return NULL; + } + /* config: 'dcr_id' */ + if (!ctx->dcr_id) { + flb_plg_error(ins, "property 'dcr_id' is not defined"); + flb_az_li_ctx_destroy(ctx); + return NULL; + } + /* config: 'table_name' */ + if (!ctx->table_name) { + flb_plg_error(ins, "property 'table_name' is not defined"); + flb_az_li_ctx_destroy(ctx); + return NULL; + } + + /* Allocate and set auth url */ + ctx->auth_url = flb_sds_create_size(sizeof(FLB_AZ_LI_AUTH_URL_TMPLT) - 1 + + flb_sds_len(ctx->tenant_id)); + if (!ctx->auth_url) { + flb_errno(); + flb_az_li_ctx_destroy(ctx); + return NULL; + } + flb_sds_snprintf(&ctx->auth_url, flb_sds_alloc(ctx->auth_url), + FLB_AZ_LI_AUTH_URL_TMPLT, ctx->tenant_id); + + /* Allocate and set dce full url */ + ctx->dce_u_url = flb_sds_create_size(sizeof(FLB_AZ_LI_DCE_URL_TMPLT) - 1 + + flb_sds_len(ctx->dce_url) + + flb_sds_len(ctx->dcr_id) + + flb_sds_len(ctx->table_name)); + if (!ctx->dce_u_url) { + flb_errno(); + flb_az_li_ctx_destroy(ctx); + return NULL; + } + flb_sds_snprintf(&ctx->dce_u_url, flb_sds_alloc(ctx->dce_u_url), + FLB_AZ_LI_DCE_URL_TMPLT, ctx->dce_url, + ctx->dcr_id, ctx->table_name); + + /* Initialize the auth mutex */ + pthread_mutex_init(&ctx->token_mutex, NULL); + + /* Create oauth2 context */ + ctx->u_auth = flb_oauth2_create(config, ctx->auth_url, + FLB_AZ_LI_TOKEN_TIMEOUT); + if (!ctx->u_auth) { + flb_plg_error(ins, "cannot create oauth2 context"); + flb_az_li_ctx_destroy(ctx); + return NULL; + } + + /* Create upstream context for Log Ingsetion endpoint */ + ctx->u_dce = flb_upstream_create_url(config, ctx->dce_url, + FLB_AZ_LI_TLS_MODE, ins->tls); + if (!ctx->u_dce) { + flb_plg_error(ins, "upstream creation failed"); + flb_az_li_ctx_destroy(ctx); + return NULL; + } + flb_output_upstream_set(ctx->u_dce, ins); + + flb_plg_info(ins, "dce_url='%s', dcr='%s', table='%s', stream='Custom-%s'", + ctx->dce_url, ctx->dcr_id, ctx->table_name, ctx->table_name); + + return ctx; +} + +/* Free the context and created memory */ +int flb_az_li_ctx_destroy(struct flb_az_li *ctx) +{ + if (!ctx) { + return -1; + } + + if (ctx->auth_url) { + flb_sds_destroy(ctx->auth_url); + } + + if (ctx->dce_u_url) { + flb_sds_destroy(ctx->dce_u_url); + } + + if (ctx->u_auth) { + flb_oauth2_destroy(ctx->u_auth); + } + + if (ctx->u_dce) { + flb_upstream_destroy(ctx->u_dce); + } + flb_free(ctx); + + return 0; +} diff --git a/plugins/out_azure_logs_ingestion/azure_logs_ingestion_conf.h b/plugins/out_azure_logs_ingestion/azure_logs_ingestion_conf.h new file mode 100644 index 00000000000..3886f75bc19 --- /dev/null +++ b/plugins/out_azure_logs_ingestion/azure_logs_ingestion_conf.h @@ -0,0 +1,29 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Fluent Bit + * ========== + * Copyright (C) 2015-2022 The Fluent Bit Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLB_OUT_AZURE_LOGS_INGESTION_CONF_H +#define FLB_OUT_AZURE_LOGS_INGESTION_CONF_H + +#include "azure_logs_ingestion.h" + +struct flb_az_li* flb_az_li_ctx_create(struct flb_output_instance *ins, + struct flb_config *config); +int flb_az_li_ctx_destroy(struct flb_az_li *ctx); + +#endif From 4ba251fbca59281a3e92d426233c363d40073d2f Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Wed, 14 Jun 2023 20:55:32 -0600 Subject: [PATCH 011/315] lib: cmetrics: upgrade to v0.6.2 (#7565) Signed-off-by: Eduardo Silva --- lib/cmetrics/CMakeLists.txt | 2 +- lib/cmetrics/src/cmt_encode_opentelemetry.c | 29 +++++++++------------ 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/lib/cmetrics/CMakeLists.txt b/lib/cmetrics/CMakeLists.txt index 89089c0f256..411e68ddc40 100644 --- a/lib/cmetrics/CMakeLists.txt +++ b/lib/cmetrics/CMakeLists.txt @@ -57,7 +57,7 @@ endif() # CMetrics Version set(CMT_VERSION_MAJOR 0) set(CMT_VERSION_MINOR 6) -set(CMT_VERSION_PATCH 1) +set(CMT_VERSION_PATCH 2) set(CMT_VERSION_STR "${CMT_VERSION_MAJOR}.${CMT_VERSION_MINOR}.${CMT_VERSION_PATCH}") # Define __CMT_FILENAME__ consistently across Operating Systems diff --git a/lib/cmetrics/src/cmt_encode_opentelemetry.c b/lib/cmetrics/src/cmt_encode_opentelemetry.c index e0d7cfc8a3e..8c934186330 100644 --- a/lib/cmetrics/src/cmt_encode_opentelemetry.c +++ b/lib/cmetrics/src/cmt_encode_opentelemetry.c @@ -26,14 +26,10 @@ #include #include - -#define CMT_PRIVATE_ATTRIBUTE_PREFIX "__cmetrics__" - - - static Opentelemetry__Proto__Metrics__V1__ScopeMetrics ** initialize_scope_metrics_list( size_t element_count); + static void destroy_scope_metric_list( Opentelemetry__Proto__Metrics__V1__ScopeMetrics **metric_list); @@ -1607,7 +1603,6 @@ static Opentelemetry__Proto__Metrics__V1__HistogramDataPoint * data_point->n_bucket_counts = bucket_count; data_point->sum = sum; - // data_point->_sum_case = OPENTELEMETRY__PROTO__METRICS__V1__HISTOGRAM_DATA_POINT___SUM_SUM; if (bucket_count > 0) { data_point->bucket_counts = calloc(bucket_count, sizeof(uint64_t)); @@ -1901,26 +1896,26 @@ static Opentelemetry__Proto__Metrics__V1__Metric * metric->sum->n_data_points = data_point_count; } else if (type == CMT_UNTYPED) { - metric->sum = calloc(1, sizeof(Opentelemetry__Proto__Metrics__V1__Sum)); + metric->gauge = calloc(1, sizeof(Opentelemetry__Proto__Metrics__V1__Gauge)); - if (metric->sum == NULL) { + if (metric->gauge == NULL) { destroy_metric(metric); return NULL; } - opentelemetry__proto__metrics__v1__sum__init(metric->sum); + opentelemetry__proto__metrics__v1__gauge__init(metric->gauge); - metric->data_case = OPENTELEMETRY__PROTO__METRICS__V1__METRIC__DATA_SUM; - metric->sum->data_points = initialize_numerical_data_point_list(data_point_count); + metric->data_case = OPENTELEMETRY__PROTO__METRICS__V1__METRIC__DATA_GAUGE; + metric->gauge->data_points = initialize_numerical_data_point_list(data_point_count); - if (metric->sum->data_points == NULL) { + if (metric->gauge->data_points == NULL) { destroy_metric(metric); return NULL; } - metric->sum->n_data_points = data_point_count; + metric->gauge->n_data_points = data_point_count; } else if (type == CMT_GAUGE) { metric->gauge = calloc(1, sizeof(Opentelemetry__Proto__Metrics__V1__Gauge)); @@ -2487,13 +2482,15 @@ static cfl_sds_t render_opentelemetry_context_to_sds( cfl_sds_t result_buffer; size_t result_size; - result_size = opentelemetry__proto__metrics__v1__metrics_data__get_packed_size(context->metrics_data); + result_size = opentelemetry__proto__metrics__v1__metrics_data__get_packed_size( + context->metrics_data); result_buffer = cfl_sds_create_size(result_size); if(result_buffer != NULL) { - opentelemetry__proto__metrics__v1__metrics_data__pack(context->metrics_data, - (uint8_t *) result_buffer); + opentelemetry__proto__metrics__v1__metrics_data__pack( + context->metrics_data, + (uint8_t *) result_buffer); cfl_sds_set_len(result_buffer, result_size); } From ecf5a09dcf4ae5ef609736e8b95ceb7aad25afcd Mon Sep 17 00:00:00 2001 From: Wesley Pettit Date: Wed, 14 Jun 2023 19:55:59 -0700 Subject: [PATCH 012/315] out_cloudwatch_logs: fix logic in free-ing log streams on shutdown (#7159) Signed-off-by: Wesley Pettit --- plugins/out_cloudwatch_logs/cloudwatch_logs.c | 27 +++---------------- plugins/out_cloudwatch_logs/cloudwatch_logs.h | 5 +--- 2 files changed, 5 insertions(+), 27 deletions(-) diff --git a/plugins/out_cloudwatch_logs/cloudwatch_logs.c b/plugins/out_cloudwatch_logs/cloudwatch_logs.c index a37039ca500..e197fe8841b 100644 --- a/plugins/out_cloudwatch_logs/cloudwatch_logs.c +++ b/plugins/out_cloudwatch_logs/cloudwatch_logs.c @@ -213,16 +213,6 @@ static int cb_cloudwatch_init(struct flb_output_instance *ins, ctx->sts_endpoint = (char *) tmp; } - /* init log streams */ - if (ctx->log_stream_name) { - ctx->stream.name = flb_sds_create(ctx->log_stream_name); - if (!ctx->stream.name) { - flb_errno(); - goto error; - } - ctx->stream_created = FLB_FALSE; - } - /* one tls instance for provider, one for cw client */ ctx->cred_tls = flb_tls_create(FLB_TLS_CLIENT_MODE, FLB_TRUE, @@ -484,19 +474,10 @@ void flb_cloudwatch_ctx_destroy(struct flb_cloudwatch *ctx) flb_sds_destroy(ctx->stream_name); } - if (ctx->log_stream_name) { - if (ctx->stream.name) { - flb_sds_destroy(ctx->stream.name); - } - if (ctx->stream.sequence_token) { - flb_sds_destroy(ctx->stream.sequence_token); - } - } else { - mk_list_foreach_safe(head, tmp, &ctx->streams) { - stream = mk_list_entry(head, struct log_stream, _head); - mk_list_del(&stream->_head); - log_stream_destroy(stream); - } + mk_list_foreach_safe(head, tmp, &ctx->streams) { + stream = mk_list_entry(head, struct log_stream, _head); + mk_list_del(&stream->_head); + log_stream_destroy(stream); } flb_free(ctx); } diff --git a/plugins/out_cloudwatch_logs/cloudwatch_logs.h b/plugins/out_cloudwatch_logs/cloudwatch_logs.h index e89cd3ce1e9..7fe8bf0b764 100644 --- a/plugins/out_cloudwatch_logs/cloudwatch_logs.h +++ b/plugins/out_cloudwatch_logs/cloudwatch_logs.h @@ -135,10 +135,7 @@ struct flb_cloudwatch { struct flb_record_accessor *ra_group; struct flb_record_accessor *ra_stream; - /* if we're writing to a static log stream, we'll use this */ - struct log_stream stream; - int stream_created; - /* if the log stream is dynamic, we'll use this */ + /* stores log streams we're putting to */ struct mk_list streams; /* buffers for data processing and request payload */ From 00e229efdf6b0280803ba679f19630d77f369831 Mon Sep 17 00:00:00 2001 From: Wesley Pettit Date: Wed, 14 Jun 2023 19:56:22 -0700 Subject: [PATCH 013/315] aws: sts_credentials: make STS response parsing less brittle by checking for the full XML end node (#7357) Signed-off-by: Wesley Pettit --- src/aws/flb_aws_credentials_sts.c | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/src/aws/flb_aws_credentials_sts.c b/src/aws/flb_aws_credentials_sts.c index 1de72db9aac..d059f43dc20 100644 --- a/src/aws/flb_aws_credentials_sts.c +++ b/src/aws/flb_aws_credentials_sts.c @@ -33,16 +33,30 @@ &RoleSessionName=%s&RoleArn=%s" #define STS_ASSUME_ROLE_URI_BASE_LEN 54 +/* + * The STS APIs return an XML document with credentials. + * The part of the document we care about looks like this: + * + * akid + * skid + * token + * 2019-11-09T13:34:41Z + * + */ #define CREDENTIALS_NODE "" #define CREDENTIALS_NODE_LEN 13 #define ACCESS_KEY_NODE "" #define ACCESS_KEY_NODE_LEN 13 +#define ACCESS_KEY_NODE_END "" #define SECRET_KEY_NODE "" #define SECRET_KEY_NODE_LEN 17 +#define SECRET_KEY_NODE_END "" #define SESSION_TOKEN_NODE "" #define SESSION_TOKEN_NODE_LEN 14 +#define SESSION_TOKEN_NODE_END "" #define EXPIRATION_NODE "" #define EXPIRATION_NODE_LEN 12 +#define EXPIRATION_NODE_END "" #define TOKEN_FILE_ENV_VAR "AWS_WEB_IDENTITY_TOKEN_FILE" #define ROLE_ARN_ENV_VAR "AWS_ROLE_ARN" @@ -58,7 +72,7 @@ static int sts_assume_role_request(struct flb_aws_client *sts_client, struct flb_aws_credentials **creds, char *uri, time_t *next_refresh); -static flb_sds_t get_node(char *cred_node, char* node_name, int node_len); +static flb_sds_t get_node(char *cred_node, char* node_name, int node_name_len, char* node_end); /* @@ -825,24 +839,24 @@ struct flb_aws_credentials *flb_parse_sts_resp(char *response, } creds->access_key_id = get_node(cred_node, ACCESS_KEY_NODE, - ACCESS_KEY_NODE_LEN); + ACCESS_KEY_NODE_LEN, ACCESS_KEY_NODE_END); if (!creds->access_key_id) { goto error; } creds->secret_access_key = get_node(cred_node, SECRET_KEY_NODE, - SECRET_KEY_NODE_LEN); + SECRET_KEY_NODE_LEN, SECRET_KEY_NODE_END); if (!creds->secret_access_key) { goto error; } creds->session_token = get_node(cred_node, SESSION_TOKEN_NODE, - SESSION_TOKEN_NODE_LEN); + SESSION_TOKEN_NODE_LEN, SESSION_TOKEN_NODE_END); if (!creds->session_token) { goto error; } - tmp = get_node(cred_node, EXPIRATION_NODE, EXPIRATION_NODE_LEN); + tmp = get_node(cred_node, EXPIRATION_NODE, EXPIRATION_NODE_LEN, EXPIRATION_NODE_END); if (!tmp) { goto error; } @@ -909,7 +923,7 @@ flb_sds_t flb_sts_uri(char *action, char *role_arn, char *session_name, return uri; } -static flb_sds_t get_node(char *cred_node, char* node_name, int node_len) +static flb_sds_t get_node(char *cred_node, char* node_name, int node_name_len, char* node_end) { char *node = NULL; char *end = NULL; @@ -922,8 +936,8 @@ static flb_sds_t get_node(char *cred_node, char* node_name, int node_len) node_name); return NULL; } - node += node_len; - end = strchr(node, '<'); + node += node_name_len; + end = strstr(node, node_end); if (!end) { flb_error("[aws_credentials] Could not find end of '%s' node in " "sts response", node_name); From 96cbe59069b778ebfc165e80a4405510d956d0cd Mon Sep 17 00:00:00 2001 From: Wesley Pettit Date: Wed, 14 Jun 2023 19:57:05 -0700 Subject: [PATCH 014/315] out_s3: fix wrong decrementing of INDEX when UploadPart fails (#7393) Signed-off-by: Wesley Pettit --- plugins/out_s3/s3.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/plugins/out_s3/s3.c b/plugins/out_s3/s3.c index 1e35ca55c35..f938cdaf51e 100644 --- a/plugins/out_s3/s3.c +++ b/plugins/out_s3/s3.c @@ -1121,15 +1121,6 @@ static int upload_data(struct flb_s3 *ctx, struct s3_file *chunk, s3_store_file_unlock(chunk); chunk->failures += 1; } - if (ctx->key_fmt_has_seq_index) { - ctx->seq_index--; - - ret = write_seq_index(ctx->seq_index_file, ctx->seq_index); - if (ret < 0) { - flb_plg_error(ctx->ins, "Failed to decrement index after request error"); - return -1; - } - } return FLB_RETRY; } m_upload->part_number += 1; From 2d99b1c09cacaeeae2980c01c2c07f0e7d74a2f3 Mon Sep 17 00:00:00 2001 From: Wesley Pettit Date: Fri, 2 Jun 2023 17:00:31 -0700 Subject: [PATCH 015/315] aws: always use calloc for creds Signed-off-by: Wesley Pettit --- src/aws/flb_aws_credentials_ec2.c | 2 +- src/aws/flb_aws_credentials_http.c | 2 +- src/aws/flb_aws_credentials_profile.c | 2 +- src/aws/flb_aws_credentials_sts.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/aws/flb_aws_credentials_ec2.c b/src/aws/flb_aws_credentials_ec2.c index 0aef2e2833e..976d143bde2 100644 --- a/src/aws/flb_aws_credentials_ec2.c +++ b/src/aws/flb_aws_credentials_ec2.c @@ -88,7 +88,7 @@ struct flb_aws_credentials *get_credentials_fn_ec2(struct flb_aws_provider return NULL; } - creds = flb_malloc(sizeof(struct flb_aws_credentials)); + creds = flb_calloc(1, sizeof(struct flb_aws_credentials)); if (!creds) { flb_errno(); return NULL; diff --git a/src/aws/flb_aws_credentials_http.c b/src/aws/flb_aws_credentials_http.c index e149d648dae..f3ff179e1b6 100644 --- a/src/aws/flb_aws_credentials_http.c +++ b/src/aws/flb_aws_credentials_http.c @@ -98,7 +98,7 @@ struct flb_aws_credentials *get_credentials_fn_http(struct flb_aws_provider return NULL; } - creds = flb_malloc(sizeof(struct flb_aws_credentials)); + creds = flb_calloc(1, sizeof(struct flb_aws_credentials)); if (!creds) { flb_errno(); goto error; diff --git a/src/aws/flb_aws_credentials_profile.c b/src/aws/flb_aws_credentials_profile.c index a149ec44cd5..88d6298e706 100644 --- a/src/aws/flb_aws_credentials_profile.c +++ b/src/aws/flb_aws_credentials_profile.c @@ -111,7 +111,7 @@ struct flb_aws_credentials *get_credentials_fn_profile(struct flb_aws_provider } } - creds = flb_malloc(sizeof(struct flb_aws_credentials)); + creds = flb_calloc(1, sizeof(struct flb_aws_credentials)); if (!creds) { flb_errno(); goto error; diff --git a/src/aws/flb_aws_credentials_sts.c b/src/aws/flb_aws_credentials_sts.c index d059f43dc20..079be42f88d 100644 --- a/src/aws/flb_aws_credentials_sts.c +++ b/src/aws/flb_aws_credentials_sts.c @@ -135,7 +135,7 @@ struct flb_aws_credentials *get_credentials_fn_sts(struct flb_aws_provider } /* return a copy of the existing cached credentials */ - creds = flb_malloc(sizeof(struct flb_aws_credentials)); + creds = flb_calloc(1, sizeof(struct flb_aws_credentials)); if (!creds) { goto error; } From c1717668618a8770a72c39dd6dcfeb7a64582100 Mon Sep 17 00:00:00 2001 From: Wesley Pettit Date: Sat, 3 Jun 2023 19:52:50 -0700 Subject: [PATCH 016/315] aws: check for full xml end node in flb_aws_xml_get_val Signed-off-by: Wesley Pettit --- include/fluent-bit/flb_aws_util.h | 3 ++- src/aws/flb_aws_util.c | 11 ++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/include/fluent-bit/flb_aws_util.h b/include/fluent-bit/flb_aws_util.h index 96b6d3aedf9..08507dccfbb 100644 --- a/include/fluent-bit/flb_aws_util.h +++ b/include/fluent-bit/flb_aws_util.h @@ -163,8 +163,9 @@ flb_sds_t flb_json_get_val(char *response, size_t response_len, char *key); /* * Parses an XML document and returns the value of the given tag * Param `tag` should include angle brackets; ex "" + * And param `end` should include end brackets: "" */ -flb_sds_t flb_xml_get_val(char *response, size_t response_len, char *tag); +flb_sds_t flb_aws_xml_get_val(char *response, size_t response_len, char *tag, char *tag_end); /* * Checks if a response contains an AWS Auth error diff --git a/src/aws/flb_aws_util.c b/src/aws/flb_aws_util.c index 712450e16d8..75efe1b0df1 100644 --- a/src/aws/flb_aws_util.c +++ b/src/aws/flb_aws_util.c @@ -508,13 +508,13 @@ void flb_aws_print_xml_error(char *response, size_t response_len, flb_sds_t error; flb_sds_t message; - error = flb_xml_get_val(response, response_len, ""); + error = flb_aws_xml_get_val(response, response_len, "", ""); if (!error) { flb_plg_error(ins, "%s: Could not parse response", api); return; } - message = flb_xml_get_val(response, response_len, ""); + message = flb_aws_xml_get_val(response, response_len, "", ""); if (!message) { /* just print the error */ flb_plg_error(ins, "%s API responded with error='%s'", api, error); @@ -531,14 +531,15 @@ void flb_aws_print_xml_error(char *response, size_t response_len, /* Parses AWS XML API Error responses and returns the value of the tag */ flb_sds_t flb_aws_xml_error(char *response, size_t response_len) { - return flb_xml_get_val(response, response_len, ""); + return flb_aws_xml_get_val(response, response_len, "", ""); } /* * Parses an XML document and returns the value of the given tag * Param `tag` should include angle brackets; ex "" + * And param `end` should include end brackets: "" */ -flb_sds_t flb_xml_get_val(char *response, size_t response_len, char *tag) +flb_sds_t flb_aws_xml_get_val(char *response, size_t response_len, char *tag, char *tag_end) { flb_sds_t val = NULL; char *node = NULL; @@ -557,7 +558,7 @@ flb_sds_t flb_xml_get_val(char *response, size_t response_len, char *tag) /* advance to end of tag */ node += strlen(tag); - end = strchr(node, '<'); + end = strstr(node, tag_end); if (!end) { flb_error("[aws] Could not find end of '%s' node in xml", tag); return NULL; From 4e717e7d6fcc1497936e57bb3fee3e48cd6ffca6 Mon Sep 17 00:00:00 2001 From: Wesley Pettit Date: Sat, 3 Jun 2023 19:53:05 -0700 Subject: [PATCH 017/315] out_s3: use new flb_aws_xml_get_val Signed-off-by: Wesley Pettit --- plugins/out_s3/s3_multipart.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/out_s3/s3_multipart.c b/plugins/out_s3/s3_multipart.c index 4d5090cd736..1eb2a1061df 100644 --- a/plugins/out_s3/s3_multipart.c +++ b/plugins/out_s3/s3_multipart.c @@ -522,8 +522,8 @@ int create_multipart_upload(struct flb_s3 *ctx, flb_plg_debug(ctx->ins, "CreateMultipartUpload http status=%d", c->resp.status); if (c->resp.status == 200) { - tmp = flb_xml_get_val(c->resp.payload, c->resp.payload_size, - ""); + tmp = flb_aws_xml_get_val(c->resp.payload, c->resp.payload_size, + "", ""); if (!tmp) { flb_plg_error(ctx->ins, "Could not find upload ID in " "CreateMultipartUpload response"); From 033dfe082335bfe333dfcdd5e9dff3e418e007ee Mon Sep 17 00:00:00 2001 From: Wesley Pettit Date: Fri, 2 Jun 2023 17:36:36 -0700 Subject: [PATCH 018/315] aws: protect credential providers with pthread_mutex Signed-off-by: Wesley Pettit --- include/fluent-bit/flb_aws_credentials.h | 9 ++++--- src/aws/flb_aws_credentials.c | 24 ++++++++++-------- src/aws/flb_aws_credentials_ec2.c | 2 ++ src/aws/flb_aws_credentials_http.c | 2 ++ src/aws/flb_aws_credentials_profile.c | 32 +++++++++++++++++++----- src/aws/flb_aws_credentials_sts.c | 6 ++++- 6 files changed, 53 insertions(+), 22 deletions(-) diff --git a/include/fluent-bit/flb_aws_credentials.h b/include/fluent-bit/flb_aws_credentials.h index 6031b3d97b2..cba1d680a24 100644 --- a/include/fluent-bit/flb_aws_credentials.h +++ b/include/fluent-bit/flb_aws_credentials.h @@ -118,12 +118,13 @@ struct flb_aws_provider_vtable { */ struct flb_aws_provider { /* - * Fluent Bit is single-threaded but asynchonous. Co-routines are paused - * and resumed during blocking IO calls. - * + * Fluent Bit now has multi-threads/workers, need to a mutex to protect cred provider. * When a refresh is needed, only one co-routine should refresh. + * When one thread refreshes, the cached creds are freed and reset, there could be a double + * free without a lock. + * We use trylock to prevent deadlock. */ - int locked; + pthread_mutex_t lock; struct flb_aws_provider_vtable *provider_vtable; diff --git a/src/aws/flb_aws_credentials.c b/src/aws/flb_aws_credentials.c index d94c063f97d..850142e24f4 100644 --- a/src/aws/flb_aws_credentials.c +++ b/src/aws/flb_aws_credentials.c @@ -537,6 +537,8 @@ static struct flb_aws_provider *standard_chain_create(struct flb_config return NULL; } + pthread_mutex_init(&provider->lock, NULL); + implementation = flb_calloc(1, sizeof(struct flb_aws_provider_chain)); if (!implementation) { @@ -768,6 +770,8 @@ void flb_aws_provider_destroy(struct flb_aws_provider *provider) provider->provider_vtable->destroy(provider); } + pthread_mutex_destroy(&provider->lock); + /* free managed dependencies */ if (provider->base_aws_provider) { flb_aws_provider_destroy(provider->base_aws_provider); @@ -834,27 +838,25 @@ time_t flb_aws_cred_expiration(const char *timestamp) } /* - * Fluent Bit is single-threaded but asynchonous. Only one co-routine will - * be running at a time, and they only pause/resume for IO. - * - * Thus, while synchronization is needed (to prevent multiple co-routines - * from duplicating effort and performing the same work), it can be obtained - * using a simple integer flag on the provider. + * Fluent Bit is now multi-threaded and asynchonous with coros. + * The trylock prevents deadlock, and protects the provider + * when a cred refresh happens. The refresh frees and + * sets the shared cred cache, a double free could occur + * if two threads do it at the same exact time. */ /* Like a traditional try lock- it does not block if the lock is not obtained */ int try_lock_provider(struct flb_aws_provider *provider) { - if (provider->locked == FLB_TRUE) { + int ret = 0; + ret = pthread_mutex_trylock(&provider->lock); + if (ret != 0) { return FLB_FALSE; } - provider->locked = FLB_TRUE; return FLB_TRUE; } void unlock_provider(struct flb_aws_provider *provider) { - if (provider->locked == FLB_TRUE) { - provider->locked = FLB_FALSE; - } + pthread_mutex_unlock(&provider->lock); } diff --git a/src/aws/flb_aws_credentials_ec2.c b/src/aws/flb_aws_credentials_ec2.c index 976d143bde2..5d2d8515cde 100644 --- a/src/aws/flb_aws_credentials_ec2.c +++ b/src/aws/flb_aws_credentials_ec2.c @@ -229,6 +229,8 @@ struct flb_aws_provider *flb_ec2_provider_create(struct flb_config *config, return NULL; } + pthread_mutex_init(&provider->lock, NULL); + implementation = flb_calloc(1, sizeof(struct flb_aws_provider_ec2)); if (!implementation) { diff --git a/src/aws/flb_aws_credentials_http.c b/src/aws/flb_aws_credentials_http.c index f3ff179e1b6..c08b6b559c8 100644 --- a/src/aws/flb_aws_credentials_http.c +++ b/src/aws/flb_aws_credentials_http.c @@ -250,6 +250,8 @@ struct flb_aws_provider *flb_http_provider_create(struct flb_config *config, return NULL; } + pthread_mutex_init(&provider->lock, NULL); + implementation = flb_calloc(1, sizeof(struct flb_aws_provider_http)); if (!implementation) { diff --git a/src/aws/flb_aws_credentials_profile.c b/src/aws/flb_aws_credentials_profile.c index 88d6298e706..6b3ab5dbdc7 100644 --- a/src/aws/flb_aws_credentials_profile.c +++ b/src/aws/flb_aws_credentials_profile.c @@ -103,10 +103,16 @@ struct flb_aws_credentials *get_credentials_fn_profile(struct flb_aws_provider time(NULL) >= implementation->next_refresh)) { AWS_CREDS_DEBUG("Retrieving credentials for AWS Profile %s", implementation->profile); - ret = refresh_credentials(implementation, FLB_FALSE); - if (ret < 0) { - AWS_CREDS_ERROR("Failed to retrieve credentials for AWS Profile %s", - implementation->profile); + if (try_lock_provider(provider) == FLB_TRUE) { + ret = refresh_credentials(implementation, FLB_FALSE); + unlock_provider(provider); + if (ret < 0) { + AWS_CREDS_ERROR("Failed to retrieve credentials for AWS Profile %s", + implementation->profile); + return NULL; + } + } else { + AWS_CREDS_WARN("Another thread is refreshing credentials, will retry"); return NULL; } } @@ -152,15 +158,27 @@ struct flb_aws_credentials *get_credentials_fn_profile(struct flb_aws_provider int refresh_fn_profile(struct flb_aws_provider *provider) { struct flb_aws_provider_profile *implementation = provider->implementation; + int ret = -1; AWS_CREDS_DEBUG("Refresh called on the profile provider"); - return refresh_credentials(implementation, FLB_FALSE); + if (try_lock_provider(provider) == FLB_TRUE) { + ret = refresh_credentials(implementation, FLB_FALSE); + unlock_provider(provider); + return ret; + } + return ret; } int init_fn_profile(struct flb_aws_provider *provider) { struct flb_aws_provider_profile *implementation = provider->implementation; + int ret = -1; AWS_CREDS_DEBUG("Init called on the profile provider"); - return refresh_credentials(implementation, FLB_TRUE); + if (try_lock_provider(provider) == FLB_TRUE) { + ret = refresh_credentials(implementation, FLB_TRUE); + unlock_provider(provider); + return ret; + } + return ret; } /* @@ -234,6 +252,8 @@ struct flb_aws_provider *flb_profile_provider_create(char* profile) goto error; } + pthread_mutex_init(&provider->lock, NULL); + implementation = flb_calloc(1, sizeof( struct flb_aws_provider_profile)); diff --git a/src/aws/flb_aws_credentials_sts.c b/src/aws/flb_aws_credentials_sts.c index 079be42f88d..d992485cc00 100644 --- a/src/aws/flb_aws_credentials_sts.c +++ b/src/aws/flb_aws_credentials_sts.c @@ -308,6 +308,8 @@ struct flb_aws_provider *flb_sts_provider_create(struct flb_config *config, return NULL; } + pthread_mutex_init(&provider->lock, NULL); + implementation = flb_calloc(1, sizeof(struct flb_aws_provider_sts)); if (!implementation) { goto error; @@ -578,7 +580,9 @@ struct flb_aws_provider *flb_eks_provider_create(struct flb_config *config, flb_errno(); return NULL; } - + + pthread_mutex_init(&provider->lock, NULL); + implementation = flb_calloc(1, sizeof(struct flb_aws_provider_eks)); if (!implementation) { From e74710f38e7573254a1b0bed410b1809b394833c Mon Sep 17 00:00:00 2001 From: Wesley Pettit Date: Fri, 2 Jun 2023 17:41:34 -0700 Subject: [PATCH 019/315] signv4: always use calloc Signed-off-by: Wesley Pettit --- src/flb_signv4.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/flb_signv4.c b/src/flb_signv4.c index 30834ac7b1e..a4283dc050f 100644 --- a/src/flb_signv4.c +++ b/src/flb_signv4.c @@ -399,7 +399,7 @@ static flb_sds_t url_params_format(char *params) return flb_sds_create(""); } - arr = flb_malloc(sizeof(struct flb_kv *) * items); + arr = flb_calloc(1, sizeof(struct flb_kv *) * items); if (!arr) { flb_errno(); flb_kv_release(&list); @@ -825,7 +825,7 @@ static flb_sds_t flb_signv4_canonical_request(struct flb_http_client *c, all_items = mk_list_size(&list_tmp); excluded_items = 0; size = (sizeof(struct flb_kv *) * (all_items)); - arr = flb_malloc(size); + arr = flb_calloc(1, size); if (!arr) { flb_errno(); flb_kv_release(&list_tmp); @@ -1164,7 +1164,7 @@ flb_sds_t flb_signv4_do(struct flb_http_client *c, int normalize_uri, return NULL; } - gmt = flb_malloc(sizeof(struct tm)); + gmt = flb_calloc(1, sizeof(struct tm)); if (!gmt) { flb_errno(); flb_aws_credentials_destroy(creds); From 015012e71d8a651fba885fc1d23a0dc225d1d132 Mon Sep 17 00:00:00 2001 From: Celalettin Calis Date: Mon, 19 Jun 2023 18:51:04 +0300 Subject: [PATCH 020/315] ci: set a version for Chocolatey (#7588) * ci: set a version for Chocolatey fixes #7574 setting Chocolatey version to 1.4.0 since the version doesn't require .NET 4.8 Signed-off-by: Celalettin Calis * ci: added windows tests to pr image tests Signed-off-by: celalettin1286 * ci: changed build method Signed-off-by: celalettin1286 * ci: changed runner to windows 2019 Signed-off-by: celalettin1286 * ci: add matrix for windows 2019 and 2022 Signed-off-by: celalettin1286 * change job title Signed-off-by: celalettin1286 --------- Signed-off-by: Celalettin Calis Signed-off-by: celalettin1286 --- .github/workflows/pr-image-tests.yaml | 38 +++++++++++++++++++++++++++ dockerfiles/Dockerfile.windows | 1 + 2 files changed, 39 insertions(+) diff --git a/.github/workflows/pr-image-tests.yaml b/.github/workflows/pr-image-tests.yaml index cb85748c0f8..b15f8e02cea 100644 --- a/.github/workflows/pr-image-tests.yaml +++ b/.github/workflows/pr-image-tests.yaml @@ -7,6 +7,7 @@ on: - synchronize paths: - 'dockerfiles/Dockerfile' + - 'dockerfiles/Dockerfile.windows' - 'conf/**' workflow_dispatch: @@ -79,3 +80,40 @@ jobs: # Ensure we disable buildkit DOCKER_BUILDKIT: 0 shell: bash + pr-image-tests-build-windows-images: + name: PR - Docker windows build test, windows 2019 and 2022 + runs-on: windows-${{ matrix.windows-base-version }} + strategy: + fail-fast: true + matrix: + windows-base-version: + # https://github.com/fluent/fluent-bit/blob/1d366594a889624ec3003819fe18588aac3f17cd/dockerfiles/Dockerfile.windows#L3 + - '2019' + - '2022' + permissions: + contents: read + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Extract metadata from Github + id: meta + uses: docker/metadata-action@v4 + with: + images: ${{ github.repository }}/pr-${{ github.event.pull_request.number }} + tags: | + type=sha + flavor: | + suffix=-windows-${{ matrix.windows-base-version }} + + - name: Build the windows images + id: build + run: | + docker build -t ${{ steps.meta.outputs.tags }} --build-arg WINDOWS_VERSION=ltsc${{ matrix.windows-base-version }} -f ./dockerfiles/Dockerfile.windows . + + - name: Sanity check it runs + # We do this for a simple check of dependencies + run: | + docker run --rm -t ${{ steps.meta.outputs.tags }} --help + shell: bash + diff --git a/dockerfiles/Dockerfile.windows b/dockerfiles/Dockerfile.windows index b3235232fc4..eae4bda3075 100644 --- a/dockerfiles/Dockerfile.windows +++ b/dockerfiles/Dockerfile.windows @@ -40,6 +40,7 @@ RUN Start-Process /local/vc_redist.x64.exe -ArgumentList '/install', '/quiet', ' # Install Chocolatey and OpenSSL: https://github.com/StefanScherer/dockerfiles-windows/blob/main/openssl/Dockerfile ENV chocolateyUseWindowsCompression false +ENV chocolateyVersion '1.4.0' RUN iex ((new-object net.webclient).DownloadString('https://chocolatey.org/install.ps1')); ` choco feature disable --name showDownloadProgress ; ` choco install -y openssl; From 3333cbdc5f9d15c19c6e65f51f4b8d1fc3e10e86 Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Thu, 22 Jun 2023 23:00:33 -0600 Subject: [PATCH 021/315] upstream: new property to limit the amount of active TCP connections (#7586) By default, Fluent Bit tries to deliver data as faster as possible and create TCP connections on-demand and in keepalive mode for performance reasons. In high-scalable environments, the user might want to control how many connections are done in parallel by setting a limit. This patch implements a new configuration property called 'net.max_connections' that can be used in the output plugins sections, so Fluent Bit won't open more than net.max_connections if it has been set. If the limit is reached, the output plugins will issue a retry. Configuration example: [OUTPUT] name splunk match * net.max_worker_connections 10 Note that this feature works at upstream/plugin level, and the limit is applied for all the workers if they exists, e.g: if you have 50 workers and net.max_connections=10, only 10 connections will be allowed. --------- Signed-off-by: Eduardo Silva --- include/fluent-bit/flb_network.h | 3 +++ src/flb_upstream.c | 32 +++++++++++++++++++++++++++++--- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/include/fluent-bit/flb_network.h b/include/fluent-bit/flb_network.h index a2285db5b9a..eab457878c6 100644 --- a/include/fluent-bit/flb_network.h +++ b/include/fluent-bit/flb_network.h @@ -76,6 +76,9 @@ struct flb_net_setup { /* prioritize ipv4 results when trying to establish a connection*/ int dns_prefer_ipv4; + + /* maximum number of allowed active TCP connections */ + int max_worker_connections; }; /* Defines a host service and it properties */ diff --git a/src/flb_upstream.c b/src/flb_upstream.c index e9834a79840..03f9e805b4b 100644 --- a/src/flb_upstream.c +++ b/src/flb_upstream.c @@ -95,7 +95,13 @@ struct flb_config_map upstream_net[] = { FLB_CONFIG_MAP_INT, "net.keepalive_max_recycle", "2000", 0, FLB_TRUE, offsetof(struct flb_net_setup, keepalive_max_recycle), "Set maximum number of times a keepalive connection can be used " - "before it is retired." + "before it is retried." + }, + + { + FLB_CONFIG_MAP_INT, "net.max_worker_connections", "0", + 0, FLB_TRUE, offsetof(struct flb_net_setup, max_worker_connections), + "Set the maximum number of active TCP connections that can be used per worker thread." }, /* EOF */ @@ -606,6 +612,7 @@ int flb_upstream_conn_recycle(struct flb_connection *conn, int val) struct flb_connection *flb_upstream_conn_get(struct flb_upstream *u) { int err; + int total_connections = 0; struct mk_list *tmp; struct mk_list *head; struct flb_connection *conn; @@ -617,12 +624,31 @@ struct flb_connection *flb_upstream_conn_get(struct flb_upstream *u) "net.connect_timeout = %i seconds\n" "net.source_address = %s\n" "net.keepalive = %s\n" - "net.keepalive_idle_timeout = %i seconds", + "net.keepalive_idle_timeout = %i seconds\n" + "net.max_worker_connections = %i", u->tcp_host, u->tcp_port, u->base.net.connect_timeout, u->base.net.source_address ? u->base.net.source_address: "any", u->base.net.keepalive ? "enabled": "disabled", - u->base.net.keepalive_idle_timeout); + u->base.net.keepalive_idle_timeout, + u->base.net.max_worker_connections); + + + /* If the upstream is limited by max connections, check current state */ + if (u->base.net.max_worker_connections > 0) { + flb_stream_acquire_lock(&u->base, FLB_TRUE); + + total_connections = mk_list_size(&uq->av_queue); + total_connections += mk_list_size(&uq->busy_queue); + + flb_stream_release_lock(&u->base); + + if (total_connections >= u->base.net.max_worker_connections) { + flb_debug("[upstream] max worker connections=%i reached to: %s:%i, cannot connect", + u->base.net.max_worker_connections, u->tcp_host, u->tcp_port); + return NULL; + } + } conn = NULL; From cd10b96fc18595f20c8849f33b3e60ca8777b307 Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Thu, 22 Jun 2023 23:01:31 -0600 Subject: [PATCH 022/315] build: bump to v2.1.6 Signed-off-by: Eduardo Silva --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f36ad1aead0..eca4134e2f1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,7 @@ set(CMAKE_POLICY_DEFAULT_CMP0069 NEW) # Fluent Bit Version set(FLB_VERSION_MAJOR 2) set(FLB_VERSION_MINOR 1) -set(FLB_VERSION_PATCH 5) +set(FLB_VERSION_PATCH 6) set(FLB_VERSION_STR "${FLB_VERSION_MAJOR}.${FLB_VERSION_MINOR}.${FLB_VERSION_PATCH}") set(CMAKE_POSITION_INDEPENDENT_CODE ON) From 37003d3b2dfeb203786c0c248002f7e676d32c29 Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Thu, 22 Jun 2023 23:01:59 -0600 Subject: [PATCH 023/315] snap: bump to v2.1.6 Signed-off-by: Eduardo Silva --- snap/snapcraft.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 44efb080e28..581f15a3c33 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -1,6 +1,6 @@ name: fluent-bit base: core18 -version: '2.1.5' +version: '2.1.6' summary: High performance logs and stream processor description: | Fluent Bit is a high performance log processor and stream processor for Linux. From c2ec98b6843b07a48a96935351b7296db472df9a Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Thu, 22 Jun 2023 23:02:50 -0600 Subject: [PATCH 024/315] bitbake: bump to v2.1.6 Signed-off-by: Eduardo Silva --- fluent-bit-2.1.5.bb => fluent-bit-2.1.6.bb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename fluent-bit-2.1.5.bb => fluent-bit-2.1.6.bb (99%) diff --git a/fluent-bit-2.1.5.bb b/fluent-bit-2.1.6.bb similarity index 99% rename from fluent-bit-2.1.5.bb rename to fluent-bit-2.1.6.bb index ce297a5f4fa..ce387cef4a3 100644 --- a/fluent-bit-2.1.5.bb +++ b/fluent-bit-2.1.6.bb @@ -16,7 +16,7 @@ LIC_FILES_CHKSUM = "file://LICENSE;md5=2ee41112a44fe7014dce33e26468ba93" SECTION = "net" PR = "r0" -PV = "2.1.5" +PV = "2.1.6" SRCREV = "v${PV}" SRC_URI = "git://github.com/fluent/fluent-bit.git;nobranch=1" From 3c04f7948406e33005275c1030786009e526ca78 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 23 Jun 2023 10:02:50 +0100 Subject: [PATCH 025/315] release: update to 2.1.6 (#7600) Signed-off-by: GitHub Co-authored-by: patrick-stephens --- CMakeLists.txt | 2 +- dockerfiles/Dockerfile | 2 +- fluent-bit-2.1.6.bb => fluent-bit-2.1.7.bb | 2 +- snap/snapcraft.yaml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) rename fluent-bit-2.1.6.bb => fluent-bit-2.1.7.bb (99%) diff --git a/CMakeLists.txt b/CMakeLists.txt index eca4134e2f1..6fd4c5abb97 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,7 @@ set(CMAKE_POLICY_DEFAULT_CMP0069 NEW) # Fluent Bit Version set(FLB_VERSION_MAJOR 2) set(FLB_VERSION_MINOR 1) -set(FLB_VERSION_PATCH 6) +set(FLB_VERSION_PATCH 7) set(FLB_VERSION_STR "${FLB_VERSION_MAJOR}.${FLB_VERSION_MINOR}.${FLB_VERSION_PATCH}") set(CMAKE_POSITION_INDEPENDENT_CODE ON) diff --git a/dockerfiles/Dockerfile b/dockerfiles/Dockerfile index 38482459d38..63bbbbfc2cf 100644 --- a/dockerfiles/Dockerfile +++ b/dockerfiles/Dockerfile @@ -11,7 +11,7 @@ # docker buildx build --platform "linux/amd64,linux/arm64,linux/arm/v7" -f ./dockerfiles/Dockerfile.multiarch --build-arg FLB_TARBALL=https://github.com/fluent/fluent-bit/archive/v1.8.11.tar.gz ./dockerfiles/ # Set this to the current release version: it gets done so as part of the release. -ARG RELEASE_VERSION=2.1.5 +ARG RELEASE_VERSION=2.1.7 # For multi-arch builds - assumption is running on an AMD64 host FROM multiarch/qemu-user-static:x86_64-arm as qemu-arm32 diff --git a/fluent-bit-2.1.6.bb b/fluent-bit-2.1.7.bb similarity index 99% rename from fluent-bit-2.1.6.bb rename to fluent-bit-2.1.7.bb index ce387cef4a3..e24e552e96c 100644 --- a/fluent-bit-2.1.6.bb +++ b/fluent-bit-2.1.7.bb @@ -16,7 +16,7 @@ LIC_FILES_CHKSUM = "file://LICENSE;md5=2ee41112a44fe7014dce33e26468ba93" SECTION = "net" PR = "r0" -PV = "2.1.6" +PV = "2.1.7" SRCREV = "v${PV}" SRC_URI = "git://github.com/fluent/fluent-bit.git;nobranch=1" diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 581f15a3c33..bce1ce569cb 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -1,6 +1,6 @@ name: fluent-bit base: core18 -version: '2.1.6' +version: '2.1.7' summary: High performance logs and stream processor description: | Fluent Bit is a high performance log processor and stream processor for Linux. From fa6b0e530436b347c5818f2bb271cf3d0d31f0fd Mon Sep 17 00:00:00 2001 From: Pat Date: Fri, 23 Jun 2023 15:39:34 +0100 Subject: [PATCH 026/315] workflows: fix the version used for updating PRs (#7603) Signed-off-by: Patrick Stephens --- .github/workflows/staging-release.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/staging-release.yaml b/.github/workflows/staging-release.yaml index 78d2608caf4..6cf33a68518 100644 --- a/.github/workflows/staging-release.yaml +++ b/.github/workflows/staging-release.yaml @@ -869,13 +869,13 @@ jobs: id: cpr uses: peter-evans/create-pull-request@v5 with: - commit-message: 'release: update to ${{ inputs.version }}' + commit-message: 'release: update to ${{ steps.semvers.outputs.patch }}' signoff: true delete-branch: true - title: 'release: update to ${{ inputs.version }}' + title: 'release: update to ${{ steps.semvers.outputs.patch }}' labels: ci,automerge body: | - Update release ${{ inputs.version }} version. + Update next release to ${{ steps.semvers.outputs.patch }} version. - Created by ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} - Auto-generated by create-pull-request: https://github.com/peter-evans/create-pull-request draft: false From 9656412939851126a5e47e921b5b44341ac4efdc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 26 Jun 2023 10:24:00 +0100 Subject: [PATCH 027/315] workflows: bump ossf/scorecard-action from 2.1.3 to 2.2.0 (#7610) Bumps [ossf/scorecard-action](https://github.com/ossf/scorecard-action) from 2.1.3 to 2.2.0. - [Release notes](https://github.com/ossf/scorecard-action/releases) - [Changelog](https://github.com/ossf/scorecard-action/blob/main/RELEASE.md) - [Commits](https://github.com/ossf/scorecard-action/compare/80e868c13c90f172d68d1f4501dee99e2479f7af...08b4669551908b1024bb425080c797723083c031) --- updated-dependencies: - dependency-name: ossf/scorecard-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/cron-scorecards-analysis.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cron-scorecards-analysis.yaml b/.github/workflows/cron-scorecards-analysis.yaml index c7eb440d0f2..2a488881b32 100644 --- a/.github/workflows/cron-scorecards-analysis.yaml +++ b/.github/workflows/cron-scorecards-analysis.yaml @@ -30,7 +30,7 @@ jobs: persist-credentials: false - name: "Run analysis" - uses: ossf/scorecard-action@80e868c13c90f172d68d1f4501dee99e2479f7af + uses: ossf/scorecard-action@08b4669551908b1024bb425080c797723083c031 with: results_file: scorecard-results.sarif results_format: sarif From 3c2668d3e7124c682cf14b485101efdbe94fb83f Mon Sep 17 00:00:00 2001 From: Pat Date: Wed, 28 Jun 2023 14:00:19 +0100 Subject: [PATCH 028/315] core: fix up boolean conversion logic (#7618) * core: fix up boolean conversion logic Signed-off-by: Patrick Stephens --- plugins/out_cloudwatch_logs/cloudwatch_logs.c | 5 ++-- src/flb_input.c | 23 +++++-------------- src/flb_output.c | 23 +++++-------------- 3 files changed, 14 insertions(+), 37 deletions(-) diff --git a/plugins/out_cloudwatch_logs/cloudwatch_logs.c b/plugins/out_cloudwatch_logs/cloudwatch_logs.c index e197fe8841b..f6aef224088 100644 --- a/plugins/out_cloudwatch_logs/cloudwatch_logs.c +++ b/plugins/out_cloudwatch_logs/cloudwatch_logs.c @@ -185,9 +185,8 @@ static int cb_cloudwatch_init(struct flb_output_instance *ins, ctx->create_group = FLB_FALSE; tmp = flb_output_get_property("auto_create_group", ins); - /* native plugins use On/Off as bool, the old Go plugin used true/false */ - if (tmp && (strcasecmp(tmp, "On") == 0 || strcasecmp(tmp, "true") == 0)) { - ctx->create_group = FLB_TRUE; + if (tmp) { + ctx->create_group = flb_utils_bool(tmp); } ctx->retry_requests = FLB_TRUE; diff --git a/src/flb_input.c b/src/flb_input.c index 0f350896e9e..c9b3d65e6c8 100644 --- a/src/flb_input.c +++ b/src/flb_input.c @@ -541,27 +541,16 @@ int flb_input_set_property(struct flb_input_instance *ins, #ifdef FLB_HAVE_TLS else if (prop_key_check("tls", k, len) == 0 && tmp) { - if (strcasecmp(tmp, "true") == 0 || strcasecmp(tmp, "on") == 0) { - if ((ins->flags & FLB_IO_TLS) == 0) { - flb_error("[config] %s don't support TLS", ins->name); - flb_sds_destroy(tmp); - return -1; - } - - ins->use_tls = FLB_TRUE; - } - else { - ins->use_tls = FLB_FALSE; + ins->use_tls = flb_utils_bool(tmp); + if (ins->use_tls == FLB_TRUE && ((ins->flags & FLB_IO_TLS) == 0)) { + flb_error("[config] %s does not support TLS", ins->name); + flb_sds_destroy(tmp); + return -1; } flb_sds_destroy(tmp); } else if (prop_key_check("tls.verify", k, len) == 0 && tmp) { - if (strcasecmp(tmp, "true") == 0 || strcasecmp(tmp, "on") == 0) { - ins->tls_verify = FLB_TRUE; - } - else { - ins->tls_verify = FLB_FALSE; - } + ins->tls_verify = flb_utils_bool(tmp); flb_sds_destroy(tmp); } else if (prop_key_check("tls.debug", k, len) == 0 && tmp) { diff --git a/src/flb_output.c b/src/flb_output.c index 5a668aa971a..868a7b9b20d 100644 --- a/src/flb_output.c +++ b/src/flb_output.c @@ -860,27 +860,16 @@ int flb_output_set_property(struct flb_output_instance *ins, #endif #ifdef FLB_HAVE_TLS else if (prop_key_check("tls", k, len) == 0 && tmp) { - if (strcasecmp(tmp, "true") == 0 || strcasecmp(tmp, "on") == 0) { - if ((ins->flags & FLB_IO_TLS) == 0) { - flb_error("[config] %s don't support TLS", ins->name); - flb_sds_destroy(tmp); - return -1; - } - - ins->use_tls = FLB_TRUE; - } - else { - ins->use_tls = FLB_FALSE; + ins->use_tls = flb_utils_bool(tmp); + if (ins->use_tls == FLB_TRUE && ((ins->flags & FLB_IO_TLS) == 0)) { + flb_error("[config] %s does not support TLS", ins->name); + flb_sds_destroy(tmp); + return -1; } flb_sds_destroy(tmp); } else if (prop_key_check("tls.verify", k, len) == 0 && tmp) { - if (strcasecmp(tmp, "true") == 0 || strcasecmp(tmp, "on") == 0) { - ins->tls_verify = FLB_TRUE; - } - else { - ins->tls_verify = FLB_FALSE; - } + ins->tls_verify = flb_utils_bool(tmp); flb_sds_destroy(tmp); } else if (prop_key_check("tls.debug", k, len) == 0 && tmp) { From 2a76f57c93f9959df61637f0d28e80544b663c98 Mon Sep 17 00:00:00 2001 From: Pat Date: Fri, 30 Jun 2023 15:12:35 +0100 Subject: [PATCH 029/315] workflows: fix up OpenSSF Scorecard workflow (#7631) * workflows: fix up OpenSSF Scorecard workflow Signed-off-by: Patrick Stephens * workflows: add optional PAT Signed-off-by: Patrick Stephens --------- Signed-off-by: Patrick Stephens --- .github/workflows/cron-scorecards-analysis.yaml | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/.github/workflows/cron-scorecards-analysis.yaml b/.github/workflows/cron-scorecards-analysis.yaml index 2a488881b32..7f274b8efe0 100644 --- a/.github/workflows/cron-scorecards-analysis.yaml +++ b/.github/workflows/cron-scorecards-analysis.yaml @@ -20,9 +20,8 @@ jobs: permissions: # Needed to upload the results to code-scanning dashboard. security-events: write - actions: read - contents: read - + # Needed for GitHub OIDC token if publish_results is true + id-token: write steps: - name: "Checkout code" uses: actions/checkout@v3 @@ -34,9 +33,11 @@ jobs: with: results_file: scorecard-results.sarif results_format: sarif - # Read-only PAT token. To create it, - # follow the steps in https://github.com/ossf/scorecard-action#pat-token-creation. - repo_token: ${{ secrets.SCORECARD_READ_TOKEN || github.token }} + # (Optional) fine-grained personal access token. Uncomment the `repo_token` line below if: + # - you want to enable the Branch-Protection check on a *public* repository, or + # To create the PAT, follow the steps in https://github.com/ossf/scorecard-action#authentication-with-fine-grained-pat-optional. + repo_token: ${{ secrets.SCORECARD_TOKEN }} + # # Publish the results for public repositories to enable scorecard badges. For more details, see # https://github.com/ossf/scorecard-action#publishing-results. # For private repositories, `publish_results` will automatically be set to `false`, regardless From 3159f1d0728a59b16b32913c30fb3c98710d8750 Mon Sep 17 00:00:00 2001 From: Takahiro Yamashita Date: Sun, 18 Jun 2023 12:16:31 +0900 Subject: [PATCH 030/315] log_event_decoder: use flb_free Signed-off-by: Takahiro Yamashita --- src/flb_log_event_decoder.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/flb_log_event_decoder.c b/src/flb_log_event_decoder.c index aa8b571c237..155bd29d952 100644 --- a/src/flb_log_event_decoder.c +++ b/src/flb_log_event_decoder.c @@ -144,7 +144,7 @@ void flb_log_event_decoder_destroy(struct flb_log_event_decoder *context) context->initialized = FLB_FALSE; if (dynamically_allocated) { - free(context); + flb_free(context); } } } From bf97f327d5a28e41370d3c745fe928ebaabcb58e Mon Sep 17 00:00:00 2001 From: Takahiro Yamashita Date: Sun, 11 Jun 2023 09:20:32 +0900 Subject: [PATCH 031/315] log_event_decoder: add a function to get decoding result At the end of buffer, msgpack_unpack_next returns MSGPACK_UNPACK_CONTINUE. If incoming data is incomplete, msgpack_unpack_next also returns MSGPACK_UNPACK_CONTINUE. So we need to check if decoder reads the end of buffer after decoding. The new function is for it. Signed-off-by: Takahiro Yamashita --- include/fluent-bit/flb_log_event_decoder.h | 5 ++- src/flb_log_event_decoder.c | 39 ++++++++++++++++------ 2 files changed, 33 insertions(+), 11 deletions(-) diff --git a/include/fluent-bit/flb_log_event_decoder.h b/include/fluent-bit/flb_log_event_decoder.h index 8a53eeeb63d..1f18fc97364 100644 --- a/include/fluent-bit/flb_log_event_decoder.h +++ b/include/fluent-bit/flb_log_event_decoder.h @@ -27,6 +27,7 @@ #include + #define FLB_EVENT_DECODER_SUCCESS 0 #define FLB_EVENT_DECODER_ERROR_INITIALIZATION_FAILURE -1 #define FLB_EVENT_DECODER_ERROR_INVALID_CONTEXT -2 @@ -40,6 +41,7 @@ #define FLB_EVENT_DECODER_ERROR_WRONG_BODY_TYPE -10 #define FLB_EVENT_DECODER_ERROR_DESERIALIZATION_FAILURE -11 #define FLB_EVENT_DECODER_ERROR_INSUFFICIENT_DATA -12 +#define FLB_EVENT_DECODER_ERROR_NO_INCOMING_DATA -13 #define FLB_LOG_EVENT_EXPECTED_ROOT_ELEMENT_COUNT 2 #define FLB_LOG_EVENT_EXPECTED_HEADER_ELEMENT_COUNT 2 @@ -56,6 +58,7 @@ struct flb_log_event_decoder { const char *buffer; size_t offset; size_t length; + int decode_result; }; void flb_log_event_decoder_reset(struct flb_log_event_decoder *context, @@ -77,7 +80,7 @@ int flb_log_event_decoder_decode_timestamp(msgpack_object *input, int flb_event_decoder_decode_object(struct flb_log_event_decoder *context, struct flb_log_event *event, msgpack_object *input); - +int flb_log_event_decoder_get_decode_result(struct flb_log_event_decoder *context); int flb_log_event_decoder_next(struct flb_log_event_decoder *context, struct flb_log_event *record); diff --git a/src/flb_log_event_decoder.c b/src/flb_log_event_decoder.c index 155bd29d952..dd118d4b710 100644 --- a/src/flb_log_event_decoder.c +++ b/src/flb_log_event_decoder.c @@ -70,6 +70,7 @@ void flb_log_event_decoder_reset(struct flb_log_event_decoder *context, context->offset = 0; context->buffer = input_buffer; context->length = input_length; + context->decode_result = FLB_EVENT_DECODER_ERROR_NO_INCOMING_DATA; msgpack_unpacked_destroy(&context->unpacked_event); msgpack_unpacked_init(&context->unpacked_event); @@ -261,21 +262,36 @@ int flb_event_decoder_decode_object(struct flb_log_event_decoder *context, return FLB_EVENT_DECODER_SUCCESS; } +int flb_log_event_decoder_get_decode_result(struct flb_log_event_decoder *context) +{ + if (context->decode_result == FLB_EVENT_DECODER_ERROR_INSUFFICIENT_DATA && + context->offset == context->length) { + context->decode_result = FLB_EVENT_DECODER_SUCCESS; + } + + return context->decode_result; +} + int flb_log_event_decoder_next(struct flb_log_event_decoder *context, struct flb_log_event *event) { size_t previous_offset; int result; - context->record_base = NULL; - context->record_length = 0; - if (context == NULL) { return FLB_EVENT_DECODER_ERROR_INVALID_CONTEXT; } + if (context->length == 0) { + context->decode_result = FLB_EVENT_DECODER_ERROR_NO_INCOMING_DATA; + goto flb_log_event_decoder_next_end; + } + + context->record_base = NULL; + context->record_length = 0; if (event == NULL) { - return FLB_EVENT_DECODER_ERROR_INVALID_ARGUMENT; + context->decode_result = FLB_EVENT_DECODER_ERROR_INVALID_ARGUMENT; + goto flb_log_event_decoder_next_end; } memset(event, 0, sizeof(struct flb_log_event)); @@ -288,17 +304,20 @@ int flb_log_event_decoder_next(struct flb_log_event_decoder *context, &context->offset); if (result == MSGPACK_UNPACK_CONTINUE) { - return FLB_EVENT_DECODER_ERROR_INSUFFICIENT_DATA; + context->decode_result = FLB_EVENT_DECODER_ERROR_INSUFFICIENT_DATA; + goto flb_log_event_decoder_next_end; } else if (result != MSGPACK_UNPACK_SUCCESS) { - return FLB_EVENT_DECODER_ERROR_DESERIALIZATION_FAILURE; + context->decode_result = FLB_EVENT_DECODER_ERROR_DESERIALIZATION_FAILURE; + goto flb_log_event_decoder_next_end; } context->previous_offset = previous_offset; - - return flb_event_decoder_decode_object(context, - event, - &context->unpacked_event.data); + context->decode_result = flb_event_decoder_decode_object(context, + event, + &context->unpacked_event.data); + flb_log_event_decoder_next_end: + return context->decode_result; } const char *flb_log_event_decoder_get_error_description(int error_code) From e02415647b093393b5458939668670821d868750 Mon Sep 17 00:00:00 2001 From: Takahiro Yamashita Date: Sun, 11 Jun 2023 09:28:41 +0900 Subject: [PATCH 032/315] out_stdout: modify to check decoding result Signed-off-by: Takahiro Yamashita --- plugins/out_stdout/stdout.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/plugins/out_stdout/stdout.c b/plugins/out_stdout/stdout.c index aa797426058..af5538a875f 100644 --- a/plugins/out_stdout/stdout.c +++ b/plugins/out_stdout/stdout.c @@ -222,9 +222,9 @@ static void cb_stdout_flush(struct flb_event_chunk *event_chunk, FLB_OUTPUT_RETURN(FLB_RETRY); } - while ((result = flb_log_event_decoder_next( - &log_decoder, - &log_event)) == FLB_EVENT_DECODER_SUCCESS) { + while ((flb_log_event_decoder_next( + &log_decoder, + &log_event)) == FLB_EVENT_DECODER_SUCCESS) { printf("[%zd] %s: [[", cnt++, event_chunk->tag); printf("%"PRIu32".%09lu, ", @@ -239,10 +239,7 @@ static void cb_stdout_flush(struct flb_event_chunk *event_chunk, printf("]\n"); } - - if (result != FLB_EVENT_DECODER_ERROR_INSUFFICIENT_DATA) { - flb_plg_error(ctx->ins, "decoder error : %d", result); - } + result = flb_log_event_decoder_get_decode_result(&log_decoder); flb_log_event_decoder_destroy(&log_decoder); } @@ -250,6 +247,7 @@ static void cb_stdout_flush(struct flb_event_chunk *event_chunk, fflush(stdout); if (result != FLB_EVENT_DECODER_SUCCESS) { + flb_plg_error(ctx->ins, "decoder error : %d", result); FLB_OUTPUT_RETURN(FLB_ERROR); } From 8b31ec7d3ff63bee973d5659830539817509ed65 Mon Sep 17 00:00:00 2001 From: Takahiro Yamashita Date: Mon, 12 Jun 2023 21:06:30 +0900 Subject: [PATCH 033/315] log_event_decoder: rename decode_result -> last_result Signed-off-by: Takahiro Yamashita --- include/fluent-bit/flb_log_event_decoder.h | 4 +-- src/flb_log_event_decoder.c | 31 +++++++++++----------- 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/include/fluent-bit/flb_log_event_decoder.h b/include/fluent-bit/flb_log_event_decoder.h index 1f18fc97364..c9f306b2fc0 100644 --- a/include/fluent-bit/flb_log_event_decoder.h +++ b/include/fluent-bit/flb_log_event_decoder.h @@ -58,7 +58,7 @@ struct flb_log_event_decoder { const char *buffer; size_t offset; size_t length; - int decode_result; + int last_result; }; void flb_log_event_decoder_reset(struct flb_log_event_decoder *context, @@ -80,7 +80,7 @@ int flb_log_event_decoder_decode_timestamp(msgpack_object *input, int flb_event_decoder_decode_object(struct flb_log_event_decoder *context, struct flb_log_event *event, msgpack_object *input); -int flb_log_event_decoder_get_decode_result(struct flb_log_event_decoder *context); +int flb_log_event_decoder_get_last_result(struct flb_log_event_decoder *context); int flb_log_event_decoder_next(struct flb_log_event_decoder *context, struct flb_log_event *record); diff --git a/src/flb_log_event_decoder.c b/src/flb_log_event_decoder.c index dd118d4b710..39ca9d55ab3 100644 --- a/src/flb_log_event_decoder.c +++ b/src/flb_log_event_decoder.c @@ -70,7 +70,7 @@ void flb_log_event_decoder_reset(struct flb_log_event_decoder *context, context->offset = 0; context->buffer = input_buffer; context->length = input_length; - context->decode_result = FLB_EVENT_DECODER_ERROR_NO_INCOMING_DATA; + context->last_result = FLB_EVENT_DECODER_ERROR_NO_INCOMING_DATA; msgpack_unpacked_destroy(&context->unpacked_event); msgpack_unpacked_init(&context->unpacked_event); @@ -262,14 +262,14 @@ int flb_event_decoder_decode_object(struct flb_log_event_decoder *context, return FLB_EVENT_DECODER_SUCCESS; } -int flb_log_event_decoder_get_decode_result(struct flb_log_event_decoder *context) +int flb_log_event_decoder_get_last_result(struct flb_log_event_decoder *context) { - if (context->decode_result == FLB_EVENT_DECODER_ERROR_INSUFFICIENT_DATA && + if (context->last_result == FLB_EVENT_DECODER_ERROR_INSUFFICIENT_DATA && context->offset == context->length) { - context->decode_result = FLB_EVENT_DECODER_SUCCESS; + context->last_result = FLB_EVENT_DECODER_SUCCESS; } - return context->decode_result; + return context->last_result; } int flb_log_event_decoder_next(struct flb_log_event_decoder *context, @@ -282,16 +282,16 @@ int flb_log_event_decoder_next(struct flb_log_event_decoder *context, return FLB_EVENT_DECODER_ERROR_INVALID_CONTEXT; } if (context->length == 0) { - context->decode_result = FLB_EVENT_DECODER_ERROR_NO_INCOMING_DATA; - goto flb_log_event_decoder_next_end; + context->last_result = FLB_EVENT_DECODER_ERROR_INSUFFICIENT_DATA; + return context->last_result; } context->record_base = NULL; context->record_length = 0; if (event == NULL) { - context->decode_result = FLB_EVENT_DECODER_ERROR_INVALID_ARGUMENT; - goto flb_log_event_decoder_next_end; + context->last_result = FLB_EVENT_DECODER_ERROR_INVALID_ARGUMENT; + return context->last_result; } memset(event, 0, sizeof(struct flb_log_event)); @@ -304,20 +304,19 @@ int flb_log_event_decoder_next(struct flb_log_event_decoder *context, &context->offset); if (result == MSGPACK_UNPACK_CONTINUE) { - context->decode_result = FLB_EVENT_DECODER_ERROR_INSUFFICIENT_DATA; - goto flb_log_event_decoder_next_end; + context->last_result = FLB_EVENT_DECODER_ERROR_INSUFFICIENT_DATA; + return context->last_result; } else if (result != MSGPACK_UNPACK_SUCCESS) { - context->decode_result = FLB_EVENT_DECODER_ERROR_DESERIALIZATION_FAILURE; - goto flb_log_event_decoder_next_end; + context->last_result = FLB_EVENT_DECODER_ERROR_DESERIALIZATION_FAILURE; + return context->last_result; } context->previous_offset = previous_offset; - context->decode_result = flb_event_decoder_decode_object(context, + context->last_result = flb_event_decoder_decode_object(context, event, &context->unpacked_event.data); - flb_log_event_decoder_next_end: - return context->decode_result; + return context->last_result; } const char *flb_log_event_decoder_get_error_description(int error_code) From 03643cd30bb0c4349eeda2c62df43b0ff84c5982 Mon Sep 17 00:00:00 2001 From: Takahiro Yamashita Date: Mon, 12 Jun 2023 21:06:56 +0900 Subject: [PATCH 034/315] out_stdout: rename decode_result -> last_result Signed-off-by: Takahiro Yamashita --- plugins/out_stdout/stdout.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/plugins/out_stdout/stdout.c b/plugins/out_stdout/stdout.c index af5538a875f..2d6bff59856 100644 --- a/plugins/out_stdout/stdout.c +++ b/plugins/out_stdout/stdout.c @@ -222,9 +222,8 @@ static void cb_stdout_flush(struct flb_event_chunk *event_chunk, FLB_OUTPUT_RETURN(FLB_RETRY); } - while ((flb_log_event_decoder_next( - &log_decoder, - &log_event)) == FLB_EVENT_DECODER_SUCCESS) { + while (flb_log_event_decoder_next(&log_decoder, + &log_event) == FLB_EVENT_DECODER_SUCCESS) { printf("[%zd] %s: [[", cnt++, event_chunk->tag); printf("%"PRIu32".%09lu, ", @@ -239,7 +238,7 @@ static void cb_stdout_flush(struct flb_event_chunk *event_chunk, printf("]\n"); } - result = flb_log_event_decoder_get_decode_result(&log_decoder); + result = flb_log_event_decoder_get_last_result(&log_decoder); flb_log_event_decoder_destroy(&log_decoder); } @@ -247,7 +246,7 @@ static void cb_stdout_flush(struct flb_event_chunk *event_chunk, fflush(stdout); if (result != FLB_EVENT_DECODER_SUCCESS) { - flb_plg_error(ctx->ins, "decoder error : %d", result); + flb_plg_error(ctx->ins, "Log event decoder error : %d", result); FLB_OUTPUT_RETURN(FLB_ERROR); } From 1e382fa6a185bd1b15f608cadf5f5f4ad89ba728 Mon Sep 17 00:00:00 2001 From: Takahiro Yamashita Date: Mon, 12 Jun 2023 22:08:46 +0900 Subject: [PATCH 035/315] log_event_decoder: set FLB_EVENT_DECODER_ERROR_INSUFFICIENT_DATA as a default Signed-off-by: Takahiro Yamashita --- include/fluent-bit/flb_log_event_decoder.h | 1 - src/flb_log_event_decoder.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/include/fluent-bit/flb_log_event_decoder.h b/include/fluent-bit/flb_log_event_decoder.h index c9f306b2fc0..c4acbd76f17 100644 --- a/include/fluent-bit/flb_log_event_decoder.h +++ b/include/fluent-bit/flb_log_event_decoder.h @@ -41,7 +41,6 @@ #define FLB_EVENT_DECODER_ERROR_WRONG_BODY_TYPE -10 #define FLB_EVENT_DECODER_ERROR_DESERIALIZATION_FAILURE -11 #define FLB_EVENT_DECODER_ERROR_INSUFFICIENT_DATA -12 -#define FLB_EVENT_DECODER_ERROR_NO_INCOMING_DATA -13 #define FLB_LOG_EVENT_EXPECTED_ROOT_ELEMENT_COUNT 2 #define FLB_LOG_EVENT_EXPECTED_HEADER_ELEMENT_COUNT 2 diff --git a/src/flb_log_event_decoder.c b/src/flb_log_event_decoder.c index 39ca9d55ab3..00a778e3d4a 100644 --- a/src/flb_log_event_decoder.c +++ b/src/flb_log_event_decoder.c @@ -70,7 +70,7 @@ void flb_log_event_decoder_reset(struct flb_log_event_decoder *context, context->offset = 0; context->buffer = input_buffer; context->length = input_length; - context->last_result = FLB_EVENT_DECODER_ERROR_NO_INCOMING_DATA; + context->last_result = FLB_EVENT_DECODER_ERROR_INSUFFICIENT_DATA; msgpack_unpacked_destroy(&context->unpacked_event); msgpack_unpacked_init(&context->unpacked_event); From d1218d6ab395c3d06bed33ad6147430650f68bea Mon Sep 17 00:00:00 2001 From: Takahiro Yamashita Date: Sat, 1 Jul 2023 09:25:34 +0900 Subject: [PATCH 036/315] log_event_decoder: fix wrong api name Signed-off-by: Takahiro Yamashita --- include/fluent-bit/flb_log_event_decoder.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/fluent-bit/flb_log_event_decoder.h b/include/fluent-bit/flb_log_event_decoder.h index c4acbd76f17..d8d0787b767 100644 --- a/include/fluent-bit/flb_log_event_decoder.h +++ b/include/fluent-bit/flb_log_event_decoder.h @@ -83,6 +83,6 @@ int flb_log_event_decoder_get_last_result(struct flb_log_event_decoder *context) int flb_log_event_decoder_next(struct flb_log_event_decoder *context, struct flb_log_event *record); -const char *flb_log_event_encoder_strerror(int error_code); +const char *flb_log_event_decoder_get_error_description(int error_code); #endif From cf15efebf625e0e463595e616953c7306ee1bd9a Mon Sep 17 00:00:00 2001 From: Takahiro Yamashita Date: Mon, 3 Jul 2023 09:26:25 +0900 Subject: [PATCH 037/315] tests: runtime: in_otel: add test code (#7489) Signed-off-by: Takahiro Yamashita --- tests/runtime/CMakeLists.txt | 1 + tests/runtime/in_opentelemetry.c | 376 +++++++++++++++++++++++++++++++ 2 files changed, 377 insertions(+) create mode 100644 tests/runtime/in_opentelemetry.c diff --git a/tests/runtime/CMakeLists.txt b/tests/runtime/CMakeLists.txt index 04b7ac1ef33..6e7c3e59c00 100644 --- a/tests/runtime/CMakeLists.txt +++ b/tests/runtime/CMakeLists.txt @@ -45,6 +45,7 @@ if(FLB_OUT_LIB) FLB_RT_TEST(FLB_IN_DUMMY "in_dummy.c") FLB_RT_TEST(FLB_IN_HTTP "in_http.c") FLB_RT_TEST(FLB_IN_ELASTICSEARCH "in_elasticsearch.c") + FLB_RT_TEST(FLB_IN_OPENTELEMETRY "in_opentelemetry.c") FLB_RT_TEST(FLB_IN_RANDOM "in_random.c") FLB_RT_TEST(FLB_IN_STATSD "in_statsd.c") FLB_RT_TEST(FLB_IN_SYSLOG "in_syslog.c") diff --git a/tests/runtime/in_opentelemetry.c b/tests/runtime/in_opentelemetry.c new file mode 100644 index 00000000000..6f721cbec19 --- /dev/null +++ b/tests/runtime/in_opentelemetry.c @@ -0,0 +1,376 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Fluent Bit + * ========== + * Copyright (C) 2019-2022 The Fluent Bit Authors + * Copyright (C) 2015-2018 Treasure Data Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "flb_tests_runtime.h" + +#define JSON_CONTENT_TYPE "application/json" + +#define PORT_OTEL 4318 +#define TEST_MSG_OTEL_LOGS "{\"resourceLogs\":[{\"resource\":{},\"scopeLogs\":[{\"scope\":{},\"logRecords\":[{\"timeUnixNano\":\"1660296023390371588\",\"body\":{\"stringValue\":\"{\\\"message\\\":\\\"test\\\"}\"}}]}]}]}" +#define TEST_CB_MSG_OTEL_LOGS "[1660296024.698112,{\"log\":\"{\\\"message\\\":\\\"test\\\"}\"}]" + +#define V1_ENDPOINT_LOGS "/v1/logs" + +struct http_client_ctx { + struct flb_upstream *u; + struct flb_connection *u_conn; + struct flb_config *config; + struct mk_event_loop *evl; +}; + +struct test_ctx { + flb_ctx_t *flb; /* Fluent Bit library context */ + int i_ffd; /* Input fd */ + int f_ffd; /* Filter fd (unused) */ + int o_ffd; /* Output fd */ + struct http_client_ctx *httpc; +}; + + +pthread_mutex_t result_mutex = PTHREAD_MUTEX_INITIALIZER; +int num_output = 0; +static int get_output_num() +{ + int ret; + pthread_mutex_lock(&result_mutex); + ret = num_output; + pthread_mutex_unlock(&result_mutex); + + return ret; +} + +static void set_output_num(int num) +{ + pthread_mutex_lock(&result_mutex); + num_output = num; + pthread_mutex_unlock(&result_mutex); +} + +static void clear_output_num() +{ + set_output_num(0); +} + +/* Callback to check expected results */ +static int cb_check_result_json(void *record, size_t size, void *data) +{ + char *p; + char *expected; + char *result; + int num = get_output_num(); + + set_output_num(num+1); + + expected = (char *) data; + result = (char *) record; + + p = strstr(result, expected); + TEST_CHECK(p != NULL); + + if (p==NULL) { + flb_error("Expected to find: '%s' in result '%s'", + expected, result); + } + /* + * If you want to debug your test + * + * printf("Expect: '%s' in result '%s'", expected, result); + */ + flb_free(record); + return 0; +} + +struct http_client_ctx* http_client_ctx_create() +{ + struct http_client_ctx *ret_ctx = NULL; + struct mk_event_loop *evl = NULL; + + ret_ctx = flb_calloc(1, sizeof(struct http_client_ctx)); + if (!TEST_CHECK(ret_ctx != NULL)) { + flb_errno(); + TEST_MSG("flb_calloc(http_client_ctx) failed"); + return NULL; + } + + evl = mk_event_loop_create(16); + if (!TEST_CHECK(evl != NULL)) { + TEST_MSG("mk_event_loop failed"); + flb_free(ret_ctx); + return NULL; + } + ret_ctx->evl = evl; + flb_engine_evl_init(); + flb_engine_evl_set(evl); + + ret_ctx->config = flb_config_init(); + if(!TEST_CHECK(ret_ctx->config != NULL)) { + TEST_MSG("flb_config_init failed"); + mk_event_loop_destroy(evl); + flb_free(ret_ctx); + return NULL; + } + + ret_ctx->u = flb_upstream_create(ret_ctx->config, "127.0.0.1", PORT_OTEL, 0, NULL); + if (!TEST_CHECK(ret_ctx->u != NULL)) { + TEST_MSG("flb_upstream_create failed"); + flb_config_exit(ret_ctx->config); + mk_event_loop_destroy(evl); + flb_free(ret_ctx); + return NULL; + } + + ret_ctx->u_conn = flb_upstream_conn_get(ret_ctx->u); + TEST_CHECK(ret_ctx->u_conn != NULL); + + ret_ctx->u_conn->upstream = ret_ctx->u; + + return ret_ctx; +} + +static struct test_ctx *test_ctx_create(struct flb_lib_out_cb *data) +{ + int i_ffd; + int o_ffd; + struct test_ctx *ctx = NULL; + + ctx = flb_calloc(1, sizeof(struct test_ctx)); + if (!TEST_CHECK(ctx != NULL)) { + TEST_MSG("flb_calloc failed"); + flb_errno(); + return NULL; + } + + /* Service config */ + ctx->flb = flb_create(); + flb_service_set(ctx->flb, + "Flush", "0.200000000", + "Grace", "1", + "Log_Level", "error", + NULL); + + /* Input */ + i_ffd = flb_input(ctx->flb, (char *) "opentelemetry", NULL); + TEST_CHECK(i_ffd >= 0); + ctx->i_ffd = i_ffd; + + /* Output */ + o_ffd = flb_output(ctx->flb, (char *) "lib", (void *) data); + ctx->o_ffd = o_ffd; + + return ctx; +} + +int http_client_ctx_destroy(struct http_client_ctx* ctx) +{ + if (!TEST_CHECK(ctx != NULL)) { + return -1; + } + if (ctx->u) { + flb_upstream_destroy(ctx->u); + } + if (ctx->config) { + flb_config_exit(ctx->config); + } + if (ctx->evl) { + mk_event_loop_destroy(ctx->evl); + } + + flb_free(ctx); + return 0; +} + +static void test_ctx_destroy(struct test_ctx *ctx) +{ + TEST_CHECK(ctx != NULL); + if (ctx->httpc) { + http_client_ctx_destroy(ctx->httpc); + } + + sleep(1); + flb_stop(ctx->flb); + flb_destroy(ctx->flb); + flb_free(ctx); +} + +void flb_test_otel_logs() +{ + struct flb_lib_out_cb cb_data; + struct test_ctx *ctx; + struct flb_http_client *c; + int ret; + int num; + size_t b_sent; + + char *buf = TEST_MSG_OTEL_LOGS; + + clear_output_num(); + + cb_data.cb = cb_check_result_json; + cb_data.data = TEST_CB_MSG_OTEL_LOGS; + + ctx = test_ctx_create(&cb_data); + if (!TEST_CHECK(ctx != NULL)) { + TEST_MSG("test_ctx_create failed"); + exit(EXIT_FAILURE); + } + + ret = flb_output_set(ctx->flb, ctx->o_ffd, + "match", "*", + "format", "json", + NULL); + TEST_CHECK(ret == 0); + + /* Start the engine */ + ret = flb_start(ctx->flb); + TEST_CHECK(ret == 0); + + ctx->httpc = http_client_ctx_create(); + TEST_CHECK(ctx->httpc != NULL); + + c = flb_http_client(ctx->httpc->u_conn, FLB_HTTP_POST, V1_ENDPOINT_LOGS, buf, strlen(buf), + "127.0.0.1", PORT_OTEL, NULL, 0); + ret = flb_http_add_header(c, FLB_HTTP_HEADER_CONTENT_TYPE, strlen(FLB_HTTP_HEADER_CONTENT_TYPE), + JSON_CONTENT_TYPE, strlen(JSON_CONTENT_TYPE)); + TEST_CHECK(ret == 0); + if (!TEST_CHECK(c != NULL)) { + TEST_MSG("http_client failed"); + exit(EXIT_FAILURE); + } + + ret = flb_http_do(c, &b_sent); + if (!TEST_CHECK(ret == 0)) { + TEST_MSG("ret error. ret=%d\n", ret); + } + else if (!TEST_CHECK(b_sent > 0)){ + TEST_MSG("b_sent size error. b_sent = %lu\n", b_sent); + } + else if (!TEST_CHECK(c->resp.status == 201)) { + TEST_MSG("http response code error. expect: 201, got: %d\n", c->resp.status); + } + + /* waiting to flush */ + flb_time_msleep(1500); + + num = get_output_num(); + if (!TEST_CHECK(num > 0)) { + TEST_MSG("no outputs"); + } + flb_http_client_destroy(c); + flb_upstream_conn_release(ctx->httpc->u_conn); + test_ctx_destroy(ctx); +} + +void flb_test_otel_successful_response_code(char *response_code) +{ + struct flb_lib_out_cb cb_data; + struct test_ctx *ctx; + struct flb_http_client *c; + int ret; + int num; + size_t b_sent; + + char *buf = TEST_MSG_OTEL_LOGS; + + clear_output_num(); + + cb_data.cb = cb_check_result_json; + cb_data.data = TEST_CB_MSG_OTEL_LOGS; + + ctx = test_ctx_create(&cb_data); + if (!TEST_CHECK(ctx != NULL)) { + TEST_MSG("test_ctx_create failed"); + exit(EXIT_FAILURE); + } + + ret = flb_input_set(ctx->flb, ctx->i_ffd, + "successful_response_code", response_code, + NULL); + TEST_CHECK(ret == 0); + + ret = flb_output_set(ctx->flb, ctx->o_ffd, + "match", "*", + "format", "json", + NULL); + TEST_CHECK(ret == 0); + + /* Start the engine */ + ret = flb_start(ctx->flb); + TEST_CHECK(ret == 0); + + ctx->httpc = http_client_ctx_create(); + TEST_CHECK(ctx->httpc != NULL); + + c = flb_http_client(ctx->httpc->u_conn, FLB_HTTP_POST, V1_ENDPOINT_LOGS, buf, strlen(buf), + "127.0.0.1", PORT_OTEL, NULL, 0); + ret = flb_http_add_header(c, FLB_HTTP_HEADER_CONTENT_TYPE, strlen(FLB_HTTP_HEADER_CONTENT_TYPE), + JSON_CONTENT_TYPE, strlen(JSON_CONTENT_TYPE)); + TEST_CHECK(ret == 0); + if (!TEST_CHECK(c != NULL)) { + TEST_MSG("http_client failed"); + exit(EXIT_FAILURE); + } + + ret = flb_http_do(c, &b_sent); + if (!TEST_CHECK(ret == 0)) { + TEST_MSG("ret error. ret=%d\n", ret); + } + else if (!TEST_CHECK(b_sent > 0)){ + TEST_MSG("b_sent size error. b_sent = %lu\n", b_sent); + } + else if (!TEST_CHECK(c->resp.status == atoi(response_code))) { + TEST_MSG("http response code error. expect: %d, got: %d\n", atoi(response_code), c->resp.status); + } + + /* waiting to flush */ + flb_time_msleep(1500); + + num = get_output_num(); + if (!TEST_CHECK(num > 0)) { + TEST_MSG("no outputs"); + } + flb_http_client_destroy(c); + flb_upstream_conn_release(ctx->httpc->u_conn); + test_ctx_destroy(ctx); +} + +void flb_test_otel_successful_response_code_200() +{ + flb_test_otel_successful_response_code("200"); +} + +void flb_test_otel_successful_response_code_204() +{ + flb_test_otel_successful_response_code("204"); +} + +TEST_LIST = { + {"otel_logs", flb_test_otel_logs}, + {"successful_response_code_200", flb_test_otel_successful_response_code_200}, + {"successful_response_code_204", flb_test_otel_successful_response_code_204}, + {NULL, NULL} +}; + From ec565bb3bf9ec3a4a79def4c980a430bf5a2c167 Mon Sep 17 00:00:00 2001 From: Takahiro Yamashita Date: Mon, 3 Jul 2023 09:27:54 +0900 Subject: [PATCH 038/315] out_gelf: fix releasing function handling (#7640) Signed-off-by: Takahiro Yamashita --- plugins/out_gelf/gelf.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/plugins/out_gelf/gelf.c b/plugins/out_gelf/gelf.c index 556f40700c5..6d728464173 100644 --- a/plugins/out_gelf/gelf.c +++ b/plugins/out_gelf/gelf.c @@ -237,7 +237,6 @@ static void cb_gelf_flush(struct flb_event_chunk *event_chunk, int ret; flb_sds_t s; flb_sds_t tmp; - msgpack_unpacked result; size_t off = 0; size_t prev_off = 0; size_t size = 0; @@ -271,8 +270,6 @@ static void cb_gelf_flush(struct flb_event_chunk *event_chunk, FLB_OUTPUT_RETURN(FLB_RETRY); } - msgpack_unpacked_init(&result); - while ((ret = flb_log_event_decoder_next( &log_decoder, &log_event)) == FLB_EVENT_DECODER_SUCCESS) { @@ -285,7 +282,7 @@ static void cb_gelf_flush(struct flb_event_chunk *event_chunk, size = (size * 1.4); s = flb_sds_create_size(size); if (s == NULL) { - msgpack_unpacked_destroy(&result); + flb_log_event_decoder_destroy(&log_decoder); FLB_OUTPUT_RETURN(FLB_ERROR); } @@ -333,7 +330,7 @@ static void cb_gelf_flush(struct flb_event_chunk *event_chunk, flb_sds_destroy(s); } - msgpack_unpacked_destroy(&result); + flb_log_event_decoder_destroy(&log_decoder); if (ctx->mode != FLB_GELF_UDP) { flb_upstream_conn_release(u_conn); From f0e2fa4e01697826fa256e752422639b53e83cc4 Mon Sep 17 00:00:00 2001 From: Takahiro Yamashita Date: Mon, 3 Jul 2023 09:28:18 +0900 Subject: [PATCH 039/315] out_syslog: check error after flb_log_event_decoder_next (#7639) Signed-off-by: Takahiro Yamashita --- plugins/out_syslog/syslog.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/out_syslog/syslog.c b/plugins/out_syslog/syslog.c index 83484ff98ad..a333513543f 100644 --- a/plugins/out_syslog/syslog.c +++ b/plugins/out_syslog/syslog.c @@ -991,9 +991,9 @@ static int cb_syslog_format_test(struct flb_config *config, return -1; } - if ((ret = flb_log_event_decoder_next( - &log_decoder, - &log_event)) != FLB_EVENT_DECODER_SUCCESS) { + flb_log_event_decoder_next(&log_decoder, &log_event); + ret = flb_log_event_decoder_get_last_result(&log_decoder); + if (ret != FLB_EVENT_DECODER_SUCCESS) { flb_error("msgpack_unpack_next failed"); flb_log_event_decoder_destroy(&log_decoder); From cbc97b30aa28ad9286e3629677cd2ea0bac91700 Mon Sep 17 00:00:00 2001 From: Takahiro Yamashita Date: Sun, 25 Jun 2023 10:59:24 +0900 Subject: [PATCH 040/315] config_format: yaml: fix 'customs' section handling(#7559) Signed-off-by: Takahiro Yamashita --- src/config_format/flb_cf_yaml.c | 128 +++++++++++++++++++++++++++++++- 1 file changed, 124 insertions(+), 4 deletions(-) diff --git a/src/config_format/flb_cf_yaml.c b/src/config_format/flb_cf_yaml.c index 3daad835202..172d700d8e8 100644 --- a/src/config_format/flb_cf_yaml.c +++ b/src/config_format/flb_cf_yaml.c @@ -169,6 +169,9 @@ static int add_section_type(struct flb_cf *cf, struct parser_state *s) else if (s->section == SECTION_OUTPUT) { s->cf_section = flb_cf_section_create(cf, "OUTPUT", 0); } + else if (s->section == SECTION_CUSTOM) { + s->cf_section = flb_cf_section_create(cf, "customs", 0); + } if (!s->cf_section) { return -1; @@ -208,6 +211,116 @@ static char *event_type_str(yaml_event_t *event) } } +static char *state_str(enum state val) +{ + char* ret; + switch(val) { + case STATE_START: + ret = "start"; + break; + case STATE_STREAM: + ret = "stream"; + break; + case STATE_DOCUMENT: + ret = "document"; + break; + case STATE_SECTION: + ret = "section"; + break; + case STATE_SECTION_KEY: + ret = "section-key"; + break; + case STATE_SECTION_VAL: + ret = "section-val"; + break; + case STATE_SERVICE: + ret = "service"; + break; + case STATE_INCLUDE: + ret = "include"; + break; + case STATE_OTHER: + ret = "other"; + break; + case STATE_PIPELINE: + ret = "pipeline"; + break; + case STATE_PLUGIN_INPUT: + ret = "plugin-input"; + break; + case STATE_PLUGIN_FILTER: + ret = "plugin-filter"; + break; + case STATE_PLUGIN_OUTPUT: + ret = "plugin-output"; + break; + case STATE_CUSTOM: + ret = "custom"; + break; + case STATE_CUSTOM_SEQUENCE: + ret = "custom-sequence"; + break; + case STATE_CUSTOM_KEY_VALUE_PAIR: + ret = "custom-key-value-pair"; + break; + case STATE_CUSTOM_KEY: + ret = "custom-key"; + break; + case STATE_CUSTOM_VAL: + ret = "custom-val"; + break; + case STATE_PLUGIN_TYPE: + ret = "plugin-type"; + break; + case STATE_PLUGIN_KEY: + ret = "plugin-key"; + break; + case STATE_PLUGIN_VAL: + ret = "plugin-val"; + break; + case STATE_PLUGIN_VAL_LIST: + ret = "plugin-val-list"; + break; + case STATE_GROUP_KEY: + ret = "group-key"; + break; + case STATE_GROUP_VAL: + ret = "group-val"; + break; + case STATE_INPUT_PROCESSOR: + ret = "input-processor"; + break; + case STATE_INPUT_PROCESSOR_LOGS_KEY: + ret = "input-processor-logs-key"; + break; + case STATE_INPUT_PROCESSOR_LOGS_VAL: + ret = "input-processor-logs-val"; + break; + case STATE_INPUT_PROCESSOR_METRICS_KEY: + ret = "input-processor-metrics-key"; + break; + case STATE_INPUT_PROCESSOR_METRICS_VAL: + ret = "input-processor-metrics-val"; + break; + case STATE_INPUT_PROCESSOR_TRACES_KEY: + ret = "input-processor-traces-key"; + break; + case STATE_INPUT_PROCESSOR_TRACES_VAL: + ret = "input-processor-traces-val"; + break; + case STATE_ENV: + ret = "env"; + break; + case STATE_STOP: + ret = "stop"; + break; + + default: + ret = "UNKNOWN"; + } + return ret; +} + static char *get_last_included_file(struct local_ctx *ctx) { struct flb_slist_entry *e; @@ -224,9 +337,9 @@ static void yaml_error_event(struct local_ctx *ctx, struct parser_state *s, e = mk_list_entry_last(&ctx->includes, struct flb_slist_entry, _head); flb_error("[config] YAML error found in file \"%s\", line %zu, column %zu: " - "unexpected event '%s' (%d) in state %d.", + "unexpected event '%s' (%d) in state '%s' (%d).", e->str, event->start_mark.line + 1, event->start_mark.column, - event_type_str(event), event->type, s->state); + event_type_str(event), event->type, state_str(s->state), s->state); } static void yaml_error_definition(struct local_ctx *ctx, struct parser_state *s, @@ -453,7 +566,7 @@ static int consume_event(struct flb_cf *cf, struct local_ctx *ctx, case STATE_CUSTOM: switch (event->type) { case YAML_SEQUENCE_START_EVENT: - s->state = STATE_CUSTOM_SEQUENCE; + s->state = STATE_PLUGIN_TYPE; break; case YAML_SEQUENCE_END_EVENT: @@ -562,6 +675,7 @@ static int consume_event(struct flb_cf *cf, struct local_ctx *ctx, return YAML_FAILURE; } break; + default: yaml_error_event(ctx, s, event); return YAML_FAILURE; @@ -807,7 +921,13 @@ static int consume_event(struct flb_cf *cf, struct local_ctx *ctx, case YAML_MAPPING_END_EVENT: break; case YAML_SEQUENCE_END_EVENT: - s->state = STATE_PIPELINE; + if (s->section == SECTION_CUSTOM) { + /* 'customs' is a top level. So we get back to 'section'. */ + s->state = STATE_SECTION; + } + else { + s->state = STATE_PIPELINE; + } break; default: yaml_error_event(ctx, s, event); From 91129a5e547841177845c9421661f181a531eb85 Mon Sep 17 00:00:00 2001 From: Takahiro Yamashita Date: Sun, 25 Jun 2023 19:07:15 +0900 Subject: [PATCH 041/315] tests: internal: config_format_yaml: add test for customs section Signed-off-by: Takahiro Yamashita --- tests/internal/config_format_yaml.c | 29 +++++++++++++++++++ .../data/config_format/yaml/issue_7559.yaml | 14 +++++++++ 2 files changed, 43 insertions(+) create mode 100644 tests/internal/data/config_format/yaml/issue_7559.yaml diff --git a/tests/internal/config_format_yaml.c b/tests/internal/config_format_yaml.c index 4bcae842012..126cb4f0899 100644 --- a/tests/internal/config_format_yaml.c +++ b/tests/internal/config_format_yaml.c @@ -11,6 +11,7 @@ #include "flb_tests_internal.h" #define FLB_000 FLB_TESTS_DATA_PATH "/data/config_format/yaml/fluent-bit.yaml" +#define FLB_001 FLB_TESTS_DATA_PATH "/data/config_format/yaml/issue_7559.yaml" /* data/config_format/fluent-bit.yaml */ void test_basic() @@ -59,7 +60,35 @@ void test_basic() flb_cf_destroy(cf); } +/* https://github.com/fluent/fluent-bit/issues/7559 */ +void test_customs_section() +{ + struct flb_cf *cf; + struct flb_cf_section *s; + + cf = flb_cf_yaml_create(NULL, FLB_001, NULL, 0); + TEST_CHECK(cf != NULL); + if (!cf) { + exit(EXIT_FAILURE); + } + + /* Total number of sections */ + if(!TEST_CHECK(mk_list_size(&cf->sections) == 3)) { + TEST_MSG("Section number error. Got=%d expect=3", mk_list_size(&cf->sections)); + } + + s = flb_cf_section_get_by_name(cf, "customs"); + TEST_CHECK(s != NULL); + if (!TEST_CHECK(s->type == FLB_CF_CUSTOM)) { + TEST_MSG("Section type error. Got=%d expect=%d", s->type, FLB_CF_CUSTOM); + } + + flb_cf_dump(cf); + flb_cf_destroy(cf); +} + TEST_LIST = { { "basic" , test_basic}, + { "customs section", test_customs_section}, { 0 } }; diff --git a/tests/internal/data/config_format/yaml/issue_7559.yaml b/tests/internal/data/config_format/yaml/issue_7559.yaml new file mode 100644 index 00000000000..00927cae381 --- /dev/null +++ b/tests/internal/data/config_format/yaml/issue_7559.yaml @@ -0,0 +1,14 @@ +customs: + - name: calyptia + +pipeline: + inputs: + - name: fluentbit_metrics + scrape_interval: 30 + scrape_on_start: true + tag: _calyptia_cloud +service: + HTTP_Listen: 0.0.0.0 + HTTP_PORT: 2020 + HTTP_Server: 'On' + Log_Level: debug From 185873280053089e03c4eaeb90220d0c7f4da862 Mon Sep 17 00:00:00 2001 From: Phillip Whelan Date: Tue, 13 Jun 2023 18:46:40 -0400 Subject: [PATCH 042/315] in_kubernetes_events: increase interval to 500 milliseconds. Signed-off-by: Phillip Whelan --- plugins/in_kubernetes_events/kubernetes_events.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/in_kubernetes_events/kubernetes_events.h b/plugins/in_kubernetes_events/kubernetes_events.h index 7986a5014c9..bb12e4a29b2 100644 --- a/plugins/in_kubernetes_events/kubernetes_events.h +++ b/plugins/in_kubernetes_events/kubernetes_events.h @@ -27,7 +27,7 @@ #include #define DEFAULT_INTERVAL_SEC "0" -#define DEFAULT_INTERVAL_NSEC "500000" +#define DEFAULT_INTERVAL_NSEC "500000000" /* Filter context */ struct k8s_events { From 2d0489436a3c1d14dd4ff6557fadb5a194d71297 Mon Sep 17 00:00:00 2001 From: Phillip Whelan Date: Tue, 13 Jun 2023 10:21:51 -0400 Subject: [PATCH 043/315] in_kubernetes_events: allow listening to a single namespace with the 'namespace' parameter. Signed-off-by: Phillip Whelan --- .../in_kubernetes_events/kubernetes_events.c | 19 ++++++++++++++++--- .../in_kubernetes_events/kubernetes_events.h | 1 + .../kubernetes_events_conf.h | 5 ++++- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/plugins/in_kubernetes_events/kubernetes_events.c b/plugins/in_kubernetes_events/kubernetes_events.c index f407d434558..1d7695aa76b 100644 --- a/plugins/in_kubernetes_events/kubernetes_events.c +++ b/plugins/in_kubernetes_events/kubernetes_events.c @@ -555,12 +555,19 @@ static struct flb_http_client *make_event_api_request(struct k8s_events *ctx, struct flb_http_client *c; - if (continue_token == NULL && ctx->limit_request == 0) { + if (continue_token == NULL && ctx->limit_request == 0 && ctx->namespace == NULL) { return flb_http_client(u_conn, FLB_HTTP_GET, K8S_EVENTS_KUBE_API_URI, - NULL, 0, ctx->api_host, ctx->api_port, NULL, 0); + NULL, 0, ctx->api_host, ctx->api_port, NULL, 0); + } + + if (ctx->namespace == NULL) { + url = flb_sds_create(K8S_EVENTS_KUBE_API_URI); + } else { + url = flb_sds_create_size(strlen(K8S_EVENTS_KUBE_NAMESPACE_API_URI) + + strlen(ctx->namespace)); + flb_sds_printf(&url, K8S_EVENTS_KUBE_NAMESPACE_API_URI, ctx->namespace); } - url = flb_sds_create(K8S_EVENTS_KUBE_API_URI); flb_sds_cat_safe(&url, "?", 1); if (ctx->limit_request) { if (continue_token != NULL) { @@ -874,6 +881,12 @@ static struct flb_config_map config_map[] = { "kubernetes retention time for events. Default: 1h" }, + { + FLB_CONFIG_MAP_STR, "kube_namespace", NULL, + 0, FLB_TRUE, offsetof(struct k8s_events, namespace), + "kubernetes namespace to get events from, gets event from all namespaces by default." + }, + #ifdef FLB_HAVE_SQLDB { FLB_CONFIG_MAP_STR, "db", NULL, diff --git a/plugins/in_kubernetes_events/kubernetes_events.h b/plugins/in_kubernetes_events/kubernetes_events.h index bb12e4a29b2..3afd48570fa 100644 --- a/plugins/in_kubernetes_events/kubernetes_events.h +++ b/plugins/in_kubernetes_events/kubernetes_events.h @@ -44,6 +44,7 @@ struct k8s_events { int tls_debug; int tls_verify; int kube_token_ttl; + flb_sds_t namespace; /* API Server end point */ char kube_url[1024]; diff --git a/plugins/in_kubernetes_events/kubernetes_events_conf.h b/plugins/in_kubernetes_events/kubernetes_events_conf.h index fb960b9b183..9d6b54197f1 100644 --- a/plugins/in_kubernetes_events/kubernetes_events_conf.h +++ b/plugins/in_kubernetes_events/kubernetes_events_conf.h @@ -29,7 +29,10 @@ /* Kubernetes API server info */ #define K8S_EVENTS_KUBE_API_HOST "kubernetes.default.svc" #define K8S_EVENTS_KUBE_API_PORT 443 -#define K8S_EVENTS_KUBE_API_URI "/api/v1/events/" +// /apis/events.k8s.io/v1/events +// /apis/events.k8s.io/v1/namespaces/{namespace}/events +#define K8S_EVENTS_KUBE_API_URI "/api/v1/events" +#define K8S_EVENTS_KUBE_NAMESPACE_API_URI "/api/v1/namespaces/%s/events" /* secrets */ #define K8S_EVENTS_KUBE_TOKEN "/var/run/secrets/kubernetes.io/serviceaccount/token" From 92dc8445b6dddd5e30766e024092d53ffc702f7c Mon Sep 17 00:00:00 2001 From: Phillip Whelan Date: Wed, 14 Jun 2023 15:54:06 -0400 Subject: [PATCH 044/315] in_kubernetes_events: allow setting kube_token_file as empty for use with kubectl proxy. Signed-off-by: Phillip Whelan --- plugins/in_kubernetes_events/kubernetes_events.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/plugins/in_kubernetes_events/kubernetes_events.c b/plugins/in_kubernetes_events/kubernetes_events.c index 1d7695aa76b..5b0e76bc549 100644 --- a/plugins/in_kubernetes_events/kubernetes_events.c +++ b/plugins/in_kubernetes_events/kubernetes_events.c @@ -101,7 +101,7 @@ static int get_http_auth_header(struct k8s_events *ctx) char *tk = NULL; size_t tk_size = 0; - if (!ctx->token_file) { + if (!ctx->token_file || strlen(ctx->token_file) == 0) { return 0; } @@ -148,6 +148,10 @@ static int refresh_token_if_needed(struct k8s_events *ctx) int expired = FLB_FALSE; int ret; + if (!ctx->token_file || strlen(ctx->token_file) == 0) { + return 0; + } + if (ctx->token_created > 0) { if (time(NULL) > ctx->token_created + ctx->token_ttl) { expired = FLB_TRUE; @@ -257,7 +261,8 @@ static int record_get_field_uint64(msgpack_object *obj, const char *fieldname, u return 0; } - if (v->type == MSGPACK_OBJECT_POSITIVE_INTEGER || MSGPACK_OBJECT_NEGATIVE_INTEGER) { + if (v->type == MSGPACK_OBJECT_POSITIVE_INTEGER || + v->type == MSGPACK_OBJECT_NEGATIVE_INTEGER) { *val = v->via.u64; return 0; } From 8b304549a09e1cfdf0dfc85e5fad4ead42df2920 Mon Sep 17 00:00:00 2001 From: Phillip Whelan Date: Wed, 14 Jun 2023 16:08:24 -0400 Subject: [PATCH 045/315] in_kubernetes_events: remove unnecessary type check. Signed-off-by: Phillip Whelan --- plugins/in_kubernetes_events/kubernetes_events.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/plugins/in_kubernetes_events/kubernetes_events.c b/plugins/in_kubernetes_events/kubernetes_events.c index 5b0e76bc549..97719fba6e0 100644 --- a/plugins/in_kubernetes_events/kubernetes_events.c +++ b/plugins/in_kubernetes_events/kubernetes_events.c @@ -260,9 +260,7 @@ static int record_get_field_uint64(msgpack_object *obj, const char *fieldname, u } return 0; } - - if (v->type == MSGPACK_OBJECT_POSITIVE_INTEGER || - v->type == MSGPACK_OBJECT_NEGATIVE_INTEGER) { + if (v->type == MSGPACK_OBJECT_POSITIVE_INTEGER) { *val = v->via.u64; return 0; } From 1afb5befad7ac441618302cc1a4a056fd257c5d5 Mon Sep 17 00:00:00 2001 From: Takahiro Yamashita Date: Thu, 8 Jun 2023 21:00:06 +0900 Subject: [PATCH 046/315] in_kubernetes_events: call destructor when init failed Signed-off-by: Takahiro Yamashita --- .../kubernetes_events_conf.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/plugins/in_kubernetes_events/kubernetes_events_conf.c b/plugins/in_kubernetes_events/kubernetes_events_conf.c index 60a39b2bb2e..4f67d8cfcee 100644 --- a/plugins/in_kubernetes_events/kubernetes_events_conf.c +++ b/plugins/in_kubernetes_events/kubernetes_events_conf.c @@ -160,7 +160,7 @@ struct k8s_events *k8s_events_conf_create(struct flb_input_instance *ins) ctx->encoder = flb_log_event_encoder_create(FLB_LOG_EVENT_FORMAT_DEFAULT); if (!ctx->encoder) { flb_plg_error(ins, "could not initialize event encoder"); - flb_free(ctx); + k8s_events_conf_destroy(ctx); return NULL; } @@ -169,14 +169,14 @@ struct k8s_events *k8s_events_conf_create(struct flb_input_instance *ins) if (!ctx->ra_timestamp) { flb_plg_error(ctx->ins, "could not create record accessor for metadata items"); - flb_free(ctx); + k8s_events_conf_destroy(ctx); return NULL; } ctx->ra_resource_version = flb_ra_create(K8S_EVENTS_RA_RESOURCE_VERSION, FLB_TRUE); if (!ctx->ra_resource_version) { flb_plg_error(ctx->ins, "could not create record accessor for resource version"); - flb_free(ctx); + k8s_events_conf_destroy(ctx); return NULL; } @@ -200,7 +200,7 @@ struct k8s_events *k8s_events_conf_create(struct flb_input_instance *ins) ctx->api_https = FLB_TRUE; } else { - flb_free(ctx); + k8s_events_conf_destroy(ctx); return NULL; } @@ -227,7 +227,7 @@ struct k8s_events *k8s_events_conf_create(struct flb_input_instance *ins) /* network setup */ ret = network_init(ctx, ins->config); if (ret == -1) { - flb_free(ctx); + k8s_events_conf_destroy(ctx); return NULL; } @@ -238,7 +238,7 @@ struct k8s_events *k8s_events_conf_create(struct flb_input_instance *ins) ctx->db = flb_kubernetes_event_db_open(tmp, ins, ctx, ins->config); if (!ctx->db) { flb_plg_error(ctx->ins, "could not open/create database"); - flb_free(ctx); + k8s_events_conf_destroy(ctx); return NULL; } } @@ -251,7 +251,7 @@ struct k8s_events *k8s_events_conf_create(struct flb_input_instance *ins) 0); if (ret != SQLITE_OK) { flb_plg_error(ctx->ins, "error preparing database SQL statement: stmt_get_kubernetes_event_exists_by_uid"); - flb_free(ctx); + k8s_events_conf_destroy(ctx); return NULL; } @@ -262,7 +262,7 @@ struct k8s_events *k8s_events_conf_create(struct flb_input_instance *ins) 0); if (ret != SQLITE_OK) { flb_plg_error(ctx->ins, "error preparing database SQL statement: stmt_insert_kubernetes_event"); - flb_free(ctx); + k8s_events_conf_destroy(ctx); return NULL; } @@ -273,7 +273,7 @@ struct k8s_events *k8s_events_conf_create(struct flb_input_instance *ins) 0); if (ret != SQLITE_OK) { flb_plg_error(ctx->ins, "error preparing database SQL statement: stmt_delete_old_kubernetes_events"); - flb_free(ctx); + k8s_events_conf_destroy(ctx); return NULL; } } From f90e6d80fbf37662cf8ad52284d0ff0b419b8dc5 Mon Sep 17 00:00:00 2001 From: Phillip Whelan Date: Wed, 7 Jun 2023 13:58:20 -0400 Subject: [PATCH 047/315] custom_calyptia: set defaults for calyptia fleet. Configure calyptia fleet via the custom calyptia plugin so we can set default values for 'host' and 'port' (set to the production calyptia cloud). Signed-off-by: Phillip Whelan --- plugins/custom_calyptia/calyptia.c | 54 ++++++++++++++++--- plugins/in_calyptia_fleet/in_calyptia_fleet.c | 6 ++- 2 files changed, 52 insertions(+), 8 deletions(-) diff --git a/plugins/custom_calyptia/calyptia.c b/plugins/custom_calyptia/calyptia.c index 6789032d148..5c22d52200a 100644 --- a/plugins/custom_calyptia/calyptia.c +++ b/plugins/custom_calyptia/calyptia.c @@ -35,7 +35,6 @@ struct calyptia { flb_sds_t cloud_host; flb_sds_t cloud_port; flb_sds_t machine_id; - flb_sds_t fleet_id; /* used for reporting chunk trace records. */ #ifdef FLB_HAVE_CHUNK_TRACE @@ -51,7 +50,14 @@ struct calyptia { /* instances */ struct flb_input_instance *i; struct flb_output_instance *o; + struct flb_input_instance *fleet; struct flb_custom_instance *ins; + + /* Fleet configuration */ + flb_sds_t fleet_id; /* fleet-id */ + flb_sds_t fleet_config_dir; /* fleet configuration directory */ + int fleet_interval_sec; + int fleet_interval_nsec; }; /* @@ -297,10 +303,6 @@ static int cb_calyptia_init(struct flb_custom_instance *ins, flb_output_set_property(ctx->o, "machine_id", ctx->machine_id); } - if (ctx->fleet_id) { - flb_output_set_property(ctx->o, "fleet_id", ctx->fleet_id); - } - /* Override network details: development purposes only */ if (ctx->cloud_host) { flb_output_set_property(ctx->o, "cloud_host", ctx->cloud_host); @@ -324,6 +326,29 @@ static int cb_calyptia_init(struct flb_custom_instance *ins, flb_output_set_property(ctx->o, "tls.verify", "false"); } + if (ctx->fleet_id) { + flb_output_set_property(ctx->o, "fleet_id", ctx->fleet_id); + + ctx->fleet = flb_input_new(config, "calyptia_fleet", NULL, FLB_FALSE); + if (!ctx->fleet) { + flb_plg_error(ctx->ins, "could not load Calyptia Fleet plugin"); + return -1; + } + + flb_input_set_property(ctx->fleet, "api_key", ctx->api_key); + flb_input_set_property(ctx->fleet, "host", ctx->cloud_host); + flb_input_set_property(ctx->fleet, "port", ctx->cloud_port); + flb_input_set_property(ctx->fleet, "tls", + (ctx->cloud_tls == 1 ? "on" : "off")); + flb_input_set_property(ctx->fleet, "tls.verify", + (ctx->cloud_tls_verify == 1 ? "on" : "off")); + if (ctx->fleet_config_dir) { + flb_input_set_property(ctx->fleet, "config_dir", ctx->fleet_config_dir); + } + flb_input_set_property(ctx->fleet, "fleet_id", ctx->fleet_id); + } + + #ifdef FLB_HAVE_CHUNK_TRACE flb_output_set_property(ctx->o, "pipeline_id", ctx->pipeline_id); #endif /* FLB_HAVE_CHUNK_TRACE */ @@ -359,13 +384,13 @@ static struct flb_config_map config_map[] = { }, { - FLB_CONFIG_MAP_STR, "calyptia_host", NULL, + FLB_CONFIG_MAP_STR, "calyptia_host", "cloud-api.calyptia.com", 0, FLB_TRUE, offsetof(struct calyptia, cloud_host), "" }, { - FLB_CONFIG_MAP_STR, "calyptia_port", NULL, + FLB_CONFIG_MAP_STR, "calyptia_port", "443", 0, FLB_TRUE, offsetof(struct calyptia, cloud_port), "" }, @@ -397,6 +422,21 @@ static struct flb_config_map config_map[] = { 0, FLB_TRUE, offsetof(struct calyptia, fleet_id), "Fleet id to be used when registering agent in a fleet" }, + { + FLB_CONFIG_MAP_STR, "fleet.config_dir", NULL, + 0, FLB_TRUE, offsetof(struct calyptia, fleet_config_dir), + "Base path for the configuration directory." + }, + { + FLB_CONFIG_MAP_INT, "fleet.interval_sec", "-1", + 0, FLB_TRUE, offsetof(struct calyptia, fleet_interval_sec), + "Set the collector interval" + }, + { + FLB_CONFIG_MAP_INT, "fleet.interval_nsec", "-1", + 0, FLB_TRUE, offsetof(struct calyptia, fleet_interval_nsec), + "Set the collector interval (nanoseconds)" + }, #ifdef FLB_HAVE_CHUNK_TRACE { diff --git a/plugins/in_calyptia_fleet/in_calyptia_fleet.c b/plugins/in_calyptia_fleet/in_calyptia_fleet.c index 3ed7ba0e12a..a2821a31095 100644 --- a/plugins/in_calyptia_fleet/in_calyptia_fleet.c +++ b/plugins/in_calyptia_fleet/in_calyptia_fleet.c @@ -429,6 +429,10 @@ static int in_calyptia_fleet_collect(struct flb_input_instance *ins, cfgname = time_fleet_config_filename(ctx, time_last_modified); if (access(cfgname, F_OK) == -1 && errno == ENOENT) { cfgfp = fopen(cfgname, "w+"); + if (cfgfp == NULL) { + flb_plg_error(ctx->ins, "unable to open configuration file: %s", cfgname); + goto http_error; + } header = flb_sds_create_size(4096); flb_sds_printf(&header, "[INPUT]\n" @@ -707,5 +711,5 @@ struct flb_input_plugin in_calyptia_fleet_plugin = { .cb_flush_buf = NULL, .cb_exit = in_calyptia_fleet_exit, .config_map = config_map, - .flags = FLB_INPUT_NET|FLB_INPUT_CORO|FLB_IO_OPT_TLS + .flags = FLB_INPUT_NET|FLB_INPUT_CORO|FLB_IO_OPT_TLS|FLB_INPUT_PRIVATE }; From 8839cf2715352ffddcd728a899f79b41634b41de Mon Sep 17 00:00:00 2001 From: Phillip Whelan Date: Tue, 13 Jun 2023 19:01:00 -0400 Subject: [PATCH 048/315] custom_calyptia: use verbose code to pass TLS parameters to fleet plugin. Signed-off-by: Phillip Whelan --- plugins/custom_calyptia/calyptia.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/plugins/custom_calyptia/calyptia.c b/plugins/custom_calyptia/calyptia.c index 5c22d52200a..eb79ae7dfd8 100644 --- a/plugins/custom_calyptia/calyptia.c +++ b/plugins/custom_calyptia/calyptia.c @@ -338,10 +338,16 @@ static int cb_calyptia_init(struct flb_custom_instance *ins, flb_input_set_property(ctx->fleet, "api_key", ctx->api_key); flb_input_set_property(ctx->fleet, "host", ctx->cloud_host); flb_input_set_property(ctx->fleet, "port", ctx->cloud_port); - flb_input_set_property(ctx->fleet, "tls", - (ctx->cloud_tls == 1 ? "on" : "off")); - flb_input_set_property(ctx->fleet, "tls.verify", - (ctx->cloud_tls_verify == 1 ? "on" : "off")); + if (ctx->cloud_tls == 1) { + flb_input_set_property(ctx->fleet, "tls", "on"); + } else { + flb_input_set_property(ctx->fleet, "tls", "off"); + } + if (ctx->cloud_tls_verify == 1) { + flb_input_set_property(ctx->fleet, "tls.verify", "on"); + } else { + flb_input_set_property(ctx->fleet, "tls.verify", "off"); + } if (ctx->fleet_config_dir) { flb_input_set_property(ctx->fleet, "config_dir", ctx->fleet_config_dir); } From a38465aa215fc2c123184aadc359ba3fca0441dc Mon Sep 17 00:00:00 2001 From: Hiroshi Hatake Date: Fri, 30 Jun 2023 12:20:58 +0900 Subject: [PATCH 049/315] build: Install config_format headers Signed-off-by: Hiroshi Hatake --- include/CMakeLists.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt index 1bff6f62286..38f1b0dccd5 100644 --- a/include/CMakeLists.txt +++ b/include/CMakeLists.txt @@ -10,6 +10,12 @@ install(FILES ${headers} COMPONENT headers PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ) +file(GLOB headers "fluent-bit/config_format/*.h") +install(FILES ${headers} + DESTINATION ${FLB_INSTALL_INCLUDEDIR}/fluent-bit/config_format/ + COMPONENT headers + PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ) + file(GLOB headers "fluent-bit/tls/*.h") install(FILES ${headers} DESTINATION ${FLB_INSTALL_INCLUDEDIR}/fluent-bit/tls/ From 9e260ba35dfc20eb6f01462868177b9cbe0650d7 Mon Sep 17 00:00:00 2001 From: David Korczynski Date: Fri, 30 Jun 2023 04:08:16 -0700 Subject: [PATCH 050/315] filter_rewrite_tag: fix potential NULL dereference `flb_slist_entry_get` can return NULL which is not checked for at the moment. This fixes it. Signed-off-by: David Korczynski --- plugins/filter_rewrite_tag/rewrite_tag.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/plugins/filter_rewrite_tag/rewrite_tag.c b/plugins/filter_rewrite_tag/rewrite_tag.c index e1c75981b86..febeaeb3d03 100644 --- a/plugins/filter_rewrite_tag/rewrite_tag.c +++ b/plugins/filter_rewrite_tag/rewrite_tag.c @@ -135,6 +135,11 @@ static int process_config(struct flb_rewrite_tag *ctx) /* key */ entry = flb_slist_entry_get(val->val.list, 0); + if (entry == NULL) { + flb_plg_error(ctx->ins, "failed to get entry"); + flb_free(rule); + return -1; + } rule->ra_key = flb_ra_create(entry->str, FLB_FALSE); if (!rule->ra_key) { flb_plg_error(ctx->ins, "invalid record accessor key ? '%s'", From 0b9ae191cab889da28185b3ea5b710720b5e8a71 Mon Sep 17 00:00:00 2001 From: Hiroshi Hatake Date: Mon, 3 Jul 2023 10:17:16 +0900 Subject: [PATCH 051/315] in_splunk: Implement Splunk HEC input plugin (#7349) --------- Signed-off-by: Hiroshi Hatake --- CMakeLists.txt | 1 + cmake/windows-setup.cmake | 1 + plugins/CMakeLists.txt | 1 + plugins/in_splunk/CMakeLists.txt | 12 + plugins/in_splunk/splunk.c | 213 ++++++++ plugins/in_splunk/splunk.h | 60 +++ plugins/in_splunk/splunk_config.c | 184 +++++++ plugins/in_splunk/splunk_config.h | 29 ++ plugins/in_splunk/splunk_conn.c | 306 +++++++++++ plugins/in_splunk/splunk_conn.h | 54 ++ plugins/in_splunk/splunk_prot.c | 785 ++++++++++++++++++++++++++++ plugins/in_splunk/splunk_prot.h | 36 ++ tests/runtime/CMakeLists.txt | 1 + tests/runtime/in_splunk.c | 824 ++++++++++++++++++++++++++++++ 14 files changed, 2507 insertions(+) create mode 100644 plugins/in_splunk/CMakeLists.txt create mode 100644 plugins/in_splunk/splunk.c create mode 100644 plugins/in_splunk/splunk.h create mode 100644 plugins/in_splunk/splunk_config.c create mode 100644 plugins/in_splunk/splunk_config.h create mode 100644 plugins/in_splunk/splunk_conn.c create mode 100644 plugins/in_splunk/splunk_conn.h create mode 100644 plugins/in_splunk/splunk_prot.c create mode 100644 plugins/in_splunk/splunk_prot.h create mode 100644 tests/runtime/in_splunk.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 6fd4c5abb97..ed4bac08bb8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -210,6 +210,7 @@ option(FLB_IN_PODMAN_METRICS "Enable Podman Metrics input plugin" option(FLB_IN_OPENTELEMETRY "Enable OpenTelemetry input plugin" Yes) option(FLB_IN_ELASTICSEARCH "Enable Elasticsearch (Bulk API) input plugin" Yes) option(FLB_IN_CALYPTIA_FLEET "Enable Calyptia Fleet input plugin" Yes) +option(FLB_IN_SPLUNK "Enable Splunk HTTP HEC input plugin" Yes) option(FLB_OUT_AZURE "Enable Azure output plugin" Yes) option(FLB_OUT_AZURE_BLOB "Enable Azure output plugin" Yes) option(FLB_OUT_AZURE_LOGS_INGESTION "Enable Azure Logs Ingestion output plugin" Yes) diff --git a/cmake/windows-setup.cmake b/cmake/windows-setup.cmake index b1ace7b9d16..853d1cda4dd 100644 --- a/cmake/windows-setup.cmake +++ b/cmake/windows-setup.cmake @@ -62,6 +62,7 @@ if(FLB_WINDOWS_DEFAULTS) set(FLB_IN_ELASTICSEARCH Yes) # disable calyptia fleet management for now set(FLB_IN_CALYPTIA_FLEET No) + set(FLB_IN_SPLUNK Yes) # OUTPUT plugins # ============== diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 3c1b66b7d1c..ef92b37c6e7 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -224,6 +224,7 @@ REGISTER_IN_PLUGIN("in_statsd") REGISTER_IN_PLUGIN("in_opentelemetry") REGISTER_IN_PLUGIN("in_elasticsearch") REGISTER_IN_PLUGIN("in_calyptia_fleet") +REGISTER_IN_PLUGIN("in_splunk") # Test the event loop messaging when used in threaded mode REGISTER_IN_PLUGIN("in_event_test") diff --git a/plugins/in_splunk/CMakeLists.txt b/plugins/in_splunk/CMakeLists.txt new file mode 100644 index 00000000000..42ecf2e31a6 --- /dev/null +++ b/plugins/in_splunk/CMakeLists.txt @@ -0,0 +1,12 @@ +if(NOT FLB_METRICS) + message(FATAL_ERROR "Splunk input plugin requires FLB_HTTP_SERVER=On.") +endif() + +set(src + splunk.c + splunk_conn.c + splunk_prot.c + splunk_config.c + ) + +FLB_PLUGIN(in_splunk "${src}" "monkey-core-static") diff --git a/plugins/in_splunk/splunk.c b/plugins/in_splunk/splunk.c new file mode 100644 index 00000000000..78589037c26 --- /dev/null +++ b/plugins/in_splunk/splunk.c @@ -0,0 +1,213 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Fluent Bit + * ========== + * Copyright (C) 2015-2022 The Fluent Bit Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include +#include +#include + +#include "splunk.h" +#include "splunk_conn.h" +#include "splunk_config.h" + +/* + * For a server event, the collection event means a new client have arrived, we + * accept the connection and create a new TCP instance which will wait for + * JSON map messages. + */ +static int in_splunk_collect(struct flb_input_instance *ins, + struct flb_config *config, void *in_context) +{ + struct flb_connection *connection; + struct splunk_conn *conn; + struct flb_splunk *ctx; + + ctx = in_context; + + connection = flb_downstream_conn_get(ctx->downstream); + + if (connection == NULL) { + flb_plg_error(ctx->ins, "could not accept new connection"); + + return -1; + } + + flb_plg_trace(ctx->ins, "new TCP connection arrived FD=%i", + connection->fd); + + conn = splunk_conn_add(connection, ctx); + + if (conn == NULL) { + flb_downstream_conn_release(connection); + + return -1; + } + + return 0; +} + +static int in_splunk_init(struct flb_input_instance *ins, + struct flb_config *config, void *data) +{ + unsigned short int port; + int ret; + struct flb_splunk *ctx; + + (void) data; + + /* Create context and basic conf */ + ctx = splunk_config_create(ins); + if (!ctx) { + return -1; + } + + ctx->collector_id = -1; + + /* Populate context with config map defaults and incoming properties */ + ret = flb_input_config_map_set(ins, (void *) ctx); + if (ret == -1) { + flb_plg_error(ctx->ins, "configuration error"); + splunk_config_destroy(ctx); + return -1; + } + + /* Set the context */ + flb_input_set_context(ins, ctx); + + port = (unsigned short int) strtoul(ctx->tcp_port, NULL, 10); + + ctx->downstream = flb_downstream_create(FLB_TRANSPORT_TCP, + ins->flags, + ctx->listen, + port, + ins->tls, + config, + &ins->net_setup); + + if (ctx->downstream == NULL) { + flb_plg_error(ctx->ins, + "could not initialize downstream on %s:%s. Aborting", + ctx->listen, ctx->tcp_port); + + splunk_config_destroy(ctx); + + return -1; + } + + flb_input_downstream_set(ctx->downstream, ctx->ins); + + /* Collect upon data available on the standard input */ + ret = flb_input_set_collector_socket(ins, + in_splunk_collect, + ctx->downstream->server_fd, + config); + if (ret == -1) { + flb_plg_error(ctx->ins, "Could not set collector for IN_TCP input plugin"); + splunk_config_destroy(ctx); + + return -1; + } + + ctx->collector_id = ret; + + return 0; +} + +static int in_splunk_exit(void *data, struct flb_config *config) +{ + struct flb_splunk *ctx; + + (void) config; + + ctx = data; + + if (ctx != NULL) { + splunk_config_destroy(ctx); + } + + return 0; +} + + +static void in_splunk_pause(void *data, struct flb_config *config) +{ + struct flb_splunk *ctx = data; + + flb_input_collector_pause(ctx->collector_id, ctx->ins); + +} + +static void in_splunk_resume(void *data, struct flb_config *config) +{ + struct flb_splunk *ctx = data; + + flb_input_collector_resume(ctx->collector_id, ctx->ins); +} + +/* Configuration properties map */ +static struct flb_config_map config_map[] = { + { + FLB_CONFIG_MAP_SIZE, "buffer_max_size", HTTP_BUFFER_MAX_SIZE, + 0, FLB_TRUE, offsetof(struct flb_splunk, buffer_max_size), + "" + }, + + { + FLB_CONFIG_MAP_SIZE, "buffer_chunk_size", HTTP_BUFFER_CHUNK_SIZE, + 0, FLB_TRUE, offsetof(struct flb_splunk, buffer_chunk_size), + "" + }, + + { + FLB_CONFIG_MAP_SLIST_1, "success_header", NULL, + FLB_CONFIG_MAP_MULT, FLB_TRUE, offsetof(struct flb_splunk, success_headers), + "Add an HTTP header key/value pair on success. Multiple headers can be set" + }, + + { + FLB_CONFIG_MAP_STR, "splunk_token", NULL, + 0, FLB_FALSE, 0, + "Set valid Splunk HEC tokens for the requests" + }, + + { + FLB_CONFIG_MAP_STR, "tag_key", NULL, + 0, FLB_TRUE, offsetof(struct flb_splunk, tag_key), + "" + }, + + + /* EOF */ + {0} +}; + +/* Plugin reference */ +struct flb_input_plugin in_splunk_plugin = { + .name = "splunk", + .description = "Input plugin for Splunk HEC payloads", + .cb_init = in_splunk_init, + .cb_pre_run = NULL, + .cb_collect = in_splunk_collect, + .cb_flush_buf = NULL, + .cb_pause = in_splunk_pause, + .cb_resume = in_splunk_resume, + .cb_exit = in_splunk_exit, + .config_map = config_map, + .flags = FLB_INPUT_NET_SERVER | FLB_IO_OPT_TLS +}; diff --git a/plugins/in_splunk/splunk.h b/plugins/in_splunk/splunk.h new file mode 100644 index 00000000000..bf935ea2215 --- /dev/null +++ b/plugins/in_splunk/splunk.h @@ -0,0 +1,60 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Fluent Bit + * ========== + * Copyright (C) 2015-2022 The Fluent Bit Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLB_IN_SPLUNK_H +#define FLB_IN_SPLUNK_H + +#include +#include +#include +#include +#include + +#include + +#define HTTP_BUFFER_MAX_SIZE "4M" +#define HTTP_BUFFER_CHUNK_SIZE "512K" + +struct flb_splunk { + flb_sds_t listen; + flb_sds_t tcp_port; + const char *tag_key; + + int collector_id; + + /* Success HTTP headers */ + struct mk_list *success_headers; + flb_sds_t success_headers_str; + + size_t buffer_max_size; /* Maximum buffer size */ + size_t buffer_chunk_size; /* Chunk allocation size */ + + /* Token Auth */ + flb_sds_t auth_header; + + struct flb_log_event_encoder log_encoder; + struct flb_downstream *downstream; /* Client manager */ + struct mk_list connections; /* linked list of connections */ + + struct mk_server *server; + struct flb_input_instance *ins; +}; + + +#endif diff --git a/plugins/in_splunk/splunk_config.c b/plugins/in_splunk/splunk_config.c new file mode 100644 index 00000000000..f61070153f9 --- /dev/null +++ b/plugins/in_splunk/splunk_config.c @@ -0,0 +1,184 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Fluent Bit + * ========== + * Copyright (C) 2015-2022 The Fluent Bit Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "splunk.h" +#include "splunk_config.h" +#include "splunk_conn.h" +#include "splunk_config.h" + +struct flb_splunk *splunk_config_create(struct flb_input_instance *ins) +{ + struct mk_list *header_iterator; + struct flb_slist_entry *header_value; + struct flb_slist_entry *header_name; + struct flb_config_map_val *header_pair; + char port[8]; + int ret; + struct flb_splunk *ctx; + const char *tmp; + + ctx = flb_calloc(1, sizeof(struct flb_splunk)); + if (!ctx) { + flb_errno(); + return NULL; + } + ctx->ins = ins; + mk_list_init(&ctx->connections); + + /* Load the config map */ + ret = flb_input_config_map_set(ins, (void *) ctx); + if (ret == -1) { + flb_free(ctx); + return NULL; + } + + ctx->auth_header = NULL; + tmp = flb_input_get_property("splunk_token", ins); + if (tmp) { + ctx->auth_header = flb_sds_create("Splunk "); + if (ctx->auth_header == NULL) { + flb_plg_error(ctx->ins, "error on prefix of auth_header generation"); + splunk_config_destroy(ctx); + return NULL; + } + ret = flb_sds_cat_safe(&ctx->auth_header, tmp, strlen(tmp)); + if (ret < 0) { + flb_plg_error(ctx->ins, "error on token generation"); + splunk_config_destroy(ctx); + return NULL; + } + } + + /* Listen interface (if not set, defaults to 0.0.0.0:8088) */ + flb_input_net_default_listener("0.0.0.0", 8088, ins); + + ctx->listen = flb_strdup(ins->host.listen); + snprintf(port, sizeof(port) - 1, "%d", ins->host.port); + ctx->tcp_port = flb_strdup(port); + + /* HTTP Server specifics */ + ctx->server = flb_calloc(1, sizeof(struct mk_server)); + if (ctx->server == NULL) { + flb_plg_error(ctx->ins, "error on mk_server allocation"); + splunk_config_destroy(ctx); + return NULL; + } + ctx->server->keep_alive = MK_TRUE; + + /* monkey detects server->workers == 0 as the server not being initialized at the + * moment so we want to make sure that it stays that way! + */ + + ret = flb_log_event_encoder_init(&ctx->log_encoder, + FLB_LOG_EVENT_FORMAT_DEFAULT); + + if (ret != FLB_EVENT_ENCODER_SUCCESS) { + flb_plg_error(ctx->ins, "error initializing event encoder : %d", ret); + + splunk_config_destroy(ctx); + + return NULL; + } + + ctx->success_headers_str = flb_sds_create_size(1); + + if (ctx->success_headers_str == NULL) { + splunk_config_destroy(ctx); + + return NULL; + } + + flb_config_map_foreach(header_iterator, header_pair, ctx->success_headers) { + header_name = mk_list_entry_first(header_pair->val.list, + struct flb_slist_entry, + _head); + + header_value = mk_list_entry_last(header_pair->val.list, + struct flb_slist_entry, + _head); + + ret = flb_sds_cat_safe(&ctx->success_headers_str, + header_name->str, + flb_sds_len(header_name->str)); + + if (ret == 0) { + ret = flb_sds_cat_safe(&ctx->success_headers_str, + ": ", + 2); + } + + if (ret == 0) { + ret = flb_sds_cat_safe(&ctx->success_headers_str, + header_value->str, + flb_sds_len(header_value->str)); + } + + if (ret == 0) { + ret = flb_sds_cat_safe(&ctx->success_headers_str, + "\r\n", + 2); + } + + if (ret != 0) { + splunk_config_destroy(ctx); + + return NULL; + } + } + + return ctx; +} + +int splunk_config_destroy(struct flb_splunk *ctx) +{ + /* release all connections */ + splunk_conn_release_all(ctx); + + flb_log_event_encoder_destroy(&ctx->log_encoder); + + if (ctx->collector_id != -1) { + flb_input_collector_delete(ctx->collector_id, ctx->ins); + + ctx->collector_id = -1; + } + + if (ctx->auth_header != NULL) { + flb_sds_destroy(ctx->auth_header); + } + + if (ctx->downstream != NULL) { + flb_downstream_destroy(ctx->downstream); + } + + if (ctx->server) { + flb_free(ctx->server); + } + + if (ctx->success_headers_str != NULL) { + flb_sds_destroy(ctx->success_headers_str); + } + + + flb_free(ctx->listen); + flb_free(ctx->tcp_port); + flb_free(ctx); + return 0; +} diff --git a/plugins/in_splunk/splunk_config.h b/plugins/in_splunk/splunk_config.h new file mode 100644 index 00000000000..24d2008f226 --- /dev/null +++ b/plugins/in_splunk/splunk_config.h @@ -0,0 +1,29 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Fluent Bit + * ========== + * Copyright (C) 2015-2022 The Fluent Bit Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLB_IN_SPLUNK_CONFIG_H +#define FLB_IN_SPLUNK_CONFIG_H + +#include +#include "splunk.h" + +struct flb_splunk *splunk_config_create(struct flb_input_instance *ins); +int splunk_config_destroy(struct flb_splunk *ctx); + +#endif diff --git a/plugins/in_splunk/splunk_conn.c b/plugins/in_splunk/splunk_conn.c new file mode 100644 index 00000000000..f605a16c7eb --- /dev/null +++ b/plugins/in_splunk/splunk_conn.c @@ -0,0 +1,306 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Fluent Bit + * ========== + * Copyright (C) 2015-2022 The Fluent Bit Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for thet specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "splunk.h" +#include "splunk_conn.h" +#include "splunk_prot.h" + +static void splunk_conn_request_init(struct mk_http_session *session, + struct mk_http_request *request); + +static int splunk_conn_event(void *data) +{ + int status; + size_t size; + ssize_t available; + ssize_t bytes; + char *tmp; + char *request_end; + size_t request_len; + struct flb_connection *connection; + struct splunk_conn *conn; + struct mk_event *event; + struct flb_splunk *ctx; + + connection = (struct flb_connection *) data; + + conn = connection->user_data; + + ctx = conn->ctx; + + event = &connection->event; + + if (event->mask & MK_EVENT_READ) { + available = (conn->buf_size - conn->buf_len) - 1; + if (available < 1) { + if (conn->buf_size + ctx->buffer_chunk_size > ctx->buffer_max_size) { + flb_plg_trace(ctx->ins, + "fd=%i incoming data exceed limit (%zu KB)", + event->fd, (ctx->buffer_max_size / 1024)); + splunk_conn_del(conn); + return -1; + } + + size = conn->buf_size + ctx->buffer_chunk_size; + tmp = flb_realloc(conn->buf_data, size); + if (!tmp) { + flb_errno(); + return -1; + } + flb_plg_trace(ctx->ins, "fd=%i buffer realloc %i -> %zu", + event->fd, conn->buf_size, size); + + conn->buf_data = tmp; + conn->buf_size = size; + available = (conn->buf_size - conn->buf_len) - 1; + } + + /* Read data */ + bytes = flb_io_net_read(connection, + (void *) &conn->buf_data[conn->buf_len], + available); + + if (bytes <= 0) { + flb_plg_trace(ctx->ins, "fd=%i closed connection", event->fd); + splunk_conn_del(conn); + return -1; + } + + flb_plg_trace(ctx->ins, "read()=%zi pre_len=%i now_len=%zi", + bytes, conn->buf_len, conn->buf_len + bytes); + conn->buf_len += bytes; + conn->buf_data[conn->buf_len] = '\0'; + + status = mk_http_parser(&conn->request, &conn->session.parser, + conn->buf_data, conn->buf_len, conn->session.server); + + if (status == MK_HTTP_PARSER_OK) { + /* Do more logic parsing and checks for this request */ + splunk_prot_handle(ctx, conn, &conn->session, &conn->request); + + /* Evict the processed request from the connection buffer and reinitialize + * the HTTP parser. + */ + + request_end = NULL; + + if (NULL != conn->request.data.data) { + request_end = &conn->request.data.data[conn->request.data.len]; + } + else { + request_end = strstr(conn->buf_data, "\r\n\r\n"); + + if(NULL != request_end) { + request_end = &request_end[4]; + } + } + + if (NULL != request_end) { + request_len = (size_t)(request_end - conn->buf_data); + + if (0 < (conn->buf_len - request_len)) { + memmove(conn->buf_data, &conn->buf_data[request_len], + conn->buf_len - request_len); + + conn->buf_data[conn->buf_len - request_len] = '\0'; + conn->buf_len -= request_len; + } + else { + memset(conn->buf_data, 0, request_len); + + conn->buf_len = 0; + } + + /* Reinitialize the parser so the next request is properly + * handled, the additional memset intends to wipe any left over data + * from the headers parsed in the previous request. + */ + memset(&conn->session.parser, 0, sizeof(struct mk_http_parser)); + mk_http_parser_init(&conn->session.parser); + splunk_conn_request_init(&conn->session, &conn->request); + } + } + else if (status == MK_HTTP_PARSER_ERROR) { + splunk_prot_handle_error(ctx, conn, &conn->session, &conn->request); + + /* Reinitialize the parser so the next request is properly + * handled, the additional memset intends to wipe any left over data + * from the headers parsed in the previous request. + */ + memset(&conn->session.parser, 0, sizeof(struct mk_http_parser)); + mk_http_parser_init(&conn->session.parser); + splunk_conn_request_init(&conn->session, &conn->request); + } + + /* FIXME: add Protocol handler here */ + return bytes; + } + + if (event->mask & MK_EVENT_CLOSE) { + flb_plg_trace(ctx->ins, "fd=%i hangup", event->fd); + splunk_conn_del(conn); + return -1; + } + + return 0; + +} + +static void splunk_conn_session_init(struct mk_http_session *session, + struct mk_server *server, + int client_fd) +{ + /* Alloc memory for node */ + session->_sched_init = MK_TRUE; + session->pipelined = MK_FALSE; + session->counter_connections = 0; + session->close_now = MK_FALSE; + session->status = MK_REQUEST_STATUS_INCOMPLETE; + session->server = server; + session->socket = client_fd; + + /* creation time in unix time */ + session->init_time = time(NULL); + + session->channel = mk_channel_new(MK_CHANNEL_SOCKET, session->socket); + session->channel->io = session->server->network; + + /* Init session request list */ + mk_list_init(&session->request_list); + + /* Initialize the parser */ + mk_http_parser_init(&session->parser); +} + +static void splunk_conn_request_init(struct mk_http_session *session, + struct mk_http_request *request) +{ + memset(request, 0, sizeof(struct mk_http_request)); + + mk_http_request_init(session, request, session->server); + + request->in_headers.type = MK_STREAM_IOV; + request->in_headers.dynamic = MK_FALSE; + request->in_headers.cb_consumed = NULL; + request->in_headers.cb_finished = NULL; + request->in_headers.stream = &request->stream; + + mk_list_add(&request->in_headers._head, &request->stream.inputs); + + request->session = session; +} + +struct splunk_conn *splunk_conn_add(struct flb_connection *connection, + struct flb_splunk *ctx) +{ + struct splunk_conn *conn; + int ret; + + conn = flb_calloc(1, sizeof(struct splunk_conn)); + if (!conn) { + flb_errno(); + return NULL; + } + + conn->connection = connection; + + /* Set data for the event-loop */ + MK_EVENT_NEW(&connection->event); + + connection->user_data = conn; + connection->event.type = FLB_ENGINE_EV_CUSTOM; + connection->event.handler = splunk_conn_event; + + /* Connection info */ + conn->ctx = ctx; + conn->buf_len = 0; + + conn->buf_data = flb_malloc(ctx->buffer_chunk_size); + if (!conn->buf_data) { + flb_errno(); + + flb_plg_error(ctx->ins, "could not allocate new connection"); + flb_free(conn); + + return NULL; + } + conn->buf_size = ctx->buffer_chunk_size; + + /* Register instance into the event loop */ + ret = mk_event_add(flb_engine_evl_get(), + connection->fd, + FLB_ENGINE_EV_CUSTOM, + MK_EVENT_READ, + &connection->event); + if (ret == -1) { + flb_plg_error(ctx->ins, "could not register new connection"); + + flb_free(conn->buf_data); + flb_free(conn); + + return NULL; + } + + /* Initialize HTTP Session: this is a custom context for Monkey HTTP */ + splunk_conn_session_init(&conn->session, ctx->server, conn->connection->fd); + + /* Initialize HTTP Request: this is the initial request and it will be reinitialized + * automatically after the request is handled so it can be used for the next one. + */ + splunk_conn_request_init(&conn->session, &conn->request); + + /* Link connection node to parent context list */ + mk_list_add(&conn->_head, &ctx->connections); + + return conn; +} + +int splunk_conn_del(struct splunk_conn *conn) +{ + if (conn->session.channel != NULL) { + mk_channel_release(conn->session.channel); + } + + /* The downstream unregisters the file descriptor from the event-loop + * so there's nothing to be done by the plugin + */ + flb_downstream_conn_release(conn->connection); + + mk_list_del(&conn->_head); + + flb_free(conn->buf_data); + flb_free(conn); + + return 0; +} + +void splunk_conn_release_all(struct flb_splunk *ctx) +{ + struct mk_list *tmp; + struct mk_list *head; + struct splunk_conn *conn; + + mk_list_foreach_safe(head, tmp, &ctx->connections) { + conn = mk_list_entry(head, struct splunk_conn, _head); + splunk_conn_del(conn); + } +} diff --git a/plugins/in_splunk/splunk_conn.h b/plugins/in_splunk/splunk_conn.h new file mode 100644 index 00000000000..f4c955fc0b0 --- /dev/null +++ b/plugins/in_splunk/splunk_conn.h @@ -0,0 +1,54 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Fluent Bit + * ========== + * Copyright (C) 2015-2022 The Fluent Bit Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLB_IN_SPLUNK_CONN +#define FLB_IN_SPLUNK_CONN + +#include +#include + +#include +#include +#include + +struct splunk_conn { + /* Buffer */ + char *buf_data; /* Buffer data */ + int buf_len; /* Data length */ + int buf_size; /* Buffer size */ + + /* + * Parser context: we only held one parser per connection + * which is re-used everytime we have a new request. + */ + struct mk_http_parser parser; + struct mk_http_request request; + struct mk_http_session session; + struct flb_connection *connection; + + void *ctx; /* Plugin parent context */ + struct mk_list _head; /* link to flb_http->connections */ +}; + +struct splunk_conn *splunk_conn_add(struct flb_connection *connection, struct flb_splunk *ctx); +int splunk_conn_del(struct splunk_conn *conn); +void splunk_conn_release_all(struct flb_splunk *ctx); + + +#endif diff --git a/plugins/in_splunk/splunk_prot.c b/plugins/in_splunk/splunk_prot.c new file mode 100644 index 00000000000..82afa6efc83 --- /dev/null +++ b/plugins/in_splunk/splunk_prot.c @@ -0,0 +1,785 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Fluent Bit + * ========== + * Copyright (C) 2015-2022 The Fluent Bit Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include "splunk.h" +#include "splunk_conn.h" +#include "splunk_prot.h" + +#define HTTP_CONTENT_JSON 0 +#define HTTP_CONTENT_TEXT 1 +#define HTTP_CONTENT_UNKNOWN 2 + +static int send_response(struct splunk_conn *conn, int http_status, char *message) +{ + struct flb_splunk *context; + size_t sent; + int len; + flb_sds_t out; + + context = (struct flb_splunk *) conn->ctx; + + out = flb_sds_create_size(256); + if (!out) { + return -1; + } + + if (message) { + len = strlen(message); + } + else { + len = 0; + } + + if (http_status == 201) { + flb_sds_printf(&out, + "HTTP/1.1 201 Created \r\n" + "Server: Fluent Bit v%s\r\n" + "%s" + "Content-Length: 0\r\n\r\n", + FLB_VERSION_STR, + context->success_headers_str); + } + else if (http_status == 200) { + flb_sds_printf(&out, + "HTTP/1.1 200 OK\r\n" + "Server: Fluent Bit v%s\r\n" + "%s" + "Content-Length: 0\r\n\r\n", + FLB_VERSION_STR, + context->success_headers_str); + } + else if (http_status == 204) { + flb_sds_printf(&out, + "HTTP/1.1 204 No Content\r\n" + "Server: Fluent Bit v%s\r\n" + "%s" + "\r\n\r\n", + FLB_VERSION_STR, + context->success_headers_str); + } + else if (http_status == 400) { + flb_sds_printf(&out, + "HTTP/1.1 400 Forbidden\r\n" + "Server: Fluent Bit v%s\r\n" + "Content-Length: %i\r\n\r\n%s", + FLB_VERSION_STR, + len, message); + } + else if (http_status == 401) { + flb_sds_printf(&out, + "HTTP/1.1 401 Unauthorized\r\n" + "Server: Fluent Bit v%s\r\n" + "Content-Length: %i\r\n\r\n%s", + FLB_VERSION_STR, + len, message); + } + /* We should check this operations result */ + flb_io_net_write(conn->connection, + (void *) out, + flb_sds_len(out), + &sent); + + flb_sds_destroy(out); + + return 0; +} + +static int send_json_message_response(struct splunk_conn *conn, int http_status, char *message) +{ + size_t sent; + int len; + flb_sds_t out; + + out = flb_sds_create_size(256); + if (!out) { + return -1; + } + + if (message) { + len = strlen(message); + } + else { + len = 0; + } + + if (http_status == 200) { + flb_sds_printf(&out, + "HTTP/1.1 200 OK\r\n" + "Content-Type: application/json\r\n" + "Content-Length: %i\r\n\r\n%s", + len, message); + } + + /* We should check this operations result */ + flb_io_net_write(conn->connection, + (void *) out, + flb_sds_len(out), + &sent); + + flb_sds_destroy(out); + + return 0; +} + +/* implements functionality to get tag from key in record */ +static flb_sds_t tag_key(struct flb_splunk *ctx, msgpack_object *map) +{ + size_t map_size = map->via.map.size; + msgpack_object_kv *kv; + msgpack_object key; + msgpack_object val; + char *key_str = NULL; + char *val_str = NULL; + size_t key_str_size = 0; + size_t val_str_size = 0; + int j; + int check = FLB_FALSE; + int found = FLB_FALSE; + flb_sds_t tag; + + kv = map->via.map.ptr; + + for(j=0; j < map_size; j++) { + check = FLB_FALSE; + found = FLB_FALSE; + key = (kv+j)->key; + if (key.type == MSGPACK_OBJECT_BIN) { + key_str = (char *) key.via.bin.ptr; + key_str_size = key.via.bin.size; + check = FLB_TRUE; + } + if (key.type == MSGPACK_OBJECT_STR) { + key_str = (char *) key.via.str.ptr; + key_str_size = key.via.str.size; + check = FLB_TRUE; + } + + if (check == FLB_TRUE) { + if (strncmp(ctx->tag_key, key_str, key_str_size) == 0) { + val = (kv+j)->val; + if (val.type == MSGPACK_OBJECT_BIN) { + val_str = (char *) val.via.bin.ptr; + val_str_size = val.via.str.size; + found = FLB_TRUE; + break; + } + if (val.type == MSGPACK_OBJECT_STR) { + val_str = (char *) val.via.str.ptr; + val_str_size = val.via.str.size; + found = FLB_TRUE; + break; + } + } + } + } + + if (found == FLB_TRUE) { + tag = flb_sds_create_len(val_str, val_str_size); + if (!tag) { + flb_errno(); + return NULL; + } + return tag; + } + + + flb_plg_error(ctx->ins, "Could not find tag_key %s in record", ctx->tag_key); + return NULL; +} + +/* + * Process a raw text payload for Splunk HEC requests, uses the delimited character to split records, + * return the number of processed bytes + */ +static int process_raw_payload_pack(struct flb_splunk *ctx, flb_sds_t tag, char *buf, size_t size) +{ + int ret = FLB_EVENT_ENCODER_SUCCESS; + + ret = flb_log_event_encoder_begin_record(&ctx->log_encoder); + + if (ret == FLB_EVENT_ENCODER_SUCCESS) { + ret = flb_log_event_encoder_set_current_timestamp(&ctx->log_encoder); + } + + if (ret == FLB_EVENT_ENCODER_SUCCESS) { + ret = flb_log_event_encoder_append_body_values( + &ctx->log_encoder, + FLB_LOG_EVENT_CSTRING_VALUE("log"), + FLB_LOG_EVENT_STRING_VALUE(buf, size)); + } + + if (ret == FLB_EVENT_ENCODER_SUCCESS) { + ret = flb_log_event_encoder_commit_record(&ctx->log_encoder); + } + + if (ret != FLB_EVENT_ENCODER_SUCCESS) { + flb_log_event_encoder_rollback_record(&ctx->log_encoder); + return -1; + } + + if (ret == FLB_EVENT_ENCODER_SUCCESS) { + if (tag) { + flb_input_log_append(ctx->ins, tag, flb_sds_len(tag), + ctx->log_encoder.output_buffer, + ctx->log_encoder.output_length); + } + else { + /* use default plugin Tag (it internal name, e.g: http.0 */ + flb_input_log_append(ctx->ins, NULL, 0, + ctx->log_encoder.output_buffer, + ctx->log_encoder.output_length); + } + } + else { + flb_plg_error(ctx->ins, "log event encoding error : %d", ret); + } + + return 0; +} + +static void process_flb_log_append(struct flb_splunk *ctx, msgpack_object *record, + flb_sds_t tag, flb_sds_t tag_from_record, + struct flb_time tm) { + int ret; + + ret = flb_log_event_encoder_begin_record(&ctx->log_encoder); + + if (ret == FLB_EVENT_ENCODER_SUCCESS) { + ret = flb_log_event_encoder_set_timestamp( + &ctx->log_encoder, + &tm); + } + + if (ret == FLB_EVENT_ENCODER_SUCCESS) { + ret = flb_log_event_encoder_set_body_from_msgpack_object( + &ctx->log_encoder, + record); + } + + if (ret == FLB_EVENT_ENCODER_SUCCESS) { + ret = flb_log_event_encoder_commit_record(&ctx->log_encoder); + } + + if (ret == FLB_EVENT_ENCODER_SUCCESS) { + if (tag_from_record) { + flb_input_log_append(ctx->ins, + tag_from_record, + flb_sds_len(tag_from_record), + ctx->log_encoder.output_buffer, + ctx->log_encoder.output_length); + + flb_sds_destroy(tag_from_record); + } + else if (tag) { + flb_input_log_append(ctx->ins, tag, flb_sds_len(tag), + ctx->log_encoder.output_buffer, + ctx->log_encoder.output_length); + } + else { + /* use default plugin Tag (it internal name, e.g: http.0 */ + flb_input_log_append(ctx->ins, NULL, 0, + ctx->log_encoder.output_buffer, + ctx->log_encoder.output_length); + } + } + else { + flb_plg_error(ctx->ins, "Error encoding record : %d", ret); + } +} + +static int process_json_payload_pack(struct flb_splunk *ctx, flb_sds_t tag, char *buf, size_t size) +{ + int ret; + size_t off = 0; + msgpack_unpacked result; + struct flb_time tm; + int i = 0; + msgpack_object *obj; + msgpack_object record; + flb_sds_t tag_from_record = NULL; + + flb_time_get(&tm); + + msgpack_unpacked_init(&result); + while (msgpack_unpack_next(&result, buf, size, &off) == MSGPACK_UNPACK_SUCCESS) { + if (result.data.type == MSGPACK_OBJECT_MAP) { + tag_from_record = NULL; + if (ctx->tag_key) { + tag_from_record = tag_key(ctx, &result.data); + } + + process_flb_log_append(ctx, &result.data, tag, tag_from_record, tm); + + flb_log_event_encoder_reset(&ctx->log_encoder); + } + else if (result.data.type == MSGPACK_OBJECT_ARRAY) { + obj = &result.data; + for (i = 0; i < obj->via.array.size; i++) + { + record = obj->via.array.ptr[i]; + + tag_from_record = NULL; + if (ctx->tag_key) { + tag_from_record = tag_key(ctx, &record); + } + + process_flb_log_append(ctx, &record, tag, tag_from_record, tm); + + /* TODO : Optimize this + * + * This is wasteful, considering that we are emitting a series + * of records we should start and commit each one and then + * emit them all at once after the loop. + */ + + flb_log_event_encoder_reset(&ctx->log_encoder); + } + + break; + } + else { + flb_plg_error(ctx->ins, "skip record from invalid type: %i", + result.data.type); + + msgpack_unpacked_destroy(&result); + + return -1; + } + } + + msgpack_unpacked_destroy(&result); + + return 0; +} + +static ssize_t parse_hec_payload_json(struct flb_splunk *ctx, flb_sds_t tag, + char *payload, size_t size) +{ + int ret; + int out_size; + char *pack; + struct flb_pack_state pack_state; + + /* Initialize packer */ + flb_pack_state_init(&pack_state); + + /* Pack JSON as msgpack */ + ret = flb_pack_json_state(payload, size, + &pack, &out_size, &pack_state); + flb_pack_state_reset(&pack_state); + + /* Handle exceptions */ + if (ret == FLB_ERR_JSON_PART) { + flb_plg_warn(ctx->ins, "JSON data is incomplete, skipping"); + return -1; + } + else if (ret == FLB_ERR_JSON_INVAL) { + flb_plg_warn(ctx->ins, "invalid JSON message, skipping"); + return -1; + } + else if (ret == -1) { + return -1; + } + + /* Process the packaged JSON and return the last byte used */ + process_json_payload_pack(ctx, tag, pack, out_size); + flb_free(pack); + + return 0; +} + +static int validate_auth_header(struct flb_splunk *ctx, struct mk_http_request *request) +{ + struct mk_http_header *auth_header = NULL; + + if (ctx->auth_header == NULL) { + return SPLUNK_AUTH_UNAUTH; + } + + auth_header = mk_http_header_get(MK_HEADER_AUTHORIZATION, request, NULL, 0); + + if (auth_header == NULL) { + return SPLUNK_AUTH_MISSING_CRED; + } + + if (auth_header != NULL && auth_header->val.len > 0) { + if (strncmp(ctx->auth_header, + auth_header->val.data, + strlen(ctx->auth_header)) == 0) { + return SPLUNK_AUTH_SUCCESS; + } + else { + return SPLUNK_AUTH_UNAUTHORIZED; + } + } + else { + return SPLUNK_AUTH_MISSING_CRED; + } + + return SPLUNK_AUTH_SUCCESS; +} + +static int handle_hec_payload(struct flb_splunk *ctx, int content_type, + flb_sds_t tag, char *buf, size_t size) +{ + int ret; + + if (content_type == HTTP_CONTENT_JSON) { + ret = parse_hec_payload_json(ctx, tag, buf, size); + } + else if (content_type == HTTP_CONTENT_TEXT) { + ret = process_raw_payload_pack(ctx, tag, buf, size); + } + else if (content_type == HTTP_CONTENT_UNKNOWN) { + if (buf[0] == '{') { + ret = parse_hec_payload_json(ctx, tag, buf, size); + } + else { + ret = process_raw_payload_pack(ctx, tag, buf, size); + } + } + + return ret; +} + +static int process_hec_payload(struct flb_splunk *ctx, struct splunk_conn *conn, + flb_sds_t tag, + struct mk_http_session *session, + struct mk_http_request *request) +{ + int i = 0; + int ret = 0; + int type = -1; + struct mk_http_header *header; + int extra_size = -1; + struct mk_http_header *headers_extra; + int gzip_compressed = FLB_FALSE; + void *gz_data = NULL; + size_t gz_size = -1; + + header = &session->parser.headers[MK_HEADER_CONTENT_TYPE]; + if (header->key.data == NULL) { + send_response(conn, 400, "error: header 'Content-Type' is not set\n"); + return -1; + } + + if (header->val.len == 16 && + strncasecmp(header->val.data, "application/json", 16) == 0) { + type = HTTP_CONTENT_JSON; + } + else if (header->val.len == 10 && + strncasecmp(header->val.data, "text/plain", 10) == 0) { + type = HTTP_CONTENT_TEXT; + } + else { + /* Not neccesary to specify content-type for Splunk HEC. */ + flb_plg_debug(ctx->ins, "Mark as unknown type for ingested payloads"); + type = HTTP_CONTENT_UNKNOWN; + } + + if (request->data.len <= 0) { + send_response(conn, 400, "error: no payload found\n"); + return -1; + } + + extra_size = session->parser.headers_extra_count; + if (extra_size > 0) { + for (i = 0; i < extra_size; i++) { + headers_extra = &session->parser.headers_extra[i]; + if (headers_extra->key.len == 16 && + strncasecmp(headers_extra->key.data, "Content-Encoding", 16) == 0) { + if (headers_extra->val.len == 4 && + strncasecmp(headers_extra->val.data, "gzip", 4) == 0) { + flb_plg_debug(ctx->ins, "body is gzipped"); + gzip_compressed = FLB_TRUE; + } + } + } + } + + if (gzip_compressed == FLB_TRUE) { + ret = flb_gzip_uncompress((void *) request->data.data, request->data.len, + &gz_data, &gz_size); + if (ret == -1) { + flb_plg_error(ctx->ins, "gzip uncompress is failed"); + return -1; + } + + ret = handle_hec_payload(ctx, type, tag, gz_data, gz_size); + flb_free(gz_data); + } + else { + ret = handle_hec_payload(ctx, type, tag, request->data.data, request->data.len); + } + + return 0; +} + +static int process_hec_raw_payload(struct flb_splunk *ctx, struct splunk_conn *conn, + flb_sds_t tag, + struct mk_http_session *session, + struct mk_http_request *request) +{ + int ret = -1; + int type = -1; + struct mk_http_header *header; + + header = &session->parser.headers[MK_HEADER_CONTENT_TYPE]; + if (header->key.data == NULL) { + send_response(conn, 400, "error: header 'Content-Type' is not set\n"); + return -1; + } + else if (header->val.len == 10 && + strncasecmp(header->val.data, "text/plain", 10) == 0) { + type = HTTP_CONTENT_TEXT; + } + else { + /* Not neccesary to specify content-type for Splunk HEC. */ + flb_plg_debug(ctx->ins, "Mark as unknown type for ingested payloads"); + type = HTTP_CONTENT_UNKNOWN; + } + + if (request->data.len <= 0) { + send_response(conn, 400, "error: no payload found\n"); + return -1; + } + + /* Always handle as raw type of payloads here */ + ret = process_raw_payload_pack(ctx, tag, request->data.data, request->data.len); + + return ret; +} + +static inline int mk_http_point_header(mk_ptr_t *h, + struct mk_http_parser *parser, int key) +{ + struct mk_http_header *header; + + header = &parser->headers[key]; + if (header->type == key) { + h->data = header->val.data; + h->len = header->val.len; + return 0; + } + else { + h->data = NULL; + h->len = -1; + } + + return -1; +} + +/* + * Handle an incoming request. It perform extra checks over the request, if + * everything is OK, it enqueue the incoming payload. + */ +int splunk_prot_handle(struct flb_splunk *ctx, struct splunk_conn *conn, + struct mk_http_session *session, + struct mk_http_request *request) +{ + int i; + int ret; + int len; + char *uri; + char *qs; + off_t diff; + flb_sds_t tag; + struct mk_http_header *header; + + if (request->uri.data[0] != '/') { + send_response(conn, 400, "error: invalid request\n"); + return -1; + } + + /* Decode URI */ + uri = mk_utils_url_decode(request->uri); + if (!uri) { + uri = mk_mem_alloc_z(request->uri.len + 1); + if (!uri) { + return -1; + } + memcpy(uri, request->uri.data, request->uri.len); + uri[request->uri.len] = '\0'; + } + + /* Try to match a query string so we can remove it */ + qs = strchr(uri, '?'); + if (qs) { + /* remove the query string part */ + diff = qs - uri; + uri[diff] = '\0'; + } + + /* Refer the tag at first*/ + if (ctx->ins->tag && !ctx->ins->tag_default) { + tag = flb_sds_create(ctx->ins->tag); + if (tag == NULL) { + return -1; + } + } + else { + /* Compose the query string using the URI */ + len = strlen(uri); + + if (len == 1) { + tag = NULL; /* use default tag */ + } + else { + /* New tag skipping the URI '/' */ + tag = flb_sds_create_len(&uri[1], len - 1); + if (!tag) { + mk_mem_free(uri); + return -1; + } + + /* Sanitize, only allow alphanum chars */ + for (i = 0; i < flb_sds_len(tag); i++) { + if (!isalnum(tag[i]) && tag[i] != '_' && tag[i] != '.') { + tag[i] = '_'; + } + } + } + } + + /* Check if we have a Host header: Hostname ; port */ + mk_http_point_header(&request->host, &session->parser, MK_HEADER_HOST); + + /* Header: Connection */ + mk_http_point_header(&request->connection, &session->parser, + MK_HEADER_CONNECTION); + + /* HTTP/1.1 needs Host header */ + if (request->host.data == NULL && request->protocol == MK_HTTP_PROTOCOL_11) { + flb_sds_destroy(tag); + mk_mem_free(uri); + + return -1; + } + + /* Should we close the session after this request ? */ + mk_http_keepalive_check(session, request, ctx->server); + + /* Content Length */ + header = &session->parser.headers[MK_HEADER_CONTENT_LENGTH]; + if (header->type == MK_HEADER_CONTENT_LENGTH) { + request->_content_length.data = header->val.data; + request->_content_length.len = header->val.len; + } + else { + request->_content_length.data = NULL; + } + + if (request->method == MK_METHOD_GET) { + /* Handle health minotoring of splunk hec endpoint for load balancers */ + if (strcasecmp(uri, "/services/collector/health") == 0) { + send_json_message_response(conn, 200, "{\"text\":\"Success\",\"code\":200}"); + } + else { + send_response(conn, 400, "error: invalid HTTP endpoint\n"); + } + + flb_sds_destroy(tag); + mk_mem_free(uri); + + return 0; + } + + /* Under services/collector endpoints are required for + * authentication if provided splunk_token */ + ret = validate_auth_header(ctx, request); + if (ret < 0){ + send_response(conn, 401, "error: unauthroized\n"); + if (ret == SPLUNK_AUTH_MISSING_CRED) { + flb_plg_warn(ctx->ins, "missing credentials in request headers", ret); + } + else if (ret == SPLUNK_AUTH_UNAUTHORIZED) { + flb_plg_warn(ctx->ins, "wrong credentials in request headers", ret); + } + + flb_sds_destroy(tag); + mk_mem_free(uri); + + return -1; + } + + /* Handle every ingested payload cleanly */ + flb_log_event_encoder_reset(&ctx->log_encoder); + + if (request->method == MK_METHOD_POST) { + if (strcasecmp(uri, "/services/collector/raw") == 0) { + ret = process_hec_raw_payload(ctx, conn, tag, session, request); + + if (!ret) { + send_json_message_response(conn, 400, "{\"text\":\"Invalid data format\",\"code\":6}"); + } + send_json_message_response(conn, 200, "{\"text\":\"Success\",\"code\":0}"); + } + else if (strcasecmp(uri, "/services/collector/event") == 0 || + strcasecmp(uri, "/services/collector") == 0) { + ret = process_hec_payload(ctx, conn, tag, session, request); + + if (!ret) { + send_json_message_response(conn, 400, "{\"text\":\"Invalid data format\",\"code\":6}"); + } + send_json_message_response(conn, 200, "{\"text\":\"Success\",\"code\":0}"); + } + else { + send_response(conn, 400, "error: invalid HTTP endpoint\n"); + + flb_sds_destroy(tag); + mk_mem_free(uri); + + return -1; + } + } + else { + /* HEAD, PUT, PATCH, and DELETE methods are prohibited to use.*/ + + flb_sds_destroy(tag); + mk_mem_free(uri); + + send_response(conn, 400, "error: invalid HTTP method\n"); + return -1; + } + + flb_sds_destroy(tag); + mk_mem_free(uri); + + return ret; +} + +/* + * Handle an incoming request which has resulted in an http parser error. + */ +int splunk_prot_handle_error(struct flb_splunk *ctx, struct splunk_conn *conn, + struct mk_http_session *session, + struct mk_http_request *request) +{ + send_response(conn, 400, "error: invalid request\n"); + return -1; +} diff --git a/plugins/in_splunk/splunk_prot.h b/plugins/in_splunk/splunk_prot.h new file mode 100644 index 00000000000..100f12d2e5b --- /dev/null +++ b/plugins/in_splunk/splunk_prot.h @@ -0,0 +1,36 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Fluent Bit + * ========== + * Copyright (C) 2015-2022 The Fluent Bit Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLB_IN_SPLUNK_PROT +#define FLB_IN_SPLUNK_PROT + +#define SPLUNK_AUTH_UNAUTH 1 +#define SPLUNK_AUTH_SUCCESS 0 +#define SPLUNK_AUTH_MISSING_CRED -1 +#define SPLUNK_AUTH_UNAUTHORIZED -2 + +int splunk_prot_handle(struct flb_splunk *ctx, struct splunk_conn *conn, + struct mk_http_session *session, + struct mk_http_request *request); + +int splunk_prot_handle_error(struct flb_splunk *ctx, struct splunk_conn *conn, + struct mk_http_session *session, + struct mk_http_request *request); + +#endif diff --git a/tests/runtime/CMakeLists.txt b/tests/runtime/CMakeLists.txt index 6e7c3e59c00..125b0055b83 100644 --- a/tests/runtime/CMakeLists.txt +++ b/tests/runtime/CMakeLists.txt @@ -48,6 +48,7 @@ if(FLB_OUT_LIB) FLB_RT_TEST(FLB_IN_OPENTELEMETRY "in_opentelemetry.c") FLB_RT_TEST(FLB_IN_RANDOM "in_random.c") FLB_RT_TEST(FLB_IN_STATSD "in_statsd.c") + FLB_RT_TEST(FLB_IN_SPLUNK "in_splunk.c") FLB_RT_TEST(FLB_IN_SYSLOG "in_syslog.c") FLB_RT_TEST(FLB_IN_TAIL "in_tail.c") FLB_RT_TEST(FLB_IN_TCP "in_tcp.c") diff --git a/tests/runtime/in_splunk.c b/tests/runtime/in_splunk.c new file mode 100644 index 00000000000..bba4977c4c9 --- /dev/null +++ b/tests/runtime/in_splunk.c @@ -0,0 +1,824 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Fluent Bit + * ========== + * Copyright (C) 2019-2023 The Fluent Bit Authors + * Copyright (C) 2015-2018 Treasure Data Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "flb_tests_runtime.h" + +#define JSON_CONTENT_TYPE "application/json" + +struct in_splunk_client_ctx { + struct flb_upstream *u; + struct flb_connection *u_conn; + struct flb_config *config; + struct mk_event_loop *evl; +}; + +struct test_ctx { + flb_ctx_t *flb; /* Fluent Bit library context */ + int i_ffd; /* Input fd */ + int f_ffd; /* Filter fd (unused) */ + int o_ffd; /* Output fd */ + struct in_splunk_client_ctx *httpc; +}; + + +pthread_mutex_t result_mutex = PTHREAD_MUTEX_INITIALIZER; +int num_output = 0; +static int get_output_num() +{ + int ret; + pthread_mutex_lock(&result_mutex); + ret = num_output; + pthread_mutex_unlock(&result_mutex); + + return ret; +} + +static void set_output_num(int num) +{ + pthread_mutex_lock(&result_mutex); + num_output = num; + pthread_mutex_unlock(&result_mutex); +} + +static void clear_output_num() +{ + set_output_num(0); +} + +/* Callback to check expected results */ +static int cb_check_result_json(void *record, size_t size, void *data) +{ + char *p; + char *expected; + char *result; + int num = get_output_num(); + + set_output_num(num+1); + + expected = (char *) data; + result = (char *) record; + + p = strstr(result, expected); + TEST_CHECK(p != NULL); + + if (p==NULL) { + flb_error("Expected to find: '%s' in result '%s'", + expected, result); + } + /* + * If you want to debug your test + * + * printf("Expect: '%s' in result '%s'", expected, result); + */ + flb_free(record); + return 0; +} + +struct in_splunk_client_ctx* splunk_client_ctx_create(int port) +{ + struct in_splunk_client_ctx *ret_ctx = NULL; + struct mk_event_loop *evl = NULL; + + ret_ctx = flb_calloc(1, sizeof(struct in_splunk_client_ctx)); + if (!TEST_CHECK(ret_ctx != NULL)) { + flb_errno(); + TEST_MSG("flb_calloc(splunk_client_ctx) failed"); + return NULL; + } + + evl = mk_event_loop_create(16); + if (!TEST_CHECK(evl != NULL)) { + TEST_MSG("mk_event_loop failed"); + flb_free(ret_ctx); + return NULL; + } + ret_ctx->evl = evl; + flb_engine_evl_init(); + flb_engine_evl_set(evl); + + ret_ctx->config = flb_config_init(); + if(!TEST_CHECK(ret_ctx->config != NULL)) { + TEST_MSG("flb_config_init failed"); + mk_event_loop_destroy(evl); + flb_free(ret_ctx); + return NULL; + } + + ret_ctx->u = flb_upstream_create(ret_ctx->config, "127.0.0.1", port, 0, NULL); + if (!TEST_CHECK(ret_ctx->u != NULL)) { + TEST_MSG("flb_upstream_create failed"); + flb_config_exit(ret_ctx->config); + mk_event_loop_destroy(evl); + flb_free(ret_ctx); + return NULL; + } + + ret_ctx->u_conn = flb_upstream_conn_get(ret_ctx->u); + TEST_CHECK(ret_ctx->u_conn != NULL); + + ret_ctx->u_conn->upstream = ret_ctx->u; + + return ret_ctx; +} + +static struct test_ctx *test_ctx_create(struct flb_lib_out_cb *data) +{ + int i_ffd; + int o_ffd; + struct test_ctx *ctx = NULL; + + ctx = flb_calloc(1, sizeof(struct test_ctx)); + if (!TEST_CHECK(ctx != NULL)) { + TEST_MSG("flb_calloc failed"); + flb_errno(); + return NULL; + } + + /* Service config */ + ctx->flb = flb_create(); + flb_service_set(ctx->flb, + "Flush", "0.200000000", + "Grace", "1", + "Log_Level", "error", + NULL); + + /* Input */ + i_ffd = flb_input(ctx->flb, (char *) "splunk", NULL); + TEST_CHECK(i_ffd >= 0); + ctx->i_ffd = i_ffd; + + /* Output */ + o_ffd = flb_output(ctx->flb, (char *) "lib", (void *) data); + ctx->o_ffd = o_ffd; + + return ctx; +} + +int splunk_client_ctx_destroy(struct in_splunk_client_ctx* ctx) +{ + if (!TEST_CHECK(ctx != NULL)) { + return -1; + } + if (ctx->u) { + flb_upstream_destroy(ctx->u); + } + if (ctx->config) { + flb_config_exit(ctx->config); + } + if (ctx->evl) { + mk_event_loop_destroy(ctx->evl); + } + + flb_free(ctx); + return 0; +} + +static void test_ctx_destroy(struct test_ctx *ctx) +{ + TEST_CHECK(ctx != NULL); + if (ctx->httpc) { + splunk_client_ctx_destroy(ctx->httpc); + } + + sleep(1); + flb_stop(ctx->flb); + flb_destroy(ctx->flb); + flb_free(ctx); +} + +void flb_test_splunk_health() +{ + struct flb_lib_out_cb cb_data; + struct test_ctx *ctx; + struct flb_http_client *c; + int ret; + size_t b_sent; + char *expected = "{\"text\":\"Success\",\"code\":200}"; + char *buf = NULL; + int port = 8808; + char sport[16]; + + snprintf(sport, 16, "%d", port); + + ctx = test_ctx_create(&cb_data); + if (!TEST_CHECK(ctx != NULL)) { + TEST_MSG("test_ctx_create failed"); + exit(EXIT_FAILURE); + } + + ret = flb_input_set(ctx->flb, ctx->i_ffd, + "port", sport, + NULL); + TEST_CHECK(ret == 0); + + ret = flb_output_set(ctx->flb, ctx->o_ffd, + "match", "*", + "format", "json", + NULL); + TEST_CHECK(ret == 0); + + /* Start the engine */ + ret = flb_start(ctx->flb); + TEST_CHECK(ret == 0); + + ctx->httpc = splunk_client_ctx_create(port); + TEST_CHECK(ctx->httpc != NULL); + + c = flb_http_client(ctx->httpc->u_conn, FLB_HTTP_GET, "/services/collector/health", NULL, 0, + "127.0.0.1", port, NULL, 0); + if (!TEST_CHECK(c != NULL)) { + TEST_MSG("splunk_client failed"); + exit(EXIT_FAILURE); + } + + ret = flb_http_do(c, &b_sent); + if (!TEST_CHECK(ret == 0)) { + TEST_MSG("ret error. ret=%d\n", ret); + } + else if (!TEST_CHECK(b_sent > 0)){ + TEST_MSG("b_sent size error. b_sent = %lu\n", b_sent); + } + else if (!TEST_CHECK(c->resp.status == 200)) { + TEST_MSG("http response code error. expect: 200, got: %d\n", c->resp.status); + } + + /* waiting to flush */ + flb_time_msleep(1500); + + buf = strstr(c->resp.payload, expected); + if (!TEST_CHECK(buf != NULL)) { + TEST_MSG("http request for version info failed"); + } + flb_http_client_destroy(c); + flb_upstream_conn_release(ctx->httpc->u_conn); + test_ctx_destroy(ctx); +} + +void flb_test_splunk(int port, char *endpoint) +{ + struct flb_lib_out_cb cb_data; + struct test_ctx *ctx; + struct flb_http_client *c; + int ret; + int num; + size_t b_sent; + char *buf = "{\"event\": \"Pony 1 has left the barn\"}{\"event\": \"Pony 2 has left the barn\"}{\"event\": \"Pony 3 has left the barn\", \"nested\": {\"key1\": \"value1\"}}"; + char *expected = "\"event\":"; + char sport[16]; + flb_sds_t target; + + target = flb_sds_create_size(64); + flb_sds_cat(target, endpoint, strlen(endpoint)); + + snprintf(sport, 16, "%d", port); + + clear_output_num(); + + cb_data.cb = cb_check_result_json; + cb_data.data = expected; + + ctx = test_ctx_create(&cb_data); + if (!TEST_CHECK(ctx != NULL)) { + TEST_MSG("test_ctx_create failed"); + exit(EXIT_FAILURE); + } + + ret = flb_input_set(ctx->flb, ctx->i_ffd, + "port", sport, + NULL); + TEST_CHECK(ret == 0); + + ret = flb_output_set(ctx->flb, ctx->o_ffd, + "match", "*", + "format", "json", + NULL); + TEST_CHECK(ret == 0); + + /* Start the engine */ + ret = flb_start(ctx->flb); + TEST_CHECK(ret == 0); + + ctx->httpc = splunk_client_ctx_create(port); + TEST_CHECK(ctx->httpc != NULL); + + c = flb_http_client(ctx->httpc->u_conn, FLB_HTTP_POST, target, buf, strlen(buf), + "127.0.0.1", port, NULL, 0); + ret = flb_http_add_header(c, FLB_HTTP_HEADER_CONTENT_TYPE, strlen(FLB_HTTP_HEADER_CONTENT_TYPE), + JSON_CONTENT_TYPE, strlen(JSON_CONTENT_TYPE)); + TEST_CHECK(ret == 0); + if (!TEST_CHECK(c != NULL)) { + TEST_MSG("splunk_client failed"); + exit(EXIT_FAILURE); + } + + ret = flb_http_do(c, &b_sent); + if (!TEST_CHECK(ret == 0)) { + TEST_MSG("ret error. ret=%d\n", ret); + } + else if (!TEST_CHECK(b_sent > 0)){ + TEST_MSG("b_sent size error. b_sent = %lu\n", b_sent); + } + else if (!TEST_CHECK(c->resp.status == 200)) { + TEST_MSG("http response code error. expect: 200, got: %d\n", c->resp.status); + } + + /* waiting to flush */ + flb_time_msleep(1500); + + num = get_output_num(); + if (!TEST_CHECK(num > 0)) { + TEST_MSG("no outputs"); + } + flb_sds_destroy(target); + flb_http_client_destroy(c); + flb_upstream_conn_release(ctx->httpc->u_conn); + test_ctx_destroy(ctx); +} + +void flb_test_splunk_collector() +{ + flb_test_splunk(8809, "/services/collector"); +} + +void flb_test_splunk_collector_event() +{ + flb_test_splunk(8810, "/services/collector/event"); +} + +void flb_test_splunk_raw(int port) +{ + struct flb_lib_out_cb cb_data; + struct test_ctx *ctx; + struct flb_http_client *c; + int ret; + int num; + size_t b_sent; + char *buf = "1, 2, 3... Hello, world!"; + char *expected = "\"log\":"; + char sport[16]; + + snprintf(sport, 16, "%d", port); + + clear_output_num(); + + cb_data.cb = cb_check_result_json; + cb_data.data = expected; + + ctx = test_ctx_create(&cb_data); + if (!TEST_CHECK(ctx != NULL)) { + TEST_MSG("test_ctx_create failed"); + exit(EXIT_FAILURE); + } + + ret = flb_input_set(ctx->flb, ctx->i_ffd, + "port", sport, + NULL); + TEST_CHECK(ret == 0); + + ret = flb_output_set(ctx->flb, ctx->o_ffd, + "match", "*", + "format", "json", + NULL); + TEST_CHECK(ret == 0); + + /* Start the engine */ + ret = flb_start(ctx->flb); + TEST_CHECK(ret == 0); + + ctx->httpc = splunk_client_ctx_create(port); + TEST_CHECK(ctx->httpc != NULL); + + c = flb_http_client(ctx->httpc->u_conn, FLB_HTTP_POST, "/services/collector/raw", buf, strlen(buf), + "127.0.0.1", port, NULL, 0); + ret = flb_http_add_header(c, FLB_HTTP_HEADER_CONTENT_TYPE, strlen(FLB_HTTP_HEADER_CONTENT_TYPE), + JSON_CONTENT_TYPE, strlen(JSON_CONTENT_TYPE)); + TEST_CHECK(ret == 0); + if (!TEST_CHECK(c != NULL)) { + TEST_MSG("splunk_client failed"); + exit(EXIT_FAILURE); + } + + ret = flb_http_do(c, &b_sent); + if (!TEST_CHECK(ret == 0)) { + TEST_MSG("ret error. ret=%d\n", ret); + } + else if (!TEST_CHECK(b_sent > 0)){ + TEST_MSG("b_sent size error. b_sent = %lu\n", b_sent); + } + else if (!TEST_CHECK(c->resp.status == 200)) { + TEST_MSG("http response code error. expect: 200, got: %d\n", c->resp.status); + } + + /* waiting to flush */ + flb_time_msleep(1500); + + num = get_output_num(); + if (!TEST_CHECK(num > 0)) { + TEST_MSG("no outputs"); + } + flb_http_client_destroy(c); + flb_upstream_conn_release(ctx->httpc->u_conn); + test_ctx_destroy(ctx); +} + +void flb_test_splunk_collector_raw() +{ + flb_test_splunk_raw(8811); +} + +void flb_test_splunk_raw_multilines(int port) +{ + struct flb_lib_out_cb cb_data; + struct test_ctx *ctx; + struct flb_http_client *c; + int ret; + int num; + size_t b_sent; + char *buf = "127.0.0.1 - admin [28/Sep/2016:09:05:26.875 -0700] \"GET /servicesNS/admin/launcher/data/ui/views?count=-1 HTTP/1.0\" 200 126721 - - - 6ms" \ + "127.0.0.1 - admin [28/Sep/2016:09:05:26.917 -0700] \"GET /servicesNS/admin/launcher/data/ui/nav/default HTTP/1.0\" 200 4367 - - - 6ms" \ + "127.0.0.1 - admin [28/Sep/2016:09:05:26.941 -0700] \"GET /services/apps/local?search=disabled%3Dfalse&count=-1 HTTP/1.0\" 200 31930 - - - 4ms" \ + "127.0.0.1 - admin [28/Sep/2016:09:05:26.954 -0700] \"GET /services/apps/local?search=disabled%3Dfalse&count=-1 HTTP/1.0\" 200 31930 - - - 3ms" \ + "127.0.0.1 - admin [28/Sep/2016:09:05:26.968 -0700] \"GET /servicesNS/admin/launcher/data/ui/views?digest=1&count=-1 HTTP/1.0\" 200 58672 - - - 5ms"; + char *expected = "\"log\":"; + char sport[16]; + + snprintf(sport, 16, "%d", port); + + clear_output_num(); + + cb_data.cb = cb_check_result_json; + cb_data.data = expected; + + ctx = test_ctx_create(&cb_data); + if (!TEST_CHECK(ctx != NULL)) { + TEST_MSG("test_ctx_create failed"); + exit(EXIT_FAILURE); + } + + ret = flb_input_set(ctx->flb, ctx->i_ffd, + "port", sport, + NULL); + TEST_CHECK(ret == 0); + + ret = flb_output_set(ctx->flb, ctx->o_ffd, + "match", "*", + "format", "json", + NULL); + TEST_CHECK(ret == 0); + + /* Start the engine */ + ret = flb_start(ctx->flb); + TEST_CHECK(ret == 0); + + ctx->httpc = splunk_client_ctx_create(port); + TEST_CHECK(ctx->httpc != NULL); + + c = flb_http_client(ctx->httpc->u_conn, FLB_HTTP_POST, "/services/collector/raw", buf, strlen(buf), + "127.0.0.1", port, NULL, 0); + ret = flb_http_add_header(c, FLB_HTTP_HEADER_CONTENT_TYPE, strlen(FLB_HTTP_HEADER_CONTENT_TYPE), + JSON_CONTENT_TYPE, strlen(JSON_CONTENT_TYPE)); + TEST_CHECK(ret == 0); + if (!TEST_CHECK(c != NULL)) { + TEST_MSG("splunk_client failed"); + exit(EXIT_FAILURE); + } + + ret = flb_http_do(c, &b_sent); + if (!TEST_CHECK(ret == 0)) { + TEST_MSG("ret error. ret=%d\n", ret); + } + else if (!TEST_CHECK(b_sent > 0)){ + TEST_MSG("b_sent size error. b_sent = %lu\n", b_sent); + } + else if (!TEST_CHECK(c->resp.status == 200)) { + TEST_MSG("http response code error. expect: 200, got: %d\n", c->resp.status); + } + + /* waiting to flush */ + flb_time_msleep(1500); + + num = get_output_num(); + if (!TEST_CHECK(num > 0)) { + TEST_MSG("no outputs"); + } + flb_http_client_destroy(c); + flb_upstream_conn_release(ctx->httpc->u_conn); + test_ctx_destroy(ctx); +} + +void flb_test_splunk_collector_raw_multilines() +{ + flb_test_splunk_raw_multilines(8812); +} + +void flb_test_splunk_tag_key() +{ + struct flb_lib_out_cb cb_data; + struct test_ctx *ctx; + struct flb_http_client *c; + int ret; + int num; + size_t b_sent; + int port = 8812; + char sport[16]; + + char *buf = "{\"event\": \"Pony 1 has left the barn\",\"tag\":\"new_tag\"}"; + + snprintf(sport, 16, "%d", port); + + clear_output_num(); + + cb_data.cb = cb_check_result_json; + cb_data.data = "\"event\":\"Pony 1 has left the barn\",\"tag\":\"new_tag\""; + + ctx = test_ctx_create(&cb_data); + if (!TEST_CHECK(ctx != NULL)) { + TEST_MSG("test_ctx_create failed"); + exit(EXIT_FAILURE); + } + + ret = flb_input_set(ctx->flb, ctx->i_ffd, + "port", sport, + "tag_key", "tag", + NULL); + TEST_CHECK(ret == 0); + + ret = flb_output_set(ctx->flb, ctx->o_ffd, + "match", "new_tag", + "format", "json", + NULL); + TEST_CHECK(ret == 0); + + /* Start the engine */ + ret = flb_start(ctx->flb); + TEST_CHECK(ret == 0); + + ctx->httpc = splunk_client_ctx_create(port); + TEST_CHECK(ctx->httpc != NULL); + + c = flb_http_client(ctx->httpc->u_conn, FLB_HTTP_POST, "/services/collector", buf, strlen(buf), + "127.0.0.1", port, NULL, 0); + ret = flb_http_add_header(c, FLB_HTTP_HEADER_CONTENT_TYPE, strlen(FLB_HTTP_HEADER_CONTENT_TYPE), + JSON_CONTENT_TYPE, strlen(JSON_CONTENT_TYPE)); + TEST_CHECK(ret == 0); + if (!TEST_CHECK(c != NULL)) { + TEST_MSG("splunk_client failed"); + exit(EXIT_FAILURE); + } + + ret = flb_http_do(c, &b_sent); + if (!TEST_CHECK(ret == 0)) { + TEST_MSG("ret error. ret=%d\n", ret); + } + else if (!TEST_CHECK(b_sent > 0)){ + TEST_MSG("b_sent size error. b_sent = %lu\n", b_sent); + } + else if (!TEST_CHECK(c->resp.status == 200)) { + TEST_MSG("http response code error. expect: 200, got: %d\n", c->resp.status); + } + + /* waiting to flush */ + flb_time_msleep(1500); + + num = get_output_num(); + if (!TEST_CHECK(num > 0)) { + TEST_MSG("no outputs"); + } + flb_http_client_destroy(c); + flb_upstream_conn_release(ctx->httpc->u_conn); + test_ctx_destroy(ctx); +} + +void flb_test_splunk_gzip(int port, char *endpoint) +{ + struct flb_lib_out_cb cb_data; + struct test_ctx *ctx; + struct flb_http_client *c; + int ret; + int num; + size_t b_sent; + char *buf = "{\"event\": \"Pony 1 has left the barn\"}{\"event\": \"Pony 2 has left the barn\"}{\"event\": \"Pony 3 has left the barn\", \"nested\": {\"key1\": \"value1\"}}"; + char *expected = "\"event\":"; + char sport[16]; + flb_sds_t target; + void *final_data; + size_t final_bytes; + + target = flb_sds_create_size(64); + flb_sds_cat(target, endpoint, strlen(endpoint)); + + snprintf(sport, 16, "%d", port); + + clear_output_num(); + + cb_data.cb = cb_check_result_json; + cb_data.data = expected; + + ctx = test_ctx_create(&cb_data); + if (!TEST_CHECK(ctx != NULL)) { + TEST_MSG("test_ctx_create failed"); + exit(EXIT_FAILURE); + } + + ret = flb_input_set(ctx->flb, ctx->i_ffd, + "port", sport, + NULL); + TEST_CHECK(ret == 0); + + ret = flb_output_set(ctx->flb, ctx->o_ffd, + "match", "*", + "format", "json", + NULL); + TEST_CHECK(ret == 0); + + /* Start the engine */ + ret = flb_start(ctx->flb); + TEST_CHECK(ret == 0); + + ctx->httpc = splunk_client_ctx_create(port); + TEST_CHECK(ctx->httpc != NULL); + + ret = flb_gzip_compress((void *) buf, strlen(buf), &final_data, &final_bytes); + TEST_CHECK(ret != -1); + + c = flb_http_client(ctx->httpc->u_conn, FLB_HTTP_POST, target, final_data, final_bytes, + "127.0.0.1", port, NULL, 0); + ret = flb_http_add_header(c, FLB_HTTP_HEADER_CONTENT_TYPE, strlen(FLB_HTTP_HEADER_CONTENT_TYPE), + JSON_CONTENT_TYPE, strlen(JSON_CONTENT_TYPE)); + TEST_CHECK(ret == 0); + /* Add Content-Encoding: gzip */ + ret = flb_http_add_header(c, "Content-Encoding", 16, "gzip", 4); + TEST_CHECK(ret == 0); + + if (!TEST_CHECK(c != NULL)) { + TEST_MSG("splunk_client failed"); + exit(EXIT_FAILURE); + } + + ret = flb_http_do(c, &b_sent); + if (!TEST_CHECK(ret == 0)) { + TEST_MSG("ret error. ret=%d\n", ret); + } + else if (!TEST_CHECK(b_sent > 0)){ + TEST_MSG("b_sent size error. b_sent = %lu\n", b_sent); + } + else if (!TEST_CHECK(c->resp.status == 200)) { + TEST_MSG("http response code error. expect: 200, got: %d\n", c->resp.status); + } + flb_free(final_data); + + /* waiting to flush */ + flb_time_msleep(1500); + + num = get_output_num(); + if (!TEST_CHECK(num > 0)) { + TEST_MSG("no outputs"); + } + flb_sds_destroy(target); + flb_http_client_destroy(c); + flb_upstream_conn_release(ctx->httpc->u_conn); + test_ctx_destroy(ctx); +} + +void flb_test_splunk_collector_gzip() +{ + flb_test_splunk_gzip(8813, "/services/collector"); +} + +void flb_test_splunk_collector_event_gzip() +{ + flb_test_splunk_gzip(8814, "/services/collector/event"); +} + +void flb_test_splunk_raw_multilines_gzip(int port) +{ + struct flb_lib_out_cb cb_data; + struct test_ctx *ctx; + struct flb_http_client *c; + int ret; + int num; + size_t b_sent; + char *buf = "127.0.0.1 - admin [28/Sep/2016:09:05:26.875 -0700] \"GET /servicesNS/admin/launcher/data/ui/views?count=-1 HTTP/1.0\" 200 126721 - - - 6ms" \ + "127.0.0.1 - admin [28/Sep/2016:09:05:26.917 -0700] \"GET /servicesNS/admin/launcher/data/ui/nav/default HTTP/1.0\" 200 4367 - - - 6ms" \ + "127.0.0.1 - admin [28/Sep/2016:09:05:26.941 -0700] \"GET /services/apps/local?search=disabled%3Dfalse&count=-1 HTTP/1.0\" 200 31930 - - - 4ms" \ + "127.0.0.1 - admin [28/Sep/2016:09:05:26.954 -0700] \"GET /services/apps/local?search=disabled%3Dfalse&count=-1 HTTP/1.0\" 200 31930 - - - 3ms" \ + "127.0.0.1 - admin [28/Sep/2016:09:05:26.968 -0700] \"GET /servicesNS/admin/launcher/data/ui/views?digest=1&count=-1 HTTP/1.0\" 200 58672 - - - 5ms"; + char *expected = "\"log\":"; + char sport[16]; + void *final_data; + size_t final_bytes; + + snprintf(sport, 16, "%d", port); + + clear_output_num(); + + cb_data.cb = cb_check_result_json; + cb_data.data = expected; + + ctx = test_ctx_create(&cb_data); + if (!TEST_CHECK(ctx != NULL)) { + TEST_MSG("test_ctx_create failed"); + exit(EXIT_FAILURE); + } + + ret = flb_input_set(ctx->flb, ctx->i_ffd, + "port", sport, + NULL); + TEST_CHECK(ret == 0); + + ret = flb_output_set(ctx->flb, ctx->o_ffd, + "match", "*", + "format", "json", + NULL); + TEST_CHECK(ret == 0); + + /* Start the engine */ + ret = flb_start(ctx->flb); + TEST_CHECK(ret == 0); + + ctx->httpc = splunk_client_ctx_create(port); + TEST_CHECK(ctx->httpc != NULL); + + ret = flb_gzip_compress((void *) buf, strlen(buf), &final_data, &final_bytes); + TEST_CHECK(ret != -1); + + c = flb_http_client(ctx->httpc->u_conn, FLB_HTTP_POST, "/services/collector/raw", final_data, final_bytes, + "127.0.0.1", port, NULL, 0); + ret = flb_http_add_header(c, FLB_HTTP_HEADER_CONTENT_TYPE, strlen(FLB_HTTP_HEADER_CONTENT_TYPE), + JSON_CONTENT_TYPE, strlen(JSON_CONTENT_TYPE)); + /* Add Content-Encoding: gzip */ + ret = flb_http_add_header(c, "Content-Encoding", 16, "gzip", 4); + TEST_CHECK(ret == 0); + + TEST_CHECK(ret == 0); + if (!TEST_CHECK(c != NULL)) { + TEST_MSG("splunk_client failed"); + exit(EXIT_FAILURE); + } + + ret = flb_http_do(c, &b_sent); + if (!TEST_CHECK(ret == 0)) { + TEST_MSG("ret error. ret=%d\n", ret); + } + else if (!TEST_CHECK(b_sent > 0)){ + TEST_MSG("b_sent size error. b_sent = %lu\n", b_sent); + } + else if (!TEST_CHECK(c->resp.status == 200)) { + TEST_MSG("http response code error. expect: 200, got: %d\n", c->resp.status); + } + flb_free(final_data); + + /* waiting to flush */ + flb_time_msleep(1500); + + num = get_output_num(); + if (!TEST_CHECK(num > 0)) { + TEST_MSG("no outputs"); + } + flb_http_client_destroy(c); + flb_upstream_conn_release(ctx->httpc->u_conn); + test_ctx_destroy(ctx); +} + +void flb_test_splunk_collector_raw_multilines_gzip() +{ + flb_test_splunk_raw_multilines_gzip(8815); +} + +TEST_LIST = { + {"health", flb_test_splunk_health}, + {"collector", flb_test_splunk_collector}, + {"collector_event", flb_test_splunk_collector_event}, + {"collector_raw", flb_test_splunk_collector_raw}, + {"collector_raw_multilines", flb_test_splunk_collector_raw_multilines}, + {"collector_gzip", flb_test_splunk_collector_gzip}, + {"collector_event_gzip", flb_test_splunk_collector_event_gzip}, + {"collector_raw_multilines_gzip", flb_test_splunk_collector_raw_multilines_gzip}, + {"tag_key", flb_test_splunk_tag_key}, + {NULL, NULL} +}; From e8b03a154af87f64e97fff2d2f5b9705429ba640 Mon Sep 17 00:00:00 2001 From: Hiroshi Hatake Date: Mon, 3 Jul 2023 10:18:53 +0900 Subject: [PATCH 052/315] utils: plugin: freeing properly for duplicated string shared properties (#7464) * utils: Add string property handling function instead of just checking duplicated props Signed-off-by: Hiroshi Hatake * filter: Use string property handling function Signed-off-by: Hiroshi Hatake * input: Use string property handling function Signed-off-by: Hiroshi Hatake * output: Use string property handling function Signed-off-by: Hiroshi Hatake * custom: Use string property handling function Signed-off-by: Hiroshi Hatake --------- Signed-off-by: Hiroshi Hatake --- include/fluent-bit/flb_utils.h | 3 +++ src/flb_custom.c | 3 ++- src/flb_filter.c | 4 ++-- src/flb_input.c | 20 ++++++++++---------- src/flb_output.c | 18 +++++++++--------- src/flb_utils.c | 26 ++++++++++++++++++++++++++ 6 files changed, 52 insertions(+), 22 deletions(-) diff --git a/include/fluent-bit/flb_utils.h b/include/fluent-bit/flb_utils.h index eec48243162..0dcbe2e0029 100644 --- a/include/fluent-bit/flb_utils.h +++ b/include/fluent-bit/flb_utils.h @@ -70,5 +70,8 @@ int flb_utils_read_file(char *path, char **out_buf, size_t *out_size); char *flb_utils_get_os_name(); int flb_utils_uuid_v4_gen(char *buf); int flb_utils_get_machine_id(char **out_id, size_t *out_size); +void flb_utils_set_plugin_string_property(const char *name, + flb_sds_t *field_storage, + flb_sds_t new_value); #endif diff --git a/src/flb_custom.c b/src/flb_custom.c index d5c18823ed8..8279bb65d66 100644 --- a/src/flb_custom.c +++ b/src/flb_custom.c @@ -26,6 +26,7 @@ #include #include #include +#include #include static inline int instance_id(struct flb_config *config) @@ -68,7 +69,7 @@ int flb_custom_set_property(struct flb_custom_instance *ins, } if (prop_key_check("alias", k, len) == 0 && tmp) { - ins->alias = tmp; + flb_utils_set_plugin_string_property("alias", &ins->alias, tmp); } else if (prop_key_check("log_level", k, len) == 0 && tmp) { ret = flb_log_get_level_str(tmp); diff --git a/src/flb_filter.c b/src/flb_filter.c index 366e9f4b0f2..389709a9a4d 100644 --- a/src/flb_filter.c +++ b/src/flb_filter.c @@ -296,10 +296,10 @@ int flb_filter_set_property(struct flb_filter_instance *ins, else #endif if (prop_key_check("match", k, len) == 0) { - ins->match = tmp; + flb_utils_set_plugin_string_property("match", &ins->match, tmp); } else if (prop_key_check("alias", k, len) == 0 && tmp) { - ins->alias = tmp; + flb_utils_set_plugin_string_property("alias", &ins->alias, tmp); } else if (prop_key_check("log_level", k, len) == 0 && tmp) { ret = flb_log_get_level_str(tmp); diff --git a/src/flb_input.c b/src/flb_input.c index c9b3d65e6c8..9f39c0ebbb7 100644 --- a/src/flb_input.c +++ b/src/flb_input.c @@ -477,7 +477,7 @@ int flb_input_set_property(struct flb_input_instance *ins, /* Check if the key is a known/shared property */ if (prop_key_check("tag", k, len) == 0 && tmp) { - ins->tag = tmp; + flb_utils_set_plugin_string_property("tag", &ins->tag, tmp); ins->tag_len = flb_sds_len(tmp); ins->tag_default = FLB_FALSE; } @@ -502,7 +502,7 @@ int flb_input_set_property(struct flb_input_instance *ins, flb_sds_destroy(tmp); } else if (prop_key_check("alias", k, len) == 0 && tmp) { - ins->alias = tmp; + flb_utils_set_plugin_string_property("alias", &ins->alias, tmp); } else if (prop_key_check("mem_buf_limit", k, len) == 0 && tmp) { limit = flb_utils_size_to_bytes(tmp); @@ -513,10 +513,10 @@ int flb_input_set_property(struct flb_input_instance *ins, ins->mem_buf_limit = (size_t) limit; } else if (prop_key_check("listen", k, len) == 0) { - ins->host.listen = tmp; + flb_utils_set_plugin_string_property("listen", &ins->host.listen, tmp); } else if (prop_key_check("host", k, len) == 0) { - ins->host.name = tmp; + flb_utils_set_plugin_string_property("host", &ins->host.name, tmp); } else if (prop_key_check("port", k, len) == 0) { if (tmp) { @@ -558,22 +558,22 @@ int flb_input_set_property(struct flb_input_instance *ins, flb_sds_destroy(tmp); } else if (prop_key_check("tls.vhost", k, len) == 0) { - ins->tls_vhost = tmp; + flb_utils_set_plugin_string_property("tls.vhost", &ins->tls_vhost, tmp); } else if (prop_key_check("tls.ca_path", k, len) == 0) { - ins->tls_ca_path = tmp; + flb_utils_set_plugin_string_property("tls.ca_path", &ins->tls_ca_path, tmp); } else if (prop_key_check("tls.ca_file", k, len) == 0) { - ins->tls_ca_file = tmp; + flb_utils_set_plugin_string_property("tls.ca_file", &ins->tls_ca_file, tmp); } else if (prop_key_check("tls.crt_file", k, len) == 0) { - ins->tls_crt_file = tmp; + flb_utils_set_plugin_string_property("tls.crt_file", &ins->tls_crt_file, tmp); } else if (prop_key_check("tls.key_file", k, len) == 0) { - ins->tls_key_file = tmp; + flb_utils_set_plugin_string_property("tls.key_file", &ins->tls_key_file, tmp); } else if (prop_key_check("tls.key_passwd", k, len) == 0) { - ins->tls_key_passwd = tmp; + flb_utils_set_plugin_string_property("tls.key_passwd", &ins->tls_key_passwd, tmp); } #endif else if (prop_key_check("storage.type", k, len) == 0 && tmp) { diff --git a/src/flb_output.c b/src/flb_output.c index 868a7b9b20d..f06ba4f43f0 100644 --- a/src/flb_output.c +++ b/src/flb_output.c @@ -760,7 +760,7 @@ int flb_output_set_property(struct flb_output_instance *ins, /* Check if the key is a known/shared property */ if (prop_key_check("match", k, len) == 0) { - ins->match = tmp; + flb_utils_set_plugin_string_property("match", &ins->match, tmp); } #ifdef FLB_HAVE_REGEX else if (prop_key_check("match_regex", k, len) == 0 && tmp) { @@ -769,7 +769,7 @@ int flb_output_set_property(struct flb_output_instance *ins, } #endif else if (prop_key_check("alias", k, len) == 0 && tmp) { - ins->alias = tmp; + flb_utils_set_plugin_string_property("alias", &ins->alias, tmp); } else if (prop_key_check("log_level", k, len) == 0 && tmp) { ret = flb_log_get_level_str(tmp); @@ -788,7 +788,7 @@ int flb_output_set_property(struct flb_output_instance *ins, ins->log_suppress_interval = ret; } else if (prop_key_check("host", k, len) == 0) { - ins->host.name = tmp; + flb_utils_set_plugin_string_property("host", &ins->host.name, tmp); } else if (prop_key_check("port", k, len) == 0) { if (tmp) { @@ -877,22 +877,22 @@ int flb_output_set_property(struct flb_output_instance *ins, flb_sds_destroy(tmp); } else if (prop_key_check("tls.vhost", k, len) == 0) { - ins->tls_vhost = tmp; + flb_utils_set_plugin_string_property("tls.vhost", &ins->tls_vhost, tmp); } else if (prop_key_check("tls.ca_path", k, len) == 0) { - ins->tls_ca_path = tmp; + flb_utils_set_plugin_string_property("tls.ca_path", &ins->tls_ca_path, tmp); } else if (prop_key_check("tls.ca_file", k, len) == 0) { - ins->tls_ca_file = tmp; + flb_utils_set_plugin_string_property("tls.ca_file", &ins->tls_ca_file, tmp); } else if (prop_key_check("tls.crt_file", k, len) == 0) { - ins->tls_crt_file = tmp; + flb_utils_set_plugin_string_property("tls.crt_file", &ins->tls_crt_file, tmp); } else if (prop_key_check("tls.key_file", k, len) == 0) { - ins->tls_key_file = tmp; + flb_utils_set_plugin_string_property("tls.key_file", &ins->tls_key_file, tmp); } else if (prop_key_check("tls.key_passwd", k, len) == 0) { - ins->tls_key_passwd = tmp; + flb_utils_set_plugin_string_property("tls.key_passwd", &ins->tls_key_passwd, tmp); } #endif else if (prop_key_check("storage.total_limit_size", k, len) == 0 && tmp) { diff --git a/src/flb_utils.c b/src/flb_utils.c index d10194628c2..93e04556390 100644 --- a/src/flb_utils.c +++ b/src/flb_utils.c @@ -1399,3 +1399,29 @@ int flb_utils_get_machine_id(char **out_id, size_t *out_size) return -1; } + +void flb_utils_set_plugin_string_property(const char *name, + flb_sds_t *field_storage, + flb_sds_t new_value) +{ + if (field_storage == NULL) { + flb_error("[utils] invalid field storage pointer for property '%s'", + name); + + return; + } + + if (*field_storage != NULL) { + flb_warn("[utils] property '%s' is already specified with value '%s'." + " Overwriting with '%s'", + name, + *field_storage, + new_value); + + flb_sds_destroy(*field_storage); + + *field_storage = NULL; + } + + *field_storage = new_value; +} From b52c5b1fd8661c9fe54a2151e73fc499bac7469e Mon Sep 17 00:00:00 2001 From: Hiroshi Hatake Date: Mon, 3 Jul 2023 10:20:11 +0900 Subject: [PATCH 053/315] in_elasticsearch: provide version parameter for configurable server version (#7579) * in_elasticsearch: Add version parameter support For some ES client, it needs to unify the versions between server and client. The default version of that parameter is still 8.0.0. Signed-off-by: Hiroshi Hatake * in_elasticsearch: test: Re-diversified for using port numbers Signed-off-by: Hiroshi Hatake --------- Signed-off-by: Hiroshi Hatake --- plugins/in_elasticsearch/in_elasticsearch.c | 6 ++ plugins/in_elasticsearch/in_elasticsearch.h | 1 + .../in_elasticsearch_bulk_prot.c | 46 +++++++++- .../in_elasticsearch_bulk_prot.h | 3 +- tests/runtime/in_elasticsearch.c | 88 +++++++++++++++++-- 5 files changed, 133 insertions(+), 11 deletions(-) diff --git a/plugins/in_elasticsearch/in_elasticsearch.c b/plugins/in_elasticsearch/in_elasticsearch.c index fef9cb66a54..af1a594c6db 100644 --- a/plugins/in_elasticsearch/in_elasticsearch.c +++ b/plugins/in_elasticsearch/in_elasticsearch.c @@ -219,6 +219,12 @@ static struct flb_config_map config_map[] = { "Specify hostname or FQDN. This parameter is effective for sniffering node information." }, + { + FLB_CONFIG_MAP_STR, "version", "8.0.0", + 0, FLB_TRUE, offsetof(struct flb_in_elasticsearch, es_version), + "Specify returning Elasticsearch server version." + }, + /* EOF */ {0} }; diff --git a/plugins/in_elasticsearch/in_elasticsearch.h b/plugins/in_elasticsearch/in_elasticsearch.h index 548aa0e0dfa..159dff88c0a 100644 --- a/plugins/in_elasticsearch/in_elasticsearch.h +++ b/plugins/in_elasticsearch/in_elasticsearch.h @@ -37,6 +37,7 @@ struct flb_in_elasticsearch { const char *tag_key; const char *meta_key; flb_sds_t hostname; + flb_sds_t es_version; char cluster_name[16]; char node_name[12]; diff --git a/plugins/in_elasticsearch/in_elasticsearch_bulk_prot.c b/plugins/in_elasticsearch/in_elasticsearch_bulk_prot.c index eae41adc2df..7ef06146195 100644 --- a/plugins/in_elasticsearch/in_elasticsearch_bulk_prot.c +++ b/plugins/in_elasticsearch/in_elasticsearch_bulk_prot.c @@ -97,6 +97,50 @@ static int send_json_message_response(struct in_elasticsearch_bulk_conn *conn, i return 0; } +static int send_version_message_response(struct flb_in_elasticsearch *ctx, + struct in_elasticsearch_bulk_conn *conn, int http_status) +{ + size_t sent; + int len; + flb_sds_t out; + flb_sds_t resp; + + out = flb_sds_create_size(256); + if (!out) { + return -1; + } + resp = flb_sds_create_size(384); + if (!resp) { + flb_sds_destroy(out); + return -1; + } + + flb_sds_printf(&resp, + ES_VERSION_RESPONSE_TEMPLATE, + ctx->es_version); + + len = flb_sds_len(resp); + + if (http_status == 200) { + flb_sds_printf(&out, + "HTTP/1.1 200 OK\r\n" + "Content-Type: application/json\r\n" + "Content-Length: %i\r\n\r\n%s", + len, resp); + } + + /* We should check this operations result */ + flb_io_net_write(conn->connection, + (void *) out, + flb_sds_len(out), + &sent); + + flb_sds_destroy(resp); + flb_sds_destroy(out); + + return 0; +} + static int send_dummy_sniffer_response(struct in_elasticsearch_bulk_conn *conn, int http_status, struct flb_in_elasticsearch *ctx) { @@ -785,7 +829,7 @@ int in_elasticsearch_bulk_prot_handle(struct flb_in_elasticsearch *ctx, send_dummy_sniffer_response(conn, 200, ctx); } else if (strlen(uri) == 1 && strncmp(uri, "/", 1) == 0) { - send_json_message_response(conn, 200, ES_VERSION_RESPONSE); + send_version_message_response(ctx, conn, 200); } else { send_json_message_response(conn, 200, "{}"); diff --git a/plugins/in_elasticsearch/in_elasticsearch_bulk_prot.h b/plugins/in_elasticsearch/in_elasticsearch_bulk_prot.h index af8c2c22eed..be1aeceea1d 100644 --- a/plugins/in_elasticsearch/in_elasticsearch_bulk_prot.h +++ b/plugins/in_elasticsearch/in_elasticsearch_bulk_prot.h @@ -20,7 +20,8 @@ #ifndef FLB_IN_ELASTICSEARCH_BULK_PROT #define FLB_IN_ELASTICSEARCH_BULK_PROT -#define ES_VERSION_RESPONSE "{\"version\":{\"number\":\"8.0.0\",\"build_flavor\":\"Fluent Bit OSS\"},\"tagline\":\"Fluent Bit's Bulk API compatible endpoint\"}" +#define ES_VERSION_RESPONSE_TEMPLATE \ + "{\"version\":{\"number\":\"%s\",\"build_flavor\":\"Fluent Bit OSS\"},\"tagline\":\"Fluent Bit's Bulk API compatible endpoint\"}" #define ES_NODES_TEMPLATE "{\"_nodes\":{\"total\":1,\"successful\":1,\"failed\":0}," \ "\"nodes\":{\"%s\":{\"name\":\"%s\",\"version\":\"8.0.0\"," \ diff --git a/tests/runtime/in_elasticsearch.c b/tests/runtime/in_elasticsearch.c index e648af89d03..b373d2859cf 100644 --- a/tests/runtime/in_elasticsearch.c +++ b/tests/runtime/in_elasticsearch.c @@ -282,6 +282,75 @@ void flb_test_in_elasticsearch_version() test_ctx_destroy(ctx); } +void flb_test_in_elasticsearch_version_configured() +{ + struct flb_lib_out_cb cb_data; + struct test_ctx *ctx; + struct flb_http_client *c; + int ret; + size_t b_sent; + char *expected = "\"version\":{\"number\":\"8.1.2\",\"build_flavor\""; + char *buf = NULL; + int port = 9202; + char sport[16]; + + snprintf(sport, 16, "%d", port); + + ctx = test_ctx_create(&cb_data); + if (!TEST_CHECK(ctx != NULL)) { + TEST_MSG("test_ctx_create failed"); + exit(EXIT_FAILURE); + } + + ret = flb_input_set(ctx->flb, ctx->i_ffd, + "port", sport, + "version", "8.1.2", + NULL); + TEST_CHECK(ret == 0); + + ret = flb_output_set(ctx->flb, ctx->o_ffd, + "match", "*", + "format", "json", + NULL); + TEST_CHECK(ret == 0); + + /* Start the engine */ + ret = flb_start(ctx->flb); + TEST_CHECK(ret == 0); + + ctx->httpc = in_elasticsearch_client_ctx_create(port); + TEST_CHECK(ctx->httpc != NULL); + + c = flb_http_client(ctx->httpc->u_conn, FLB_HTTP_GET, "/", NULL, 0, + "127.0.0.1", port, NULL, 0); + if (!TEST_CHECK(c != NULL)) { + TEST_MSG("in_elasticsearch_client failed"); + exit(EXIT_FAILURE); + } + + ret = flb_http_do(c, &b_sent); + if (!TEST_CHECK(ret == 0)) { + TEST_MSG("ret error. ret=%d\n", ret); + } + else if (!TEST_CHECK(b_sent > 0)){ + TEST_MSG("b_sent size error. b_sent = %lu\n", b_sent); + } + else if (!TEST_CHECK(c->resp.status == 200)) { + TEST_MSG("http response code error. expect: 200, got: %d\n", c->resp.status); + } + + /* waiting to flush */ + flb_time_msleep(1500); + + buf = strstr(c->resp.payload, expected); + if (!TEST_CHECK(buf != NULL)) { + TEST_MSG("http request for version info failed"); + } + flb_http_client_destroy(c); + flb_upstream_conn_release(ctx->httpc->u_conn); + test_ctx_destroy(ctx); +} + void flb_test_in_elasticsearch(char *write_op, int port, char *tag) { struct flb_lib_out_cb cb_data; @@ -378,12 +447,12 @@ void flb_test_in_elasticsearch(char *write_op, int port, char *tag) void flb_test_in_elasticsearch_index_op() { - flb_test_in_elasticsearch("index", 9202, NULL); + flb_test_in_elasticsearch("index", 9203, NULL); } void flb_test_in_elasticsearch_create_op() { - flb_test_in_elasticsearch("create", 9203, NULL); + flb_test_in_elasticsearch("create", 9204, NULL); } void flb_test_in_elasticsearch_invalid(char *write_op, int status, char *expected_op, int port) @@ -473,17 +542,17 @@ void flb_test_in_elasticsearch_invalid(char *write_op, int status, char *expecte void flb_test_in_elasticsearch_update_op() { - flb_test_in_elasticsearch_invalid("update", 403, "update", 9204); + flb_test_in_elasticsearch_invalid("update", 403, "update", 9205); } void flb_test_in_elasticsearch_delete_op() { - flb_test_in_elasticsearch_invalid("delete", 404, "delete", 9205); + flb_test_in_elasticsearch_invalid("delete", 404, "delete", 9206); } void flb_test_in_elasticsearch_nonexistent_op() { - flb_test_in_elasticsearch_invalid("nonexistent", 400, "unknown", 9206); + flb_test_in_elasticsearch_invalid("nonexistent", 400, "unknown", 9207); } void flb_test_in_elasticsearch_multi_ops() @@ -493,7 +562,7 @@ void flb_test_in_elasticsearch_multi_ops() struct flb_http_client *c; int ret; int num; - int port = 9207; + int port = 9208; char sport[16]; size_t b_sent; char *buf = NDJSON_BULK; @@ -576,7 +645,7 @@ void flb_test_in_elasticsearch_multi_ops_gzip() struct flb_http_client *c; int ret; int num; - int port = 9208; + int port = 9209; char sport[16]; size_t b_sent; char *buf = NDJSON_BULK; @@ -668,7 +737,7 @@ void flb_test_in_elasticsearch_node_info() struct test_ctx *ctx; struct flb_http_client *c; int ret; - int port = 9208; + int port = 9210; char sport[16]; size_t b_sent; char *expected = "{\"_nodes\":{\"total\":1,\"successful\":1,\"failed\":0},\"nodes\":{\""; @@ -738,7 +807,7 @@ void flb_test_in_elasticsearch_tag_key() int ret; int num; size_t b_sent; - int port = 9209; + int port = 9211; char sport[16]; char *buf = "{\"index\":{\"_index\":\"fluent-bit\"}}\n{\"test\":\"msg\",\"tag\":\"new_tag\"}\n"; @@ -815,6 +884,7 @@ void flb_test_in_elasticsearch_index_op_with_plugin_tag() TEST_LIST = { {"version", flb_test_in_elasticsearch_version}, + {"configured_version", flb_test_in_elasticsearch_version_configured}, {"index_op", flb_test_in_elasticsearch_index_op}, {"create_op", flb_test_in_elasticsearch_create_op}, {"update_op", flb_test_in_elasticsearch_update_op}, From 0f75afd2b86176bd03248201111bd035650f8d78 Mon Sep 17 00:00:00 2001 From: Hiroshi Hatake Date: Fri, 16 Jun 2023 19:07:03 +0900 Subject: [PATCH 054/315] lib: wamr: Upgrade the bundled WAMR version to 1.2.2 Signed-off-by: Hiroshi Hatake --- cmake/libraries.cmake | 2 +- .../compilation_on_android_ubuntu.yml | 573 -- .../workflows/compilation_on_windows.yml | 115 - lib/wasm-micro-runtime-WAMR-1.1.1/README.md | 194 - .../core/app-mgr/README.md | 10 - .../core/iwasm/common/wasm_memory.c | 187 - .../iwasm/fast-jit/fe/jit_emit_function.c | 540 -- .../core/iwasm/fast-jit/fe/jit_emit_memory.c | 782 -- .../core/iwasm/fast-jit/jit_compiler.c | 176 - .../core/iwasm/interpreter/wasm_runtime.h | 502 -- .../libraries/lib-rats/lib_rats_wrapper.c | 60 - .../libraries/lib-rats/lib_rats_wrapper.h | 18 - .../src/numeric_limits.h | 42 - .../iwasm/libraries/wasi-nn/.dockerignore | 1 - .../core/iwasm/libraries/wasi-nn/README.md | 43 - .../core/iwasm/libraries/wasi-nn/logger.h | 55 - .../libraries/wasi-nn/test/requirements.txt | 1 - .../libraries/wasi-nn/test/test_tensorflow.c | 301 - .../iwasm/libraries/wasi-nn/wasi_nn.cmake | 10 - .../core/iwasm/libraries/wasi-nn/wasi_nn.h | 132 - .../iwasm/libraries/wasi-nn/wasi_nn_common.h | 44 - .../iwasm/libraries/wasi-nn/wasi_nn_native.c | 264 - .../libraries/wasi-nn/wasi_nn_tensorflow.cpp | 188 - .../libraries/wasi-nn/wasi_nn_tensorflow.hpp | 40 - .../platform/common/posix/posix_malloc.c | 24 - .../core/version.h.in | 14 - .../doc/build_wamr.md | 612 -- .../language-bindings/python/README.md | 31 - .../language-bindings/python/setup.py | 30 - .../samples/native-lib/wasm-app/main.c | 29 - .../samples/sgx-ra/README.md | 42 - .../samples/sgx-ra/wasm-app/main.c | 36 - .../workload/XNNPACK/build_workload.sh | 1 - .../samples/workload/XNNPACK/xnnpack.patch | 112 - .../samples/workload/bwa/CMakeLists.txt | 46 - .../samples/workload/bwa/build_workload.sh | 1 - .../samples/workload/cmake/preparation.cmake | 49 - .../samples/workload/docker/build_workload.sh | 33 - .../workload/meshoptimizer/CMakeLists.txt | 30 - .../workload/meshoptimizer/build_workload.sh | 1 - .../samples/workload/wasm-av1/CMakeLists.txt | 32 - .../workload/wasm-av1/build_workload.sh | 1 - .../wasm_django/static/upload/connection.wasm | Bin 6379 -> 0 bytes .../static/upload/event_publisher.wasm | Bin 5074 -> 0 bytes .../static/upload/event_subscriber.wasm | Bin 3917 -> 0 bytes .../static/upload/request_handler.wasm | Bin 6702 -> 0 bytes .../static/upload/request_sender.wasm | Bin 5212 -> 0 bytes .../wasm_django/static/upload/sensor.wasm | Bin 4027 -> 0 bytes .../wasm_django/static/upload/simple | Bin 368240 -> 0 bytes .../static/upload/sys/connection.wasm | Bin 6379 -> 0 bytes .../static/upload/sys/event_publisher.wasm | Bin 5074 -> 0 bytes .../static/upload/sys/event_subscriber.wasm | Bin 3917 -> 0 bytes .../static/upload/sys/request_handler.wasm | Bin 6702 -> 0 bytes .../static/upload/sys/request_sender.wasm | Bin 5212 -> 0 bytes .../wasm_django/static/upload/sys/timer.wasm | Bin 2468 -> 0 bytes .../wasm_django/static/upload/timer.wasm | Bin 2468 -> 0 bytes .../wasm_django/static/upload/ui_app.wasm | Bin 1953 -> 0 bytes .../static/upload/vgl_wasm_runtime | Bin 512936 -> 0 bytes .../static/upload/wasm_runtime_wgl | Bin 591680 -> 0 bytes .../build-wasi-sdk/build_wasi_sdk.py | 299 - .../build-wasi-sdk/patches/wasi_libc.patch | 13 - .../build-wasi-sdk/patches/wasi_sdk.patch | 15 - .../VSCode-Extension/resource/debug/README.md | 13 - .../src/debugConfigurationProvider.ts | 63 - .../src/utilities/directoryUtilities.ts | 120 - .../wamr-ide/VSCode-Extension/tsconfig.json | 21 - .../.clang-tidy | 0 .../.devcontainer/Dockerfile | 59 +- .../.devcontainer/devcontainer.json | 12 +- .../scripts/extract_from_release_notes.py | 60 + .../scripts/fetch_and_compare_version.py | 123 + .../scripts/reuse_latest_release_binaries.py | 102 + .../.github/workflows/build_docker_images.yml | 89 + .../.github/workflows/build_iwasm_release.yml | 108 + .../workflows/build_llvm_libraries.yml | 91 + .../.github/workflows/build_wamr_lldb.yml | 197 + .../.github/workflows/build_wamr_sdk.yml | 78 + .../workflows/build_wamr_vscode_ext.yml | 73 + .../.github/workflows/build_wamrc.yml | 86 + .../.github/workflows/coding_guidelines.yml} | 13 +- .../compilation_on_android_ubuntu.yml | 645 ++ .../workflows/compilation_on_macos.yml | 265 +- .../workflows/compilation_on_nuttx.yml | 86 +- .../.github/workflows/compilation_on_sgx.yml | 293 +- .../workflows/compilation_on_windows.yml | 77 + .../.github/workflows/create_tag.yml | 68 + .../.github/workflows/release_process.yml | 215 + .../reuse_latest_release_binaries.yml | 68 + .../.github/workflows/spec_test_on_nuttx.yml | 145 + .../.gitignore | 12 +- .../ATTRIBUTIONS.md | 0 .../CMakeLists.txt | 34 +- .../CODE_OF_CONDUCT.md | 0 .../CONTRIBUTING.md | 0 .../LICENSE | 0 .../ORG_CODE_OF_CONDUCT.md | 0 lib/wasm-micro-runtime-WAMR-1.2.2/README.md | 113 + .../RELEASE_NOTES.md | 402 + .../SConscript | 0 .../SECURITY.md | 0 .../TSC_Charter.md | 0 .../assembly-script/.gitignore | 0 .../assembly-script/README.md | 0 .../assembly-script/package-lock.json | 0 .../assembly-script/package.json | 0 .../samples/event_publisher.ts | 0 .../samples/event_subscriber.ts | 0 .../samples/request_handler.ts | 0 .../assembly-script/samples/request_sender.ts | 0 .../assembly-script/samples/timer.ts | 0 .../assembly-script/samples/tsconfig.json | 0 .../assembly-script/wamr_app_lib/console.ts | 0 .../assembly-script/wamr_app_lib/request.ts | 4 +- .../assembly-script/wamr_app_lib/timer.ts | 0 .../wamr_app_lib/tsconfig.json | 0 .../build-scripts/SConscript | 0 .../build-scripts/SConscript_config | 1 + .../build-scripts/build_llvm.py | 126 +- .../build-scripts/config_common.cmake | 170 +- .../build-scripts/esp-idf/README.md | 0 .../build-scripts/esp-idf/wamr/CMakeLists.txt | 2 +- .../build-scripts/involve_boringssl.cmake | 41 + .../build-scripts/lldb-wasm.patch | 36 + .../build-scripts/requirements.txt | 1 + .../build-scripts/runtime_lib.cmake | 59 +- .../ci/build_wamr.sh | 0 .../ci/coding_guidelines_check.py | 0 .../core/app-framework/README.md | 27 +- .../app-framework/app-native-shared/README.md | 0 .../app-native-shared/attr_container.c | 194 +- .../app-native-shared/bi-inc/attr_container.h | 180 +- .../app-native-shared/bi-inc/shared_utils.h | 0 .../bi-inc/wgl_shared_utils.h | 0 .../app-native-shared/native_interface.cmake | 0 .../app-native-shared/native_interface.h | 0 .../app-native-shared/restful_utils.c | 0 .../core/app-framework/app_ext_lib_export.c | 0 .../core/app-framework/app_framework.cmake | 0 .../core/app-framework/base/app/bh_platform.c | 0 .../core/app-framework/base/app/bh_platform.h | 0 .../app-framework/base/app/req_resp_api.h | 0 .../core/app-framework/base/app/request.c | 0 .../core/app-framework/base/app/timer.c | 0 .../core/app-framework/base/app/timer_api.h | 0 .../app-framework/base/app/wa-inc/request.h | 0 .../base/app/wa-inc/timer_wasm_app.h | 0 .../app-framework/base/app/wasm_app.cmake | 0 .../core/app-framework/base/app/wasm_app.h | 0 .../app-framework/base/native/base_lib.inl | 0 .../base/native/base_lib_export.c | 0 .../base/native/req_resp_native_api.h | 0 .../base/native/request_response.c | 0 .../app-framework/base/native/runtime_lib.h | 0 .../base/native/timer_native_api.h | 0 .../app-framework/base/native/timer_wrapper.c | 0 .../app-framework/base/native/wasm_lib.cmake | 0 .../app-framework/connection/app/connection.c | 0 .../connection/app/connection_api.h | 0 .../connection/app/wa-inc/connection.h | 0 .../connection/app/wasm_app.cmake | 0 .../connection/native/connection.inl | 0 .../connection/native/connection_lib.h | 0 .../connection/native/connection_native_api.h | 0 .../connection/native/connection_wrapper.c | 0 .../connection/native/linux/conn_tcp.c | 0 .../connection/native/linux/conn_tcp.h | 0 .../connection/native/linux/conn_uart.c | 0 .../connection/native/linux/conn_uart.h | 0 .../connection/native/linux/conn_udp.c | 0 .../connection/native/linux/conn_udp.h | 0 .../connection/native/linux/connection_mgr.c | 0 .../native/linux/connection_mgr.cmake | 0 .../connection/native/wasm_lib.cmake | 0 .../native/zephyr/connection_lib_impl.c | 0 .../native/zephyr/connection_mgr.cmake | 0 .../core/app-framework/sensor/app/sensor.c | 0 .../app-framework/sensor/app/sensor_api.h | 0 .../app-framework/sensor/app/wa-inc/sensor.h | 0 .../app-framework/sensor/app/wasm_app.cmake | 0 .../sensor/native/runtime_sensor.c | 0 .../sensor/native/runtime_sensor.h | 0 .../sensor/native/runtime_sensor.inl | 0 .../sensor/native/sensor_mgr_ref.c | 0 .../sensor/native/sensor_native_api.h | 0 .../sensor/native/wasm_lib.cmake | 0 .../template/app/wa-inc/app_xxx.h | 0 .../app-framework/template/app/wasm_app.cmake | 0 .../app-framework/template/native/app_xxx.inl | 0 .../template/native/wasm_lib.cmake | 0 .../core/app-mgr/README.md | 8 + .../core/app-mgr/app-manager/app_manager.c | 0 .../core/app-mgr/app-manager/app_manager.h | 0 .../app-mgr/app-manager/app_manager_host.c | 0 .../app-mgr/app-manager/app_manager_host.h | 0 .../core/app-mgr/app-manager/app_mgr.cmake | 0 .../core/app-mgr/app-manager/ble_msg.c | 0 .../core/app-mgr/app-manager/coding_rule.txt | 0 .../core/app-mgr/app-manager/event.c | 0 .../core/app-mgr/app-manager/event.h | 0 .../core/app-mgr/app-manager/message.c | 0 .../core/app-mgr/app-manager/module_config.h | 0 .../core/app-mgr/app-manager/module_jeff.c | 0 .../core/app-mgr/app-manager/module_jeff.h | 0 .../core/app-mgr/app-manager/module_utils.c | 0 .../app-mgr/app-manager/module_wasm_app.c | 8 + .../app-mgr/app-manager/module_wasm_app.h | 0 .../app-mgr/app-manager/module_wasm_lib.c | 0 .../app-mgr/app-manager/module_wasm_lib.h | 0 .../platform/darwin/app_mgr_darwin.c | 0 .../platform/linux/app_mgr_linux.c | 0 .../platform/zephyr/app_mgr_zephyr.c | 0 .../core/app-mgr/app-manager/resource_reg.c | 0 .../core/app-mgr/app-manager/watchdog.c | 0 .../core/app-mgr/app-manager/watchdog.h | 0 .../app-mgr-shared/app_manager_export.h | 0 .../app-mgr-shared/app_mgr_shared.cmake | 0 .../core/app-mgr/app-mgr-shared/host_link.h | 0 .../core/app-mgr/module.json | 0 .../core/config.h | 66 +- .../core/iwasm/README.md | 14 + .../core/iwasm/aot/SConscript | 0 .../core/iwasm/aot/aot_intrinsic.c | 135 +- .../core/iwasm/aot/aot_intrinsic.h | 26 +- .../core/iwasm/aot/aot_loader.c | 609 +- .../core/iwasm/aot/aot_reloc.h | 12 + .../core/iwasm/aot/aot_runtime.c | 1572 ++-- .../core/iwasm/aot/aot_runtime.h | 277 +- .../core/iwasm/aot/arch/aot_reloc_aarch64.c | 0 .../core/iwasm/aot/arch/aot_reloc_arc.c | 0 .../core/iwasm/aot/arch/aot_reloc_arm.c | 6 + .../core/iwasm/aot/arch/aot_reloc_mips.c | 0 .../core/iwasm/aot/arch/aot_reloc_riscv.c | 68 +- .../core/iwasm/aot/arch/aot_reloc_thumb.c | 46 + .../core/iwasm/aot/arch/aot_reloc_x86_32.c | 0 .../core/iwasm/aot/arch/aot_reloc_x86_64.c | 0 .../core/iwasm/aot/arch/aot_reloc_xtensa.c | 26 +- .../core/iwasm/aot/debug/LICENSE_NUTTX | 0 .../core/iwasm/aot/debug/NOTICE_NUTTX | 0 .../core/iwasm/aot/debug/elf.h | 0 .../core/iwasm/aot/debug/elf32.h | 0 .../core/iwasm/aot/debug/elf64.h | 0 .../core/iwasm/aot/debug/elf_parser.c | 0 .../core/iwasm/aot/debug/elf_parser.h | 0 .../core/iwasm/aot/debug/jit_debug.c | 0 .../core/iwasm/aot/debug/jit_debug.h | 0 .../core/iwasm/aot/iwasm_aot.cmake | 0 .../core/iwasm/common/SConscript | 0 .../iwasm/common/arch/invokeNative_aarch64.s | 0 .../common/arch/invokeNative_aarch64_simd.s | 0 .../core/iwasm/common/arch/invokeNative_arc.s | 0 .../core/iwasm/common/arch/invokeNative_arm.s | 0 .../iwasm/common/arch/invokeNative_arm_vfp.s | 0 .../iwasm/common/arch/invokeNative_em64.asm | 0 .../iwasm/common/arch/invokeNative_em64.s | 0 .../common/arch/invokeNative_em64_simd.asm | 0 .../common/arch/invokeNative_em64_simd.s | 0 .../iwasm/common/arch/invokeNative_general.c | 0 .../iwasm/common/arch/invokeNative_ia32.asm | 0 .../iwasm/common/arch/invokeNative_ia32.s | 7 +- .../common/arch/invokeNative_mingw_x64.s | 57 + .../common/arch/invokeNative_mingw_x64_simd.s | 57 + .../iwasm/common/arch/invokeNative_mips.s | 0 .../common/arch/invokeNative_osx_universal.s | 18 + .../iwasm/common/arch/invokeNative_riscv.S | 0 .../iwasm/common/arch/invokeNative_thumb.s | 0 .../common/arch/invokeNative_thumb_vfp.s | 0 .../iwasm/common/arch/invokeNative_xtensa.s | 0 .../core/iwasm/common/iwasm_common.cmake | 25 +- .../core/iwasm/common/wasm_application.c | 40 +- .../core/iwasm/common/wasm_c_api.c | 1427 ++- .../core/iwasm/common/wasm_c_api_internal.h | 9 +- .../core/iwasm/common/wasm_exec_env.c | 34 +- .../core/iwasm/common/wasm_exec_env.h | 29 +- .../core/iwasm/common/wasm_memory.c | 759 ++ .../core/iwasm/common/wasm_memory.h | 11 + .../core/iwasm/common/wasm_native.c | 69 +- .../core/iwasm/common/wasm_native.h | 4 + .../core/iwasm/common/wasm_runtime_common.c | 1197 ++- .../core/iwasm/common/wasm_runtime_common.h | 143 +- .../core/iwasm/common/wasm_shared_memory.c | 322 +- .../core/iwasm/common/wasm_shared_memory.h | 2 + .../core/iwasm/compilation/aot.c | 0 .../core/iwasm/compilation/aot.h | 17 +- .../core/iwasm/compilation/aot_compiler.c | 271 +- .../core/iwasm/compilation/aot_compiler.h | 1 + .../iwasm/compilation/aot_emit_aot_file.c | 23 +- .../core/iwasm/compilation/aot_emit_compare.c | 0 .../core/iwasm/compilation/aot_emit_compare.h | 0 .../core/iwasm/compilation/aot_emit_const.c | 2 +- .../core/iwasm/compilation/aot_emit_const.h | 0 .../core/iwasm/compilation/aot_emit_control.c | 39 +- .../core/iwasm/compilation/aot_emit_control.h | 0 .../iwasm/compilation/aot_emit_conversion.c | 127 +- .../iwasm/compilation/aot_emit_conversion.h | 0 .../iwasm/compilation/aot_emit_exception.c | 3 +- .../iwasm/compilation/aot_emit_exception.h | 0 .../iwasm/compilation/aot_emit_function.c | 365 +- .../iwasm/compilation/aot_emit_function.h | 0 .../core/iwasm/compilation/aot_emit_memory.c | 81 +- .../core/iwasm/compilation/aot_emit_memory.h | 4 + .../iwasm/compilation/aot_emit_numberic.c | 156 +- .../iwasm/compilation/aot_emit_numberic.h | 0 .../iwasm/compilation/aot_emit_parametric.c | 0 .../iwasm/compilation/aot_emit_parametric.h | 0 .../core/iwasm/compilation/aot_emit_table.c | 41 +- .../core/iwasm/compilation/aot_emit_table.h | 0 .../iwasm/compilation/aot_emit_variable.c | 8 +- .../iwasm/compilation/aot_emit_variable.h | 0 .../core/iwasm/compilation/aot_llvm.c | 1022 ++- .../core/iwasm/compilation/aot_llvm.h | 70 +- .../core/iwasm/compilation/aot_llvm_extra.cpp | 265 +- .../iwasm/compilation/aot_llvm_extra2.cpp | 108 + .../core/iwasm/compilation/aot_llvm_extra2.h | 17 + .../core/iwasm/compilation/aot_orc_extra.cpp | 289 + .../core/iwasm/compilation/aot_orc_extra.h | 75 + .../compilation/debug/dwarf_extractor.cpp | 0 .../iwasm/compilation/debug/dwarf_extractor.h | 0 .../core/iwasm/compilation/iwasm_compl.cmake | 0 .../compilation/simd/simd_access_lanes.c | 0 .../compilation/simd/simd_access_lanes.h | 0 .../iwasm/compilation/simd/simd_bit_shifts.c | 0 .../iwasm/compilation/simd/simd_bit_shifts.h | 0 .../compilation/simd/simd_bitmask_extracts.c | 0 .../compilation/simd/simd_bitmask_extracts.h | 0 .../iwasm/compilation/simd/simd_bitwise_ops.c | 0 .../iwasm/compilation/simd/simd_bitwise_ops.h | 0 .../compilation/simd/simd_bool_reductions.c | 0 .../compilation/simd/simd_bool_reductions.h | 0 .../core/iwasm/compilation/simd/simd_common.c | 0 .../core/iwasm/compilation/simd/simd_common.h | 0 .../iwasm/compilation/simd/simd_comparisons.c | 0 .../iwasm/compilation/simd/simd_comparisons.h | 0 .../compilation/simd/simd_construct_values.c | 0 .../compilation/simd/simd_construct_values.h | 0 .../iwasm/compilation/simd/simd_conversions.c | 0 .../iwasm/compilation/simd/simd_conversions.h | 0 .../compilation/simd/simd_floating_point.c | 0 .../compilation/simd/simd_floating_point.h | 0 .../iwasm/compilation/simd/simd_int_arith.c | 0 .../iwasm/compilation/simd/simd_int_arith.h | 0 .../iwasm/compilation/simd/simd_load_store.c | 0 .../iwasm/compilation/simd/simd_load_store.h | 0 .../compilation/simd/simd_sat_int_arith.c | 0 .../compilation/simd/simd_sat_int_arith.h | 0 .../core/iwasm/doc/classic_interpreter.MD | 5 + .../doc/images/export_function.excalidraw | 5695 ++++++++++++ .../doc/images/stack_format_ci.excalidraw | 2643 ++++++ .../core/iwasm/doc/images/stack_format_ci.svg | 16 + .../core/iwasm/doc/images/wasm_exports.svg | 16 + .../iwasm/doc/images/wasm_function.excalidraw | 7754 +++++++++++++++++ .../core/iwasm/doc/images/wasm_function.svg | 16 + .../iwasm/doc/images/wasm_globals.excalidraw | 2313 +++++ .../core/iwasm/doc/images/wasm_globals.svg | 16 + .../core/iwasm/doc/wasm_exports.MD | 22 + .../core/iwasm/doc/wasm_function.MD | 47 + .../core/iwasm/doc/wasm_globals.MD | 4 + .../core/iwasm/fast-jit/asmjit_sgx_patch.diff | 0 .../core/iwasm/fast-jit/cg/LICENSE_ASMJIT | 0 .../core/iwasm/fast-jit/cg/LICENSE_ZYDIS | 0 .../fast-jit/cg/x86-64/jit_codegen_x86_64.cpp | 3443 +++++++- .../core/iwasm/fast-jit/fe/jit_emit_compare.c | 0 .../core/iwasm/fast-jit/fe/jit_emit_compare.h | 0 .../core/iwasm/fast-jit/fe/jit_emit_const.c | 0 .../core/iwasm/fast-jit/fe/jit_emit_const.h | 0 .../core/iwasm/fast-jit/fe/jit_emit_control.c | 117 +- .../core/iwasm/fast-jit/fe/jit_emit_control.h | 0 .../iwasm/fast-jit/fe/jit_emit_conversion.c | 12 +- .../iwasm/fast-jit/fe/jit_emit_conversion.h | 0 .../iwasm/fast-jit/fe/jit_emit_exception.c | 2 +- .../iwasm/fast-jit/fe/jit_emit_exception.h | 0 .../iwasm/fast-jit/fe/jit_emit_function.c | 945 ++ .../iwasm/fast-jit/fe/jit_emit_function.h | 0 .../core/iwasm/fast-jit/fe/jit_emit_memory.c | 1200 +++ .../core/iwasm/fast-jit/fe/jit_emit_memory.h | 3 + .../iwasm/fast-jit/fe/jit_emit_numberic.c | 87 +- .../iwasm/fast-jit/fe/jit_emit_numberic.h | 0 .../iwasm/fast-jit/fe/jit_emit_parametric.c | 0 .../iwasm/fast-jit/fe/jit_emit_parametric.h | 0 .../core/iwasm/fast-jit/fe/jit_emit_table.c | 40 +- .../core/iwasm/fast-jit/fe/jit_emit_table.h | 0 .../iwasm/fast-jit/fe/jit_emit_variable.c | 43 +- .../iwasm/fast-jit/fe/jit_emit_variable.h | 0 .../core/iwasm/fast-jit/iwasm_fast_jit.cmake | 2 + .../core/iwasm/fast-jit/jit_codecache.c | 29 +- .../core/iwasm/fast-jit/jit_codecache.h | 0 .../core/iwasm/fast-jit/jit_codegen.c | 0 .../core/iwasm/fast-jit/jit_codegen.h | 11 +- .../core/iwasm/fast-jit/jit_compiler.c | 291 + .../core/iwasm/fast-jit/jit_compiler.h | 21 +- .../core/iwasm/fast-jit/jit_dump.c | 7 +- .../core/iwasm/fast-jit/jit_dump.h | 0 .../core/iwasm/fast-jit/jit_frontend.c | 472 +- .../core/iwasm/fast-jit/jit_frontend.h | 85 +- .../core/iwasm/fast-jit/jit_ir.c | 27 +- .../core/iwasm/fast-jit/jit_ir.def | 46 +- .../core/iwasm/fast-jit/jit_ir.h | 58 +- .../core/iwasm/fast-jit/jit_regalloc.c | 28 +- .../core/iwasm/fast-jit/jit_utils.c | 0 .../core/iwasm/fast-jit/jit_utils.h | 0 .../core/iwasm/include/aot_export.h | 9 + .../core/iwasm/include/lib_export.h | 0 .../core/iwasm/include/wasm_c_api.h | 32 +- .../core/iwasm/include/wasm_export.h | 204 +- .../core/iwasm/interpreter/SConscript | 0 .../core/iwasm/interpreter/iwasm_interp.cmake | 0 .../core/iwasm/interpreter/wasm.h | 145 +- .../core/iwasm/interpreter/wasm_interp.h | 12 - .../iwasm/interpreter/wasm_interp_classic.c | 834 +- .../core/iwasm/interpreter/wasm_interp_fast.c | 432 +- .../core/iwasm/interpreter/wasm_loader.c | 783 +- .../core/iwasm/interpreter/wasm_loader.h | 0 .../core/iwasm/interpreter/wasm_mini_loader.c | 679 +- .../core/iwasm/interpreter/wasm_opcode.h | 20 +- .../core/iwasm/interpreter/wasm_runtime.c | 2324 +++-- .../core/iwasm/interpreter/wasm_runtime.h | 668 ++ .../libraries/debug-engine/debug_engine.c | 322 +- .../libraries/debug-engine/debug_engine.cmake | 0 .../libraries/debug-engine/debug_engine.h | 37 +- .../iwasm/libraries/debug-engine/gdbserver.c | 33 +- .../iwasm/libraries/debug-engine/gdbserver.h | 6 + .../iwasm/libraries/debug-engine/handler.c | 145 +- .../iwasm/libraries/debug-engine/handler.h | 3 + .../iwasm/libraries/debug-engine/packets.c | 0 .../iwasm/libraries/debug-engine/packets.h | 0 .../core/iwasm/libraries/debug-engine/utils.c | 0 .../core/iwasm/libraries/debug-engine/utils.h | 0 .../iwasm/libraries/lib-pthread/SConscript | 0 .../libraries/lib-pthread/lib_pthread.cmake | 0 .../lib-pthread/lib_pthread_wrapper.c | 22 +- .../iwasm/libraries/lib-rats/lib_rats.cmake | 12 +- .../libraries/lib-rats/lib_rats_common.h | 40 + .../libraries/lib-rats/lib_rats_wrapper.c | 115 + .../libraries/lib-rats/lib_rats_wrapper.h | 48 + .../lib-socket/inc/wasi_socket_ext.h | 0 .../lib-socket/lib_socket_wasi.cmake | 0 .../lib-socket/src/wasi/wasi_socket_ext.c | 0 .../iwasm/libraries/lib-socket/test/build.sh | 25 + .../libraries/lib-socket/test/nslookup.c | 49 + .../iwasm/libraries/lib-socket/test/tcp_udp.c | 193 + .../lib-wasi-threads/lib_wasi_threads.cmake | 12 + .../lib_wasi_threads_wrapper.c | 184 + .../libraries/lib-wasi-threads/test/build.sh | 35 + .../libraries/lib-wasi-threads/test/common.h | 126 + .../test/create_threads_until_limit.c | 128 + .../lib-wasi-threads/test/global_atomic.c | 70 + .../lib-wasi-threads/test/global_lock.c | 83 + .../test/linear_memory_size_update.c | 94 + .../test/main_proc_exit_busy.c | 16 + .../test/main_proc_exit_busy.json | 3 + .../test/main_proc_exit_sleep.c | 16 + .../test/main_proc_exit_sleep.json | 3 + .../test/main_proc_exit_wait.c | 16 + .../test/main_proc_exit_wait.json | 3 + .../lib-wasi-threads/test/main_trap_busy.c | 16 + .../lib-wasi-threads/test/main_trap_busy.json | 3 + .../lib-wasi-threads/test/main_trap_sleep.c | 16 + .../test/main_trap_sleep.json | 3 + .../lib-wasi-threads/test/main_trap_wait.c | 16 + .../lib-wasi-threads/test/main_trap_wait.json | 3 + .../test/nonmain_proc_exit_busy.c | 16 + .../test/nonmain_proc_exit_busy.json | 3 + .../test/nonmain_proc_exit_sleep.c | 16 + .../test/nonmain_proc_exit_sleep.json | 3 + .../test/nonmain_proc_exit_wait.c | 16 + .../test/nonmain_proc_exit_wait.json | 3 + .../lib-wasi-threads/test/nonmain_trap_busy.c | 16 + .../test/nonmain_trap_busy.json | 3 + .../test/nonmain_trap_sleep.c | 16 + .../test/nonmain_trap_sleep.json | 3 + .../lib-wasi-threads/test/nonmain_trap_wait.c | 16 + .../test/nonmain_trap_wait.json | 3 + .../test/spawn_multiple_times.c | 72 + .../lib-wasi-threads/test/sync_primitives.h | 91 + .../test/trap_after_main_thread_finishes.c | 44 + .../test/trap_after_main_thread_finishes.json | 3 + .../test/update_shared_data_and_alloc_heap.c | 97 + .../lib-wasi-threads/tid_allocator.c | 80 + .../lib-wasi-threads/tid_allocator.h | 36 + .../iwasm/libraries/libc-builtin/SConscript | 0 .../libraries/libc-builtin/libc_builtin.cmake | 0 .../libc-builtin/libc_builtin_wrapper.c | 4 +- .../core/iwasm/libraries/libc-emcc/SConscript | 0 .../iwasm/libraries/libc-emcc/libc_emcc.cmake | 0 .../libraries/libc-emcc/libc_emcc_wrapper.c | 4 - .../iwasm/libraries/libc-uvwasi/LICENSE_LIBUV | 0 .../libraries/libc-uvwasi/LICENSE_UVWASI | 0 .../libraries/libc-uvwasi/libc_uvwasi.cmake | 2 +- .../libc-uvwasi/libc_uvwasi_wrapper.c | 20 +- .../core/iwasm/libraries/libc-wasi/SConscript | 0 .../iwasm/libraries/libc-wasi/libc_wasi.cmake | 0 .../libraries/libc-wasi/libc_wasi_wrapper.c | 149 +- .../libraries/libc-wasi/libc_wasi_wrapper.h | 0 .../sandboxed-system-primitives/LICENSE | 0 .../include/LICENSE | 0 .../include/wasmtime_ssp.h | 64 + .../sandboxed-system-primitives/src/LICENSE | 0 .../sandboxed-system-primitives/src/README.md | 0 .../sandboxed-system-primitives/src/gnuc.h | 14 + .../sandboxed-system-primitives/src/locking.h | 0 .../sandboxed-system-primitives/src/posix.c | 255 +- .../sandboxed-system-primitives/src/posix.h | 0 .../sandboxed-system-primitives/src/queue.h | 0 .../sandboxed-system-primitives/src/random.c | 0 .../sandboxed-system-primitives/src/random.h | 0 .../src/refcount.h | 37 + .../sandboxed-system-primitives/src/rights.h | 0 .../src/ssp_config.h | 24 +- .../sandboxed-system-primitives/src/str.c | 0 .../sandboxed-system-primitives/src/str.h | 0 .../iwasm/libraries/thread-mgr/SConscript | 0 .../libraries/thread-mgr/thread_manager.c | 589 +- .../libraries/thread-mgr/thread_manager.h | 39 +- .../libraries/thread-mgr/thread_mgr.cmake | 0 .../core/iwasm/libraries/wasi-nn/README.md | 96 + .../wasi-nn/cmake/Findtensorflow_lite.cmake | 41 + .../libraries/wasi-nn/src/utils/logger.h | 69 + .../wasi-nn/src/utils/wasi_nn_app_native.c | 163 + .../wasi-nn/src/utils/wasi_nn_app_native.h | 51 + .../iwasm/libraries/wasi-nn/src/wasi_nn.c | 306 + .../libraries/wasi-nn/src/wasi_nn_private.h | 31 + .../wasi-nn/src/wasi_nn_tensorflowlite.cpp | 417 + .../wasi-nn/src/wasi_nn_tensorflowlite.hpp | 45 + .../libraries/wasi-nn/test/CMakeLists.txt | 9 +- .../libraries/wasi-nn/test/Dockerfile.compile | 23 + .../libraries/wasi-nn/test/Dockerfile.cpu | 27 + .../wasi-nn/test/Dockerfile.nvidia-gpu | 40 + .../wasi-nn/test/Dockerfile.vx-delegate | 99 + .../iwasm/libraries/wasi-nn/test/build.sh | 5 +- .../libraries/wasi-nn/test/models/average.py | 0 .../libraries/wasi-nn/test/models/max.py | 0 .../wasi-nn/test/models/mult_dimension.py | 0 .../wasi-nn/test/models/mult_outputs.py | 0 .../libraries/wasi-nn/test/models/sum.py | 0 .../libraries/wasi-nn/test/models/utils.py | 0 .../libraries/wasi-nn/test/requirements.txt | 1 + .../libraries/wasi-nn/test/test_tensorflow.c | 146 + .../core/iwasm/libraries/wasi-nn/test/utils.c | 162 + .../core/iwasm/libraries/wasi-nn/test/utils.h | 52 + .../iwasm/libraries/wasi-nn/wasi_nn.cmake | 22 + .../core/iwasm/libraries/wasi-nn/wasi_nn.h | 89 + .../iwasm/libraries/wasi-nn/wasi_nn_types.h | 106 + .../core/shared/coap/er-coap/LICENSE.md | 0 .../core/shared/coap/er-coap/coap-constants.h | 0 .../core/shared/coap/extension/coap_ext.h | 0 .../core/shared/coap/lib_coap.cmake | 0 .../core/shared/mem-alloc/SConscript | 0 .../core/shared/mem-alloc/ems/ems_alloc.c | 22 +- .../core/shared/mem-alloc/ems/ems_gc.h | 0 .../shared/mem-alloc/ems/ems_gc_internal.h | 50 +- .../core/shared/mem-alloc/ems/ems_hmu.c | 0 .../core/shared/mem-alloc/ems/ems_kfc.c | 42 +- .../core/shared/mem-alloc/mem_alloc.c | 0 .../core/shared/mem-alloc/mem_alloc.cmake | 0 .../core/shared/mem-alloc/mem_alloc.h | 0 .../core/shared/platform/README.md | 0 .../shared/platform/alios/alios_platform.c | 6 + .../core/shared/platform/alios/alios_thread.c | 0 .../core/shared/platform/alios/alios_time.c | 0 .../shared/platform/alios/platform_internal.h | 0 .../platform/alios/shared_platform.cmake | 0 .../shared/platform/android/platform_init.c | 0 .../platform/android/platform_internal.h | 2 + .../platform/android/shared_platform.cmake | 0 .../common/freertos/freertos_malloc.c | 6 + .../common/freertos/freertos_thread.c | 0 .../platform/common/freertos/freertos_time.c | 0 .../freertos/platform_api_freertos.cmake | 0 .../shared/platform/common/math/COPYRIGHT | 0 .../core/shared/platform/common/math/math.c | 10 +- .../common/math/platform_api_math.cmake | 0 .../common/posix/platform_api_posix.cmake | 0 .../platform/common/posix/posix_malloc.c | 72 + .../platform/common/posix/posix_memmap.c | 0 .../platform/common/posix/posix_socket.c | 93 +- .../platform/common/posix/posix_thread.c | 26 +- .../shared/platform/common/posix/posix_time.c | 0 .../shared/platform/darwin/platform_init.c | 0 .../platform/darwin/platform_internal.h | 2 + .../platform/darwin/shared_platform.cmake | 0 .../core/shared/platform/ego/platform_init.c | 6 + .../shared/platform/ego/platform_internal.h | 6 + .../shared/platform/ego/shared_platform.cmake | 20 + .../shared/platform/esp-idf/espidf_malloc.c | 6 + .../shared/platform/esp-idf/espidf_memmap.c | 0 .../shared/platform/esp-idf/espidf_platform.c | 4 +- .../shared/platform/esp-idf/espidf_socket.c | 228 + .../shared/platform/esp-idf/espidf_thread.c | 0 .../platform/esp-idf/platform_internal.h | 2 + .../platform/esp-idf/shared_platform.cmake | 0 .../shared/platform/freebsd}/platform_init.c | 0 .../platform/freebsd/platform_internal.h | 108 + .../platform/freebsd/shared_platform.cmake | 18 + .../platform/include/platform_api_extension.h | 61 +- .../platform/include/platform_api_vmcore.h | 0 .../shared/platform/include/platform_common.h | 4 + .../platform/linux-sgx/platform_internal.h | 9 + .../core/shared/platform/linux-sgx/sgx_file.c | 45 +- .../core/shared/platform/linux-sgx/sgx_file.h | 2 + .../core/shared/platform/linux-sgx/sgx_ipfs.c | 118 +- .../core/shared/platform/linux-sgx/sgx_ipfs.h | 2 +- .../shared/platform/linux-sgx/sgx_platform.c | 6 + .../shared/platform/linux-sgx/sgx_pthread.c | 0 .../shared/platform/linux-sgx/sgx_pthread.h | 0 .../platform/linux-sgx/sgx_rsrv_mem_mngr.h | 0 .../shared/platform/linux-sgx/sgx_signal.c | 0 .../shared/platform/linux-sgx/sgx_signal.h | 0 .../shared/platform/linux-sgx/sgx_socket.c | 18 + .../shared/platform/linux-sgx/sgx_socket.h | 4 + .../shared/platform/linux-sgx/sgx_thread.c | 0 .../core/shared/platform/linux-sgx/sgx_time.c | 0 .../core/shared/platform/linux-sgx/sgx_time.h | 0 .../shared/platform/linux-sgx/sgx_wamr.edl | 3 + .../platform/linux-sgx/shared_platform.cmake | 0 .../platform/linux-sgx/untrusted/file.c | 6 + .../platform/linux-sgx/untrusted/pthread.c | 0 .../platform/linux-sgx/untrusted/signal.c | 0 .../platform/linux-sgx/untrusted/socket.c | 0 .../platform/linux-sgx/untrusted/time.c | 0 .../shared/platform/linux}/platform_init.c | 0 .../shared/platform/linux/platform_internal.h | 2 + .../platform/linux/shared_platform.cmake | 0 .../shared/platform/nuttx/nuttx_platform.c | 120 +- .../shared/platform/nuttx/platform_internal.h | 3 + .../platform/nuttx/shared_platform.cmake | 0 .../shared/platform/riot/platform_internal.h | 0 .../core/shared/platform/riot/riot_platform.c | 6 + .../core/shared/platform/riot/riot_thread.c | 0 .../core/shared/platform/riot/riot_time.c | 0 .../platform/riot/shared_platform.cmake | 0 .../core/shared/platform/rt-thread/SConscript | 0 .../platform/rt-thread/platform_internal.h | 0 .../shared/platform/rt-thread/rtt_platform.c | 6 + .../platform/rt-thread/shared_platform.cmake | 0 .../shared/platform/vxworks/platform_init.c | 43 + .../platform/vxworks/platform_internal.h | 2 + .../platform/vxworks/shared_platform.cmake | 0 .../shared/platform/windows/platform_init.c | 0 .../platform/windows/platform_internal.h | 27 + .../platform/windows/shared_platform.cmake | 5 +- .../shared/platform/windows/win_atomic.cpp | 22 + .../core/shared/platform/windows/win_malloc.c | 6 + .../core/shared/platform/windows/win_memmap.c | 0 .../core/shared/platform/windows/win_socket.c | 0 .../core/shared/platform/windows/win_thread.c | 67 +- .../core/shared/platform/windows/win_time.c | 0 .../platform/zephyr/platform_internal.h | 28 +- .../platform/zephyr/shared_platform.cmake | 0 .../shared/platform/zephyr/zephyr_platform.c | 6 + .../shared/platform/zephyr/zephyr_thread.c | 0 .../core/shared/platform/zephyr/zephyr_time.c | 0 .../core/shared/utils/SConscript | 0 .../core/shared/utils/bh_assert.c | 2 +- .../core/shared/utils/bh_assert.h | 4 +- .../core/shared/utils/bh_common.c | 67 + .../core/shared/utils/bh_common.h | 9 + .../core/shared/utils/bh_hashmap.c | 3 + .../core/shared/utils/bh_hashmap.h | 5 +- .../core/shared/utils/bh_list.c | 0 .../core/shared/utils/bh_list.h | 0 .../core/shared/utils/bh_log.c | 26 + .../core/shared/utils/bh_log.h | 8 + .../core/shared/utils/bh_platform.h | 5 - .../core/shared/utils/bh_queue.c | 0 .../core/shared/utils/bh_queue.h | 2 +- .../core/shared/utils/bh_vector.c | 0 .../core/shared/utils/bh_vector.h | 0 .../core/shared/utils/runtime_timer.c | 0 .../core/shared/utils/runtime_timer.h | 2 +- .../core/shared/utils/shared_utils.cmake | 0 .../core/shared/utils/uncommon/SConscript | 0 .../core/shared/utils/uncommon/bh_getopt.c | 0 .../core/shared/utils/uncommon/bh_getopt.h | 0 .../core/shared/utils/uncommon/bh_read_file.c | 0 .../core/shared/utils/uncommon/bh_read_file.h | 0 .../utils/uncommon/shared_uncommon.cmake | 0 .../core/version.h | 7 +- .../doc/build_wamr.md | 213 + .../doc/build_wasm_app.md | 42 +- .../doc/devcontainer.md | 0 .../doc/embed_wamr.md | 2 +- .../doc/export_native_api.md | 0 .../doc/linux_sgx.md | 0 .../doc/memory_tune.md | 7 +- .../doc/memory_usage.md | 134 + .../doc/multi_module.md | 0 .../doc/other_wasm_compilers.md | 0 .../doc/pics/app_framework.PNG | Bin .../doc/pics/embed.PNG | Bin .../doc/pics/extend_library.PNG | Bin .../doc/pics/multi_module_pic1.png | Bin .../doc/pics/native_call_wasm.PNG | Bin .../doc/pics/request.PNG | Bin .../doc/pics/safe.PNG | Bin .../doc/pics/sensor_callflow.PNG | Bin .../doc/pics/sub.PNG | Bin .../doc/pics/vgl_demo.png | Bin .../doc/pics/vgl_demo2.png | Bin .../doc/pics/vgl_demo_linux.png | Bin .../doc/pics/vgl_linux.PNG | Bin .../doc/pics/wamr-arch.JPG | Bin .../doc/pics/wamr_memory_model.png | Bin .../doc/pics/wamr_menu_config.png | Bin .../doc/port_wamr.md | 25 +- .../doc/pthread_impls.md | 59 + .../doc/pthread_library.md | 3 + .../doc/ref_types.md | 0 .../doc/release_ack.md | 0 .../doc/roadmap.md | 0 .../doc/semantic_version.md | 0 .../doc/socket_api.md | 12 +- .../doc/source_debugging.md | 33 +- .../doc/wamr_api.md | 0 .../doc/wasm_c_api.md | 0 .../doc/xip.md | 0 .../language-bindings/go/README.md | 0 .../language-bindings/go/build.sh | 8 +- .../language-bindings/go/go.mod | 0 .../language-bindings/go/go.sum | 1 + .../language-bindings/go/samples/build.sh | 0 .../language-bindings/go/samples/run.sh | 0 .../language-bindings/go/samples/test.go | 0 .../go/samples/wasm-app/build.sh | 0 .../go/samples/wasm-app/main.c | 0 .../language-bindings/go/wamr/cgo.go | 0 .../language-bindings/go/wamr/instance.go | 0 .../go/wamr/instance_test.go | 0 .../language-bindings/go/wamr/module.go | 0 .../language-bindings/go/wamr/module_test.go | 0 .../go/wamr/packaged/include/dummy.go | 0 .../wamr/packaged/lib/darwin-aarch64/dummy.go | 6 + .../wamr/packaged/lib/darwin-amd64/dummy.go | 0 .../go/wamr/packaged/lib/dummy.go | 0 .../go/wamr/packaged/lib/linux-amd64/dummy.go | 0 .../language-bindings/go/wamr/runtime.go | 0 .../language-bindings/go/wamr/runtime_test.go | 0 .../language-bindings/python/.gitignore | 0 .../language-bindings/python/LICENSE | 0 .../language-bindings/python/MANIFEST.in | 1 + .../language-bindings/python/README.md | 34 + .../language-bindings/python/pyproject.toml | 2 +- .../language-bindings/python/setup.py | 65 + .../python/src/wamr}/__init__.py | 0 .../python/src/wamr/libs}/.placeholder | 0 .../python/src/wamr/wamrapi}/__init__.py | 0 .../python/src/wamr/wamrapi/wamr.py | 149 + .../python/src/wamr/wasmcapi}/__init__.py | 0 .../python/src/wamr/wasmcapi}/binding.py | 0 .../python/src/wamr/wasmcapi}/ffi.py | 4 +- .../python/utils/create_lib.sh | 32 + .../python/wamr-api/README.md | 29 + .../python/wamr-api/requirements.txt | 1 + .../python/wamr-api/samples/compile.sh | 11 + .../python/wamr-api/samples/main.py | 22 + .../python/wamr-api/samples/sum.c | 12 + .../python/wasm-c-api/README.md | 7 + .../python/wasm-c-api}/docs/design.md | 0 .../docs/images/python_package_life_cycle.png | Bin .../python/wasm-c-api}/docs/setup_dev_env.md | 0 .../python/wasm-c-api}/requirements.txt | 0 .../python/wasm-c-api}/samples/hello.wat | 0 .../python/wasm-c-api}/samples/hello_oop.py | 0 .../wasm-c-api}/samples/hello_procedural.py | 2 +- .../python/wasm-c-api}/tests/__init__.py | 0 .../python/wasm-c-api}/tests/context.py | 0 .../python/wasm-c-api}/tests/test_advanced.py | 2 +- .../python/wasm-c-api}/tests/test_basic.py | 8 +- .../python/wasm-c-api}/utils/bindgen.py | 8 +- .../product-mini/README.md | 455 + .../hello-world-cmake/CMakeLists.txt | 0 .../app-samples/hello-world-cmake/build.sh | 0 .../app-samples/hello-world-cmake/main.c | 0 .../app-samples/hello-world-cmake/print.c | 0 .../app-samples/hello-world/build.sh | 0 .../app-samples/hello-world/main.c | 0 .../platforms/alios-things/aos.mk | 12 + .../platforms/alios-things/src/main.c | 8 +- .../platforms/alios-things/src/test_wasm.h | 0 .../platforms/android/CMakeLists.txt | 3 +- .../platforms/android/build_jit.sh | 0 .../platforms/android/build_llvm.sh | 1 + .../platforms/android/wasm-jni.cpp | 4 + .../platforms/darwin/CMakeLists.txt | 0 .../platforms/darwin/build_jit.sh | 0 .../platforms/darwin/build_llvm.sh | 1 + .../product-mini/platforms/darwin/main.c | 0 .../product-mini/platforms/esp-idf/.gitignore | 0 .../platforms/esp-idf/CMakeLists.txt | 0 .../platforms/esp-idf/build_and_run.sh | 0 .../platforms/esp-idf/main/CMakeLists.txt | 0 .../platforms/esp-idf/main/main.c | 4 + .../platforms/esp-idf/main/test_wasm.h | 0 .../platforms/esp-idf/sdkconfig.defaults | 0 .../esp-idf/sdkconfig.defaults.esp32 | 0 .../esp-idf/sdkconfig.defaults.esp32c3 | 0 .../platforms/freebsd/CMakeLists.txt | 132 + .../platforms/freebsd/build_jit.sh | 11 + .../platforms/freebsd}/build_llvm.sh | 1 + .../product-mini/platforms/freebsd}/main.c | 0 .../product-mini/platforms/ios/CMakeLists.txt | 0 .../platforms/ios/generate_xcodeproj.sh | 0 .../platforms/linux-sgx/CMakeLists.txt | 37 +- .../linux-sgx/CMakeLists_minimal.txt | 4 - .../linux-sgx/enclave-sample/Makefile | 43 +- .../linux-sgx/enclave-sample/Makefile_minimal | 0 .../platforms/linux/CMakeLists.txt | 21 +- .../product-mini/platforms/linux/build_jit.sh | 0 .../platforms/linux/build_llvm.sh | 7 + .../product-mini/platforms/linux}/main.c | 0 .../product-mini/platforms/nuttx}/main.c | 0 .../product-mini/platforms/nuttx/wamr.mk | 39 +- .../product-mini/platforms/posix/main.c | 183 +- .../platforms/riot/CMakeLists.txt | 5 + .../product-mini/platforms/riot/Makefile | 0 .../product-mini/platforms/riot/iwasmt.c | 17 +- .../product-mini/platforms/riot/test_wasm.h | 0 .../platforms/rt-thread/SConscript | 0 .../product-mini/platforms/rt-thread/iwasm.c | 0 .../platforms/rt-thread/iwasm.cmake | 0 .../platforms/vxworks/CMakeLists.txt | 0 .../product-mini/platforms/vxworks/main.c | 6 + .../platforms/windows/CMakeLists.txt | 5 - .../platforms/windows/build_llvm.py | 0 .../product-mini/platforms/windows/main.c | 139 +- .../platforms/zephyr/simple/CMakeLists.txt | 10 + .../platforms/zephyr/simple/README_docker.md | 0 .../platforms/zephyr/simple/boards/esp32.conf | 0 .../zephyr/simple/boards/nucleo767zi.conf | 0 .../zephyr/simple/boards/qemu_arc.conf | 0 .../zephyr/simple/boards/qemu_cortex_a53.conf | 0 .../zephyr/simple/boards/qemu_riscv32.conf | 0 .../zephyr/simple/boards/qemu_riscv64.conf | 0 .../zephyr/simple/boards/qemu_x86_nommu.conf | 0 .../zephyr/simple/boards/qemu_xtensa.conf | 0 .../platforms/zephyr/simple/build_and_run.sh | 0 .../zephyr/simple/esp32_custom_linker.ld | 0 .../platforms/zephyr/simple/src/main.c | 11 +- .../platforms/zephyr/simple/src/test_wasm.h | 0 .../zephyr/simple/src/test_wasm_riscv64.h | 0 .../simple/src/wasm-app-riscv64/build.sh | 0 .../zephyr/simple/src/wasm-app-riscv64/main.c | 0 .../samples/README.md | 17 + .../samples/basic/.gitignore | 0 .../samples/basic/CMakeLists.txt | 8 +- .../samples/basic/README.md | 0 .../samples/basic/build.sh | 0 .../samples/basic/run.sh | 0 .../samples/basic/src/main.c | 0 .../samples/basic/src/native_impl.c | 4 - .../samples/basic/wasm-apps/testapp.c | 0 .../samples/file/CMakeLists.txt | 0 .../samples/file/README.md | 0 .../samples/file/src/CMakeLists.txt | 8 +- .../samples/file/src/main.c | 12 +- .../samples/file/wasm-app/CMakeLists.txt | 0 .../samples/file/wasm-app/main.c | 77 +- .../samples/gui/README.md | 0 .../samples/gui/build.sh | 0 .../samples/gui/lv_config/lv_conf.h | 0 .../samples/gui/lv_config/lv_drv_conf.h | 0 .../samples/gui/lv_config/system_header.h | 0 .../samples/gui/wamr_config_gui.cmake | 0 .../samples/gui/wasm-apps/build_apps.sh | 0 .../samples/gui/wasm-apps/decrease/Makefile | 0 .../samples/gui/wasm-apps/decrease/src/main.c | 0 .../gui/wasm-apps/increase/CMakeLists.txt | 0 .../samples/gui/wasm-apps/increase/Makefile | 6 +- .../samples/gui/wasm-apps/increase/src/main.c | 0 .../src/platform/linux/iwasm_main.c | 0 .../src/platform/linux/lv_drv_conf.h | 0 .../src/platform/linux/main.c | 0 .../src/platform/zephyr/LICENSE | 0 .../src/platform/zephyr/XPT2046.c | 0 .../src/platform/zephyr/XPT2046.h | 0 .../src/platform/zephyr/board_config.h | 0 .../src/platform/zephyr/display.h | 0 .../src/platform/zephyr/display_ili9340.c | 0 .../src/platform/zephyr/display_ili9340.h | 0 .../zephyr/display_ili9340_adafruit_1480.c | 0 .../src/platform/zephyr/iwasm_main.c | 0 .../src/platform/zephyr/main.c | 0 .../src/platform/zephyr/pin_config_jlf.h | 0 .../src/platform/zephyr/pin_config_stm32.h | 0 .../samples/littlevgl/LICENCE.txt | 0 .../samples/littlevgl/README.md | 0 .../samples/littlevgl/build.sh | 0 .../samples/littlevgl/lv_config/lv_conf.h | 0 .../samples/littlevgl/lv_config/lv_drv_conf.h | 0 .../vgl-native-ui-app/CMakeLists.txt | 0 .../vgl-native-ui-app/CMakeLists.txt.in | 0 .../vgl-native-ui-app/lv-drivers/.gitignore | 0 .../lv-drivers/display_indev.h | 0 .../lv-drivers/indev/mouse.c | 0 .../lv-drivers/indev/mouse.h | 0 .../lv-drivers/linux_display_indev.c | 0 .../lv-drivers/system_header.h | 0 .../littlevgl/vgl-native-ui-app/main.c | 0 .../littlevgl/vgl-wasm-runtime/CMakeLists.txt | 0 .../vgl-wasm-runtime/src/display_indev.h | 0 .../src/platform/linux/display_indev.c | 0 .../src/platform/linux/iwasm_main.c | 0 .../src/platform/linux/main.c | 0 .../src/platform/linux/mouse.c | 0 .../src/platform/zephyr/LICENSE | 0 .../src/platform/zephyr/XPT2046.c | 0 .../src/platform/zephyr/XPT2046.h | 0 .../src/platform/zephyr/board_config.h | 0 .../src/platform/zephyr/display.h | 0 .../src/platform/zephyr/display_ili9340.c | 0 .../src/platform/zephyr/display_ili9340.h | 0 .../zephyr/display_ili9340_adafruit_1480.c | 0 .../src/platform/zephyr/display_indev.c | 0 .../src/platform/zephyr/iwasm_main.c | 0 .../src/platform/zephyr/main.c | 0 .../src/platform/zephyr/pin_config_jlf.h | 0 .../src/platform/zephyr/pin_config_stm32.h | 0 .../littlevgl/wamr_config_littlevgl.cmake | 0 .../littlevgl/wasm-apps/Makefile_wasm_app | 0 .../wasm-apps/Makefile_wasm_app_no_wasi | 0 .../littlevgl/wasm-apps/build_wasm_app.sh | 0 .../littlevgl/wasm-apps/src/display_indev.h | 0 .../samples/littlevgl/wasm-apps/src/main.c | 0 .../littlevgl/wasm-apps/src/system_header.h | 0 .../samples/multi-module/CMakeLists.txt | 9 +- .../samples/multi-module/src/main.c | 0 .../multi-module/wasm-apps/CMakeLists.txt | 0 .../samples/multi-module/wasm-apps/mA.c | 0 .../samples/multi-module/wasm-apps/mB.c | 0 .../samples/multi-module/wasm-apps/mC.c | 0 .../samples/multi-module/wasm-apps/mD.cpp | 0 .../samples/multi-module/wasm-apps/mE.cpp | 0 .../samples/multi-thread/CMakeLists.txt | 8 +- .../multi-thread/wasm-apps/CMakeLists.txt | 6 + .../samples/multi-thread/wasm-apps/main.c | 0 .../wasm-apps/main_global_atomic.c | 48 + .../wasm-apps/main_thread_exception.c | 36 + .../samples/native-lib/CMakeLists.txt | 23 +- .../samples/native-lib/README.md | 12 +- .../samples/native-lib/test_add.c | 0 .../samples/native-lib/test_hello.c | 34 + .../samples/native-lib/test_hello2.c | 59 + .../samples/native-lib/test_sqrt.c | 0 .../native-lib/wasm-app/CMakeLists.txt | 0 .../samples/native-lib/wasm-app/main.c | 70 + .../samples/ref-types/CMakeLists.txt | 19 +- .../samples/ref-types/src/hello.c | 0 .../samples/ref-types/src/hello.wat | 0 .../samples/sgx-ra/CMakeLists.txt | 7 +- .../samples/sgx-ra/README.md | 203 + .../samples/sgx-ra/wasm-app/CMakeLists.txt | 0 .../samples/sgx-ra/wasm-app/main.c | 117 + .../samples/simple/.gitignore | 0 .../samples/simple/CMakeLists.txt | 5 + .../samples/simple/README.md | 0 .../samples/simple/build.sh | 6 +- .../profiles/arm-interp/toolchain.cmake | 0 .../arm-interp/wamr_config_simple.cmake | 0 .../simple/profiles/arm64-aot/toolchain.cmake | 0 .../arm64-aot/wamr_config_simple.cmake | 0 .../profiles/arm64-interp/toolchain.cmake | 0 .../arm64-interp/wamr_config_simple.cmake | 0 .../host-aot/wamr_config_simple.cmake | 0 .../host-interp/wamr_config_simple.cmake | 0 .../macos-interp/wamr_config_simple.cmake | 11 + .../samples/simple/sample_test_run.py | 224 + .../samples/simple/src/iwasm_main.c | 0 .../samples/simple/src/main.c | 0 .../samples/simple/wasm-apps/connection.c | 0 .../simple/wasm-apps/event_publisher.c | 0 .../simple/wasm-apps/event_subscriber.c | 0 .../simple/wasm-apps/request_handler.c | 0 .../samples/simple/wasm-apps/request_sender.c | 0 .../samples/simple/wasm-apps/sensor.c | 0 .../samples/simple/wasm-apps/timer.c | 0 .../samples/socket-api/CMakeLists.txt | 8 +- .../samples/socket-api/README.md | 6 +- .../samples/socket-api/sample_test_run.py | 141 + .../socket-api/wasm-src/CMakeLists.txt | 4 +- .../socket-api/wasm-src/addr_resolve.c | 0 .../samples/socket-api/wasm-src/inc/.gitkeep | 0 .../socket-api/wasm-src/multicast_client.c | 0 .../socket-api/wasm-src/multicast_server.c | 0 .../samples/socket-api/wasm-src/send_recv.c | 15 +- .../samples/socket-api/wasm-src/socket_opts.c | 0 .../socket-api/wasm-src/socket_utils.h | 0 .../samples/socket-api/wasm-src/tcp_client.c | 0 .../samples/socket-api/wasm-src/tcp_server.c | 0 .../socket-api/wasm-src/timeout_client.c | 0 .../socket-api/wasm-src/timeout_server.c | 0 .../samples/socket-api/wasm-src/udp_client.c | 0 .../samples/socket-api/wasm-src/udp_server.c | 0 .../samples/spawn-thread/CMakeLists.txt | 8 +- .../samples/spawn-thread/src/main.c | 0 .../spawn-thread/wasm-apps/CMakeLists.txt | 0 .../samples/spawn-thread/wasm-apps/sum.c | 0 .../samples/wasi-threads/CMakeLists.txt | 80 + .../samples/wasi-threads/README.md | 22 + .../wasi-threads/wasm-apps/CMakeLists.txt | 46 + .../wasi-threads/wasm-apps/no_pthread.c | 74 + .../wasm-apps/wasi_thread_start.S | 22 + .../wasm-apps/wasi_thread_start.h | 32 + .../samples/wasm-c-api-imports/.gitignore | 2 + .../samples/wasm-c-api-imports/CMakeLists.txt | 174 + .../samples/wasm-c-api-imports/README.md | 174 + .../wasm-c-api-imports/host/CMakeLists.txt | 12 + .../wasm-c-api-imports/host/example1.c | 204 + .../wasm-c-api-imports/wasm/CMakeLists.txt | 47 + .../wasm-c-api-imports/wasm/inc/.gitkeep} | 0 .../wasm-c-api-imports/wasm/send_recv.c | 244 + .../samples/wasm-c-api/CMakeLists.txt | 77 +- .../samples/wasm-c-api/README.md | 8 +- .../samples/wasm-c-api/src/LICENSE | 0 .../samples/wasm-c-api/src/callback.c | 8 +- .../samples/wasm-c-api/src/callback.wat | 0 .../samples/wasm-c-api/src/callback_chain.c | 2 +- .../samples/wasm-c-api/src/callback_chain.wat | 4 +- .../samples/wasm-c-api/src/clone.c | 535 ++ .../samples/wasm-c-api/src/clone.wat | 15 + .../samples/wasm-c-api/src/empty_imports.c | 14 +- .../samples/wasm-c-api/src/empty_imports.wat | 0 .../samples/wasm-c-api/src/global.c | 40 +- .../samples/wasm-c-api/src/global.wat | 0 .../wasm-c-api/src/globalexportimport-0.wat | 0 .../wasm-c-api/src/globalexportimport-1.wat | 0 .../wasm-c-api/src/globalexportimport.c | 29 +- .../samples/wasm-c-api/src/hello.c | 8 +- .../samples/wasm-c-api/src/hello.wat | 0 .../samples/wasm-c-api/src/hostref.c | 40 +- .../samples/wasm-c-api/src/hostref.wat | 0 .../samples/wasm-c-api/src/memory.c | 21 +- .../samples/wasm-c-api/src/memory.wat | 0 .../samples/wasm-c-api/src/multi.c | 8 +- .../samples/wasm-c-api/src/multi.wat | 0 .../samples/wasm-c-api/src/reflect.c | 0 .../samples/wasm-c-api/src/reflect.wat | 2 +- .../samples/wasm-c-api/src/serialize.c | 131 + .../samples/wasm-c-api/src/serialize.wat | 4 + .../samples/wasm-c-api/src/table.c | 13 +- .../samples/wasm-c-api/src/table.wat | 0 .../samples/wasm-c-api/src/threads.c | 187 + .../samples/wasm-c-api/src/threads.wat | 5 + .../samples/wasm-c-api/src/trap.c | 2 + .../samples/wasm-c-api/src/trap.wat | 0 .../wasm-c-api/src/utils/multi_module_utils.c | 0 .../samples/workload/CMakeLists.txt | 116 + .../samples/workload/README.md | 29 +- .../samples/workload/XNNPACK/.gitignore | 0 .../samples/workload/XNNPACK/CMakeLists.txt | 65 +- .../samples/workload/XNNPACK/README.md | 4 +- .../samples/workload/XNNPACK/benchmark.patch | 0 .../samples/workload/XNNPACK/xnnpack.patch | 141 + .../samples/workload/bwa/.gitignore | 0 .../workload/bwa/CMakeLists.bwa_wasm.txt | 15 +- .../samples/workload/bwa/CMakeLists.txt | 73 + .../samples/workload/bwa/README.md | 4 +- .../samples/workload/bwa/bwa.patch | 0 .../samples/workload/cmake/FindBinaryen.cmake | 43 + .../samples/workload/cmake/FindWASISDK.cmake | 38 + .../samples/workload/include/.gitkeep} | 0 .../samples/workload/meshoptimizer/.gitignore | 0 .../workload/meshoptimizer/CMakeLists.txt | 38 + .../samples/workload/meshoptimizer/README.md | 4 +- .../workload/meshoptimizer/codecbench.patch | 18 +- .../samples/workload/preparation.sh | 12 +- .../samples/workload/tensorflow/README.md | 22 +- .../samples/workload/tensorflow/build.sh | 86 +- .../samples/workload/tensorflow/tf_lite.patch | 0 .../samples/workload/wasm-av1/.gitignore | 0 .../workload/wasm-av1/CMakeLists.avx_wasm.txt | 10 +- .../samples/workload/wasm-av1/CMakeLists.txt | 44 + .../samples/workload/wasm-av1/README.md | 4 +- .../samples/workload/wasm-av1/av1-clang.patch | 0 .../samples/workload/wasm-av1/build.sh | 4 +- .../samples/workload/wasm-av1/wasm-av1.patch | 0 .../test-tools/.gitignore | 0 .../test-tools/IoT-APP-Store-Demo/README.md | 0 .../IoT-APP-Store-Demo/docker-compose.yml | 0 .../IoT-APP-Store-Demo/wasm_django/Dockerfile | 9 + .../IoT-APP-Store-Demo/wasm_django/db.sqlite3 | Bin .../wasm_django/devices}/__init__.py | 0 .../wasm_django/devices/admin.py | 0 .../wasm_django/devices/apps.py | 0 .../devices/migrations}/__init__.py | 0 .../wasm_django/devices/models.py | 0 .../devices/templates/application.html | 0 .../devices/templates/appstore.html | 0 .../wasm_django/devices/templates/empty.html | 0 .../wasm_django/devices/templates/help.html | 4 +- .../wasm_django/devices/templates/mysite.html | 0 .../wasm_django/devices/tests.py | 0 .../wasm_django/devices/views.py | 0 .../IoT-APP-Store-Demo/wasm_django/manage.py | 0 .../wasm_django/mysite}/__init__.py | 0 .../wasm_django/mysite/settings.py | 0 .../wasm_django/mysite/urls.py | 0 .../wasm_django/mysite/wsgi.py | 0 .../wasm_django/server/Dockerfile | 6 + .../wasm_django/server/wasm_server.py | 34 +- .../wasm_django/static/css/application.css | 0 .../wasm_django/static/css/appstore.css | 0 .../wasm_django/static/css/index.css | 0 .../wasm_django/static/js/application.js | 0 .../wasm_django/static/js/appstore.js | 0 .../wasm_django/static/js/index.js | 0 .../wasm_django/static/photo/app(1).png | Bin .../wasm_django/static/photo/application.png | Bin .../wasm_django/static/photo/delete.png | Bin .../wasm_django/static/photo/download(1).png | Bin .../wasm_django/static/photo/menu.png | Bin .../static/photo/milky-way-2695569_1280.jpg | Bin .../wasm_django/static/photo/net_device.png | Bin .../static/photo/software-icon-32081.png | Bin .../wasm_django/static/photo/totalblack.png | Bin .../wasm_django/static/upload/connection.wasm | Bin 0 -> 6280 bytes .../static/upload/event_publisher.wasm | Bin 0 -> 4958 bytes .../static/upload/event_subscriber.wasm | Bin 0 -> 4015 bytes .../static/upload/request_handler.wasm | Bin 0 -> 6776 bytes .../static/upload/request_sender.wasm | Bin 0 -> 5311 bytes .../wasm_django/static/upload/sensor.wasm | Bin 0 -> 4455 bytes .../wasm_django/static/upload/simple | Bin 0 -> 387456 bytes .../static/upload/sys/connection.wasm | Bin 0 -> 6280 bytes .../static/upload/sys/event_publisher.wasm | Bin 0 -> 4958 bytes .../static/upload/sys/event_subscriber.wasm | Bin 0 -> 4015 bytes .../static/upload/sys/request_handler.wasm | Bin 0 -> 6776 bytes .../static/upload/sys/request_sender.wasm | Bin 0 -> 5311 bytes .../wasm_django/static/upload/sys/timer.wasm | Bin 0 -> 2388 bytes .../wasm_django/static/upload/timer.wasm | Bin 0 -> 2388 bytes .../wasm_django/static/upload/ui_app.wasm | Bin 0 -> 1912 bytes .../static/upload/wasm_runtime_wgl | Bin 0 -> 615016 bytes .../test-tools/binarydump-tool/CMakeLists.txt | 0 .../test-tools/binarydump-tool/binarydump.c | 0 .../test-tools/component-test/README.md | 0 .../test-tools/component-test/__init__.py | 0 .../component-test/framework/__init__.py | 0 .../component-test/framework/case_base.py | 0 .../component-test/framework/engine.py | 0 .../component-test/framework/framework.py | 0 .../component-test/framework/suite.py | 0 .../component-test/framework/test_api.py | 0 .../component-test/framework/test_utils.py | 0 .../component-test/harness}/__init__.py | 0 .../component-test/harness/harness_api.py | 0 .../host-clients/src/host_app_sample.c | 0 .../component-test/host-clients/src/makefile | 0 .../test-tools/component-test/set_dev_env.sh | 0 .../test-tools/component-test/start.py | 0 .../suites/01-life-cycle}/__init__.py | 0 .../cases/01-install}/__init__.py | 0 .../01-life-cycle/cases/01-install/case.py | 0 .../cases/02-request}/__init__.py | 0 .../01-life-cycle/cases/02-request/case.py | 0 .../01-life-cycle/cases/03-event}/__init__.py | 0 .../01-life-cycle/cases/03-event/case.py | 0 .../cases/04-request-internal}/__init__.py | 0 .../cases/04-request-internal/case.py | 0 .../cases/05-event-internal}/__init__.py | 0 .../cases/05-event-internal/case.py | 0 .../01-life-cycle/cases/06-timer}/__init__.py | 0 .../01-life-cycle/cases/06-timer/case.py | 0 .../cases/07-sensor}/__init__.py | 0 .../01-life-cycle/cases/07-sensor/case.py | 0 .../cases/08-on-destroy/__init__.py} | 0 .../01-life-cycle/cases/08-on-destroy/case.py | 0 .../suites/01-life-cycle/cases/__init__.py} | 0 .../suites/01-life-cycle/suite_setup.py | 0 .../01-life-cycle/test-app/01_install.c | 0 .../01-life-cycle/test-app/02_request.c | 0 .../suites/01-life-cycle/test-app/03_event.c | 0 .../test-app/04_request_internal_req.c | 0 .../test-app/04_request_internal_resp.c | 0 .../test-app/05_event_internal_provider.c | 0 .../test-app/05_event_internal_subscriber.c | 0 .../suites/01-life-cycle/test-app/06_timer.c | 0 .../suites/01-life-cycle/test-app/07_sensor.c | 0 .../01-life-cycle/test-app/08_on_destroy.c | 0 .../suites/01-life-cycle/test-app/build.sh | 0 .../01-life-cycle/tools/product/start.sh | 0 .../01-life-cycle/tools/product/stop.sh | 0 .../component-test/suites/__init__.py | 0 .../component-test/suites/readme.txt | 0 .../test-tools/host-tool/CMakeLists.txt | 0 .../host-tool/external/cJSON/LICENSE | 0 .../host-tool/external/cJSON/cJSON.c | 0 .../host-tool/external/cJSON/cJSON.h | 0 .../host-tool/external/cJSON/cjson.cmake | 0 .../host-tool/src/host_tool_utils.c | 60 +- .../host-tool/src/host_tool_utils.h | 0 .../test-tools/host-tool/src/main.c | 0 .../test-tools/host-tool/src/transport.c | 0 .../test-tools/host-tool/src/transport.h | 0 .../collect_files.py | 245 + .../test-tools/wamr-ide/.gitattributes | 0 .../wamr-ide/Media/Config_building_target.png | Bin .../wamr-ide/Media/build_folder.png | Bin .../wamr-ide/Media/build_terminal.png | Bin .../Media/change_workspace_dialog.png | Bin .../wamr-ide/Media/compilation_config.png | Bin .../wamr-ide/Media/compilation_config_2.png | Bin .../test-tools/wamr-ide/Media/debug.png | Bin .../wamr-ide/Media/decoration_for_files.png | Bin .../wamr-ide/Media/docker_config.jpg | Bin .../wamr-ide/Media/docker_engine_config.png | Bin .../wamr-ide/Media/docker_images.png | Bin .../wamr-ide/Media/install_from_vsix.png | Bin .../wamr-ide/Media/new_project_page.png | Bin .../wamr-ide/Media/open_project_page.png | Bin .../wamr-ide/Media/project_template.png | Bin .../wamr-ide/Media/right_click_menus_1.png | Bin .../wamr-ide/Media/right_click_menus_2.png | Bin .../test-tools/wamr-ide/Media/run.png | Bin .../wamr-ide/Media/save_configuration.png | Bin .../Media/set_up_workspace_message.png | Bin .../wamr-ide/Media/wamr_ide_main_menu.png | Bin .../test-tools/wamr-ide/README.md | 102 +- .../test-tools/wamr-ide/Script/build.bat | 0 .../test-tools/wamr-ide/Script/build.sh | 0 .../wamr-ide/VSCode-Extension/.eslintrc.json | 13 +- .../wamr-ide/VSCode-Extension/.gitignore | 0 .../VSCode-Extension/.prettierrc.json | 0 .../VSCode-Extension/.vscode/extensions.json | 0 .../VSCode-Extension/.vscode/launch.json | 0 .../VSCode-Extension/.vscode/tasks.json | 0 .../wamr-ide/VSCode-Extension/.vscodeignore | 0 .../wamr-ide/VSCode-Extension/CONTRIBUTING.md | 34 + .../wamr-ide/VSCode-Extension/LICENSE | 0 .../wamr-ide/VSCode-Extension/README.md | 14 +- .../wamr-ide/VSCode-Extension/package.json | 13 +- .../VSCode-Extension/resource/debug/README.md | 15 + .../resource/debug/darwin/.placeholder | 0 .../resource/debug/linux/.placeholder | 0 .../resource/debug/windows/.placeholder | 0 .../resource/scripts/CMakeLists.txt | 0 .../resource/scripts/boot_debugger_server.bat | 2 +- .../resource/scripts/boot_debugger_server.sh | 2 +- .../resource/scripts/build.bat | 2 +- .../resource/scripts/build.sh | 2 +- .../resource/scripts/destroy.bat | 0 .../resource/scripts/destroy.sh | 0 .../resource/scripts/project.cmake | 0 .../VSCode-Extension/resource/scripts/run.bat | 2 +- .../VSCode-Extension/resource/scripts/run.sh | 2 +- .../libc-builtin-sysroot/include/assert.h | 0 .../libc-builtin-sysroot/include/ctype.h | 0 .../libc-builtin-sysroot/include/errno.h | 0 .../libc-builtin-sysroot/include/fcntl.h | 0 .../libc-builtin-sysroot/include/inttypes.h | 0 .../libc-builtin-sysroot/include/limits.h | 0 .../libc-builtin-sysroot/include/pthread.h | 0 .../libc-builtin-sysroot/include/stdarg.h | 0 .../libc-builtin-sysroot/include/stdbool.h | 0 .../libc-builtin-sysroot/include/stdint.h | 0 .../libc-builtin-sysroot/include/stdio.h | 0 .../libc-builtin-sysroot/include/stdlib.h | 0 .../libc-builtin-sysroot/include/string.h | 0 .../libc-builtin-sysroot/include/strings.h | 0 .../resource/webview/css/style.css | 0 .../resource/webview/js/configbuildtarget.js | 9 +- .../resource/webview/js/newproj.js | 0 .../webview/page/configBuildTarget.html | 0 .../resource/webview/page/newProject.html | 0 .../VSCode-Extension/src/constants.ts | 7 + .../src/debugConfigurationProvider.ts | 42 + .../src/decorationProvider.ts | 41 +- .../VSCode-Extension/src/extension.ts | 457 +- .../VSCode-Extension/src/taskProvider.ts | 26 +- .../src/utilities/directoryUtilities.ts | 211 + .../src/utilities/dockerUtilities.ts | 125 + .../VSCode-Extension/src/utilities/getUri.ts | 2 +- .../src/utilities/lldbUtilities.ts | 119 + .../src/view/NewProjectPanel.ts | 95 +- .../src/view/TargetConfigPanel.ts | 113 +- .../wamr-ide/VSCode-Extension/tsconfig.json | 16 + .../WASM-Debug-Server/Docker/Dockerfile | 30 + .../WASM-Debug-Server/Docker/README.md | 0 .../Docker/build_docker_image.bat | 0 .../Docker/build_docker_image.sh | 0 .../Docker/resource/debug.sh | 0 .../WASM-Debug-Server/Docker/resource/run.sh | 0 .../WASM-Toolchain/Docker/.dockerignore | 0 .../wamr-ide/WASM-Toolchain/Docker/Dockerfile | 71 + .../wamr-ide/WASM-Toolchain/Docker/README.md | 0 .../Docker/build_docker_image.bat | 0 .../Docker/build_docker_image.sh | 0 .../Docker/resource/build_wasm.sh | 0 .../Docker/resource/wamr_toolchain.cmake | 0 .../tests/benchmarks/coremark/README.md | 2 +- .../tests/benchmarks/coremark/build.sh | 4 +- .../tests/benchmarks/coremark/run.sh | 0 .../tests/benchmarks/jetstream/README.md | 2 +- .../tests/benchmarks/jetstream/build.sh | 0 .../benchmarks/jetstream/jetstream.patch | 0 .../tests/benchmarks/jetstream/run_aot.sh | 0 .../tests/benchmarks/libsodium/README.md | 23 + .../tests/benchmarks/libsodium/build.sh | 42 + .../tests/benchmarks/libsodium/test_aot.sh | 59 + .../tests/benchmarks/polybench/README.md | 2 +- .../tests/benchmarks/polybench/build.sh | 3 +- .../tests/benchmarks/polybench/run_aot.sh | 0 .../tests/benchmarks/polybench/run_interp.sh | 0 .../tests/benchmarks/sightglass/README.md | 2 +- .../tests/benchmarks/sightglass/build.sh | 0 .../tests/benchmarks/sightglass/run_aot.sh | 0 .../tests/benchmarks/sightglass/run_interp.sh | 0 .../tests/wamr-test-suites/README.md | 0 .../wamr-test-suites/spec-test-script/CHANGES | 0 .../wamr-test-suites/spec-test-script/all.py | 138 +- .../wamr-test-suites/spec-test-script/all.sh | 0 .../spec-test-script/collect_coverage.sh | 82 + .../spec-test-script/ignore_cases.patch | 0 .../spec-test-script/runtest.py | 376 +- .../spec-test-script/simd_ignore_cases.patch | 0 .../tail-call/return_call.wast | 0 .../tail-call/return_call_indirect.wast | 0 .../thread_proposal_fix_atomic_case.patch | 0 .../thread_proposal_ignore_cases.patch | 0 .../tests/wamr-test-suites/test_wamr.sh | 381 +- .../wasi-test-script/run_wasi_tests.sh | 80 + .../wamr-compiler/CMakeLists.txt | 20 +- .../wamr-compiler/README.md | 32 + .../wamr-compiler/build_llvm.py | 0 .../wamr-compiler/build_llvm.sh | 1 + .../wamr-compiler/build_llvm_arc.sh | 1 + .../wamr-compiler/build_llvm_xtensa.sh | 1 + .../wamr-compiler/main.c | 19 + .../wamr-sdk/Kconfig | 0 .../wamr-sdk/Makefile | 0 .../wamr-sdk/README.md | 7 + .../wamr-sdk/app/CMakeLists.txt | 0 .../app/libc-builtin-sysroot/include/assert.h | 0 .../app/libc-builtin-sysroot/include/ctype.h | 0 .../app/libc-builtin-sysroot/include/errno.h | 0 .../app/libc-builtin-sysroot/include/fcntl.h | 0 .../libc-builtin-sysroot/include/inttypes.h | 0 .../app/libc-builtin-sysroot/include/limits.h | 0 .../libc-builtin-sysroot/include/pthread.h | 0 .../libc-builtin-sysroot/include/semaphore.h | 0 .../app/libc-builtin-sysroot/include/stdarg.h | 0 .../libc-builtin-sysroot/include/stdbool.h | 0 .../app/libc-builtin-sysroot/include/stdint.h | 47 +- .../app/libc-builtin-sysroot/include/stdio.h | 0 .../app/libc-builtin-sysroot/include/stdlib.h | 0 .../app/libc-builtin-sysroot/include/string.h | 0 .../libc-builtin-sysroot/include/strings.h | 0 .../share/defined-symbols.txt | 0 .../wamr-sdk/app/wamr_toolchain.cmake | 0 .../wamr-sdk/app/wasi_toolchain.cmake | 0 .../wamr-sdk/build_sdk.sh | 6 +- .../wamr-sdk/menuconfig.sh | 0 .../wamr-sdk/runtime/CMakeLists.txt | 0 .../wamr-sdk/wamr_config_default.cmake | 0 .../wamr-sdk/wamr_config_macos_release.cmake | 40 + .../wamr-sdk/wamr_config_ubuntu_release.cmake | 40 + .../zephyr/module.yml | 0 1352 files changed, 54247 insertions(+), 14600 deletions(-) delete mode 100644 lib/wasm-micro-runtime-WAMR-1.1.1/.github/workflows/compilation_on_android_ubuntu.yml delete mode 100644 lib/wasm-micro-runtime-WAMR-1.1.1/.github/workflows/compilation_on_windows.yml delete mode 100644 lib/wasm-micro-runtime-WAMR-1.1.1/README.md delete mode 100644 lib/wasm-micro-runtime-WAMR-1.1.1/core/app-mgr/README.md delete mode 100644 lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/wasm_memory.c delete mode 100644 lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/fe/jit_emit_function.c delete mode 100644 lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/fe/jit_emit_memory.c delete mode 100644 lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/jit_compiler.c delete mode 100644 lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/interpreter/wasm_runtime.h delete mode 100644 lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/lib-rats/lib_rats_wrapper.c delete mode 100644 lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/lib-rats/lib_rats_wrapper.h delete mode 100644 lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/numeric_limits.h delete mode 100644 lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/wasi-nn/.dockerignore delete mode 100644 lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/wasi-nn/README.md delete mode 100644 lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/wasi-nn/logger.h delete mode 100644 lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/wasi-nn/test/requirements.txt delete mode 100755 lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/wasi-nn/test/test_tensorflow.c delete mode 100644 lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/wasi-nn/wasi_nn.cmake delete mode 100644 lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/wasi-nn/wasi_nn.h delete mode 100644 lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/wasi-nn/wasi_nn_common.h delete mode 100644 lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/wasi-nn/wasi_nn_native.c delete mode 100644 lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/wasi-nn/wasi_nn_tensorflow.cpp delete mode 100644 lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/wasi-nn/wasi_nn_tensorflow.hpp delete mode 100644 lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/common/posix/posix_malloc.c delete mode 100644 lib/wasm-micro-runtime-WAMR-1.1.1/core/version.h.in delete mode 100644 lib/wasm-micro-runtime-WAMR-1.1.1/doc/build_wamr.md delete mode 100644 lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/python/README.md delete mode 100755 lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/python/setup.py delete mode 100644 lib/wasm-micro-runtime-WAMR-1.1.1/samples/native-lib/wasm-app/main.c delete mode 100644 lib/wasm-micro-runtime-WAMR-1.1.1/samples/sgx-ra/README.md delete mode 100644 lib/wasm-micro-runtime-WAMR-1.1.1/samples/sgx-ra/wasm-app/main.c delete mode 120000 lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/XNNPACK/build_workload.sh delete mode 100644 lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/XNNPACK/xnnpack.patch delete mode 100644 lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/bwa/CMakeLists.txt delete mode 120000 lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/bwa/build_workload.sh delete mode 100644 lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/cmake/preparation.cmake delete mode 100755 lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/docker/build_workload.sh delete mode 100644 lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/meshoptimizer/CMakeLists.txt delete mode 120000 lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/meshoptimizer/build_workload.sh delete mode 100644 lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/wasm-av1/CMakeLists.txt delete mode 120000 lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/wasm-av1/build_workload.sh delete mode 100644 lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/connection.wasm delete mode 100644 lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/event_publisher.wasm delete mode 100644 lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/event_subscriber.wasm delete mode 100644 lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/request_handler.wasm delete mode 100644 lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/request_sender.wasm delete mode 100644 lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/sensor.wasm delete mode 100755 lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/simple delete mode 100644 lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/sys/connection.wasm delete mode 100644 lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/sys/event_publisher.wasm delete mode 100644 lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/sys/event_subscriber.wasm delete mode 100644 lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/sys/request_handler.wasm delete mode 100644 lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/sys/request_sender.wasm delete mode 100644 lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/sys/timer.wasm delete mode 100644 lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/timer.wasm delete mode 100644 lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/ui_app.wasm delete mode 100755 lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/vgl_wasm_runtime delete mode 100755 lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/wasm_runtime_wgl delete mode 100755 lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/build-wasi-sdk/build_wasi_sdk.py delete mode 100644 lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/build-wasi-sdk/patches/wasi_libc.patch delete mode 100644 lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/build-wasi-sdk/patches/wasi_sdk.patch delete mode 100644 lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/debug/README.md delete mode 100644 lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/src/debugConfigurationProvider.ts delete mode 100644 lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/src/utilities/directoryUtilities.ts delete mode 100644 lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/tsconfig.json rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/.clang-tidy (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/.devcontainer/Dockerfile (69%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/.devcontainer/devcontainer.json (87%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/.github/scripts/extract_from_release_notes.py create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/.github/scripts/fetch_and_compare_version.py create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/.github/scripts/reuse_latest_release_binaries.py create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/.github/workflows/build_docker_images.yml create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/.github/workflows/build_iwasm_release.yml create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/.github/workflows/build_llvm_libraries.yml create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/.github/workflows/build_wamr_lldb.yml create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/.github/workflows/build_wamr_sdk.yml create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/.github/workflows/build_wamr_vscode_ext.yml create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/.github/workflows/build_wamrc.yml rename lib/{wasm-micro-runtime-WAMR-1.1.1/.github/workflows/codeing_guildelines.yml => wasm-micro-runtime-WAMR-1.2.2/.github/workflows/coding_guidelines.yml} (70%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/.github/workflows/compilation_on_android_ubuntu.yml rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/.github/workflows/compilation_on_macos.yml (55%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/.github/workflows/compilation_on_nuttx.yml (58%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/.github/workflows/compilation_on_sgx.yml (60%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/.github/workflows/compilation_on_windows.yml create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/.github/workflows/create_tag.yml create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/.github/workflows/release_process.yml create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/.github/workflows/reuse_latest_release_binaries.yml create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/.github/workflows/spec_test_on_nuttx.yml rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/.gitignore (68%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/ATTRIBUTIONS.md (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/CMakeLists.txt (80%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/CODE_OF_CONDUCT.md (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/CONTRIBUTING.md (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/LICENSE (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/ORG_CODE_OF_CONDUCT.md (100%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/README.md create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/RELEASE_NOTES.md rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/SConscript (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/SECURITY.md (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/TSC_Charter.md (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/assembly-script/.gitignore (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/assembly-script/README.md (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/assembly-script/package-lock.json (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/assembly-script/package.json (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/assembly-script/samples/event_publisher.ts (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/assembly-script/samples/event_subscriber.ts (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/assembly-script/samples/request_handler.ts (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/assembly-script/samples/request_sender.ts (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/assembly-script/samples/timer.ts (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/assembly-script/samples/tsconfig.json (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/assembly-script/wamr_app_lib/console.ts (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/assembly-script/wamr_app_lib/request.ts (99%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/assembly-script/wamr_app_lib/timer.ts (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/assembly-script/wamr_app_lib/tsconfig.json (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/build-scripts/SConscript (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/build-scripts/SConscript_config (98%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/build-scripts/build_llvm.py (64%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/build-scripts/config_common.cmake (64%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/build-scripts/esp-idf/README.md (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/build-scripts/esp-idf/wamr/CMakeLists.txt (97%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/build-scripts/involve_boringssl.cmake rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/build-scripts/lldb-wasm.patch (99%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/build-scripts/requirements.txt rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/build-scripts/runtime_lib.cmake (80%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/ci/build_wamr.sh (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/ci/coding_guidelines_check.py (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-framework/README.md (81%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-framework/app-native-shared/README.md (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-framework/app-native-shared/attr_container.c (81%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-framework/app-native-shared/bi-inc/attr_container.h (67%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-framework/app-native-shared/bi-inc/shared_utils.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-framework/app-native-shared/bi-inc/wgl_shared_utils.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-framework/app-native-shared/native_interface.cmake (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-framework/app-native-shared/native_interface.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-framework/app-native-shared/restful_utils.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-framework/app_ext_lib_export.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-framework/app_framework.cmake (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-framework/base/app/bh_platform.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-framework/base/app/bh_platform.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-framework/base/app/req_resp_api.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-framework/base/app/request.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-framework/base/app/timer.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-framework/base/app/timer_api.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-framework/base/app/wa-inc/request.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-framework/base/app/wa-inc/timer_wasm_app.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-framework/base/app/wasm_app.cmake (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-framework/base/app/wasm_app.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-framework/base/native/base_lib.inl (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-framework/base/native/base_lib_export.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-framework/base/native/req_resp_native_api.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-framework/base/native/request_response.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-framework/base/native/runtime_lib.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-framework/base/native/timer_native_api.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-framework/base/native/timer_wrapper.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-framework/base/native/wasm_lib.cmake (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-framework/connection/app/connection.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-framework/connection/app/connection_api.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-framework/connection/app/wa-inc/connection.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-framework/connection/app/wasm_app.cmake (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-framework/connection/native/connection.inl (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-framework/connection/native/connection_lib.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-framework/connection/native/connection_native_api.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-framework/connection/native/connection_wrapper.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-framework/connection/native/linux/conn_tcp.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-framework/connection/native/linux/conn_tcp.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-framework/connection/native/linux/conn_uart.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-framework/connection/native/linux/conn_uart.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-framework/connection/native/linux/conn_udp.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-framework/connection/native/linux/conn_udp.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-framework/connection/native/linux/connection_mgr.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-framework/connection/native/linux/connection_mgr.cmake (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-framework/connection/native/wasm_lib.cmake (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-framework/connection/native/zephyr/connection_lib_impl.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-framework/connection/native/zephyr/connection_mgr.cmake (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-framework/sensor/app/sensor.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-framework/sensor/app/sensor_api.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-framework/sensor/app/wa-inc/sensor.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-framework/sensor/app/wasm_app.cmake (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-framework/sensor/native/runtime_sensor.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-framework/sensor/native/runtime_sensor.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-framework/sensor/native/runtime_sensor.inl (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-framework/sensor/native/sensor_mgr_ref.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-framework/sensor/native/sensor_native_api.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-framework/sensor/native/wasm_lib.cmake (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-framework/template/app/wa-inc/app_xxx.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-framework/template/app/wasm_app.cmake (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-framework/template/native/app_xxx.inl (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-framework/template/native/wasm_lib.cmake (100%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/app-mgr/README.md rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-mgr/app-manager/app_manager.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-mgr/app-manager/app_manager.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-mgr/app-manager/app_manager_host.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-mgr/app-manager/app_manager_host.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-mgr/app-manager/app_mgr.cmake (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-mgr/app-manager/ble_msg.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-mgr/app-manager/coding_rule.txt (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-mgr/app-manager/event.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-mgr/app-manager/event.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-mgr/app-manager/message.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-mgr/app-manager/module_config.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-mgr/app-manager/module_jeff.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-mgr/app-manager/module_jeff.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-mgr/app-manager/module_utils.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-mgr/app-manager/module_wasm_app.c (99%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-mgr/app-manager/module_wasm_app.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-mgr/app-manager/module_wasm_lib.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-mgr/app-manager/module_wasm_lib.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-mgr/app-manager/platform/darwin/app_mgr_darwin.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-mgr/app-manager/platform/linux/app_mgr_linux.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-mgr/app-manager/platform/zephyr/app_mgr_zephyr.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-mgr/app-manager/resource_reg.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-mgr/app-manager/watchdog.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-mgr/app-manager/watchdog.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-mgr/app-mgr-shared/app_manager_export.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-mgr/app-mgr-shared/app_mgr_shared.cmake (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-mgr/app-mgr-shared/host_link.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/app-mgr/module.json (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/config.h (87%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/README.md rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/aot/SConscript (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/aot/aot_intrinsic.c (82%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/aot/aot_intrinsic.h (91%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/aot/aot_loader.c (86%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/aot/aot_reloc.h (91%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/aot/aot_runtime.c (66%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/aot/aot_runtime.h (68%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/aot/arch/aot_reloc_aarch64.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/aot/arch/aot_reloc_arc.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/aot/arch/aot_reloc_arm.c (98%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/aot/arch/aot_reloc_mips.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/aot/arch/aot_reloc_riscv.c (87%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/aot/arch/aot_reloc_thumb.c (86%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/aot/arch/aot_reloc_x86_32.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/aot/arch/aot_reloc_x86_64.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/aot/arch/aot_reloc_xtensa.c (90%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/aot/debug/LICENSE_NUTTX (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/aot/debug/NOTICE_NUTTX (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/aot/debug/elf.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/aot/debug/elf32.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/aot/debug/elf64.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/aot/debug/elf_parser.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/aot/debug/elf_parser.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/aot/debug/jit_debug.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/aot/debug/jit_debug.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/aot/iwasm_aot.cmake (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/common/SConscript (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/common/arch/invokeNative_aarch64.s (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/common/arch/invokeNative_aarch64_simd.s (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/common/arch/invokeNative_arc.s (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/common/arch/invokeNative_arm.s (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/common/arch/invokeNative_arm_vfp.s (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/common/arch/invokeNative_em64.asm (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/common/arch/invokeNative_em64.s (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/common/arch/invokeNative_em64_simd.asm (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/common/arch/invokeNative_em64_simd.s (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/common/arch/invokeNative_general.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/common/arch/invokeNative_ia32.asm (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/common/arch/invokeNative_ia32.s (73%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_mingw_x64.s create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_mingw_x64_simd.s rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/common/arch/invokeNative_mips.s (100%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_osx_universal.s rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/common/arch/invokeNative_riscv.S (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/common/arch/invokeNative_thumb.s (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/common/arch/invokeNative_thumb_vfp.s (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/common/arch/invokeNative_xtensa.s (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/common/iwasm_common.cmake (78%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/common/wasm_application.c (95%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/common/wasm_c_api.c (81%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/common/wasm_c_api_internal.h (96%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/common/wasm_exec_env.c (84%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/common/wasm_exec_env.h (89%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_memory.c rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/common/wasm_memory.h (61%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/common/wasm_native.c (85%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/common/wasm_native.h (94%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/common/wasm_runtime_common.c (84%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/common/wasm_runtime_common.h (89%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/common/wasm_shared_memory.c (53%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/common/wasm_shared_memory.h (95%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/compilation/aot.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/compilation/aot.h (94%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/compilation/aot_compiler.c (94%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/compilation/aot_compiler.h (99%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/compilation/aot_emit_aot_file.c (99%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/compilation/aot_emit_compare.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/compilation/aot_emit_compare.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/compilation/aot_emit_const.c (99%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/compilation/aot_emit_const.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/compilation/aot_emit_control.c (98%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/compilation/aot_emit_control.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/compilation/aot_emit_conversion.c (91%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/compilation/aot_emit_conversion.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/compilation/aot_emit_exception.c (98%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/compilation/aot_emit_exception.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/compilation/aot_emit_function.c (89%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/compilation/aot_emit_function.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/compilation/aot_emit_memory.c (96%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/compilation/aot_emit_memory.h (96%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/compilation/aot_emit_numberic.c (88%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/compilation/aot_emit_numberic.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/compilation/aot_emit_parametric.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/compilation/aot_emit_parametric.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/compilation/aot_emit_table.c (91%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/compilation/aot_emit_table.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/compilation/aot_emit_variable.c (99%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/compilation/aot_emit_variable.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/compilation/aot_llvm.c (86%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/compilation/aot_llvm.h (91%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/compilation/aot_llvm_extra.cpp (53%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_llvm_extra2.cpp create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_llvm_extra2.h create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_orc_extra.cpp create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_orc_extra.h rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/compilation/debug/dwarf_extractor.cpp (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/compilation/debug/dwarf_extractor.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/compilation/iwasm_compl.cmake (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/compilation/simd/simd_access_lanes.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/compilation/simd/simd_access_lanes.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/compilation/simd/simd_bit_shifts.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/compilation/simd/simd_bit_shifts.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/compilation/simd/simd_bitmask_extracts.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/compilation/simd/simd_bitmask_extracts.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/compilation/simd/simd_bitwise_ops.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/compilation/simd/simd_bitwise_ops.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/compilation/simd/simd_bool_reductions.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/compilation/simd/simd_bool_reductions.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/compilation/simd/simd_common.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/compilation/simd/simd_common.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/compilation/simd/simd_comparisons.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/compilation/simd/simd_comparisons.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/compilation/simd/simd_construct_values.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/compilation/simd/simd_construct_values.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/compilation/simd/simd_conversions.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/compilation/simd/simd_conversions.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/compilation/simd/simd_floating_point.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/compilation/simd/simd_floating_point.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/compilation/simd/simd_int_arith.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/compilation/simd/simd_int_arith.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/compilation/simd/simd_load_store.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/compilation/simd/simd_load_store.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/compilation/simd/simd_sat_int_arith.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/compilation/simd/simd_sat_int_arith.h (100%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/doc/classic_interpreter.MD create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/doc/images/export_function.excalidraw create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/doc/images/stack_format_ci.excalidraw create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/doc/images/stack_format_ci.svg create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/doc/images/wasm_exports.svg create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/doc/images/wasm_function.excalidraw create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/doc/images/wasm_function.svg create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/doc/images/wasm_globals.excalidraw create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/doc/images/wasm_globals.svg create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/doc/wasm_exports.MD create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/doc/wasm_function.MD create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/doc/wasm_globals.MD rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/fast-jit/asmjit_sgx_patch.diff (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/fast-jit/cg/LICENSE_ASMJIT (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/fast-jit/cg/LICENSE_ZYDIS (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/fast-jit/cg/x86-64/jit_codegen_x86_64.cpp (67%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/fast-jit/fe/jit_emit_compare.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/fast-jit/fe/jit_emit_compare.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/fast-jit/fe/jit_emit_const.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/fast-jit/fe/jit_emit_const.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/fast-jit/fe/jit_emit_control.c (91%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/fast-jit/fe/jit_emit_control.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/fast-jit/fe/jit_emit_conversion.c (97%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/fast-jit/fe/jit_emit_conversion.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/fast-jit/fe/jit_emit_exception.c (98%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/fast-jit/fe/jit_emit_exception.h (100%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/fe/jit_emit_function.c rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/fast-jit/fe/jit_emit_function.h (100%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/fe/jit_emit_memory.c rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/fast-jit/fe/jit_emit_memory.h (97%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/fast-jit/fe/jit_emit_numberic.c (96%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/fast-jit/fe/jit_emit_numberic.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/fast-jit/fe/jit_emit_parametric.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/fast-jit/fe/jit_emit_parametric.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/fast-jit/fe/jit_emit_table.c (86%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/fast-jit/fe/jit_emit_table.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/fast-jit/fe/jit_emit_variable.c (86%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/fast-jit/fe/jit_emit_variable.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/fast-jit/iwasm_fast_jit.cmake (96%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/fast-jit/jit_codecache.c (62%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/fast-jit/jit_codecache.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/fast-jit/jit_codegen.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/fast-jit/jit_codegen.h (85%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/jit_compiler.c rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/fast-jit/jit_compiler.h (84%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/fast-jit/jit_dump.c (97%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/fast-jit/jit_dump.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/fast-jit/jit_frontend.c (86%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/fast-jit/jit_frontend.h (86%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/fast-jit/jit_ir.c (98%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/fast-jit/jit_ir.def (86%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/fast-jit/jit_ir.h (97%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/fast-jit/jit_regalloc.c (96%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/fast-jit/jit_utils.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/fast-jit/jit_utils.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/include/aot_export.h (92%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/include/lib_export.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/include/wasm_c_api.h (94%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/include/wasm_export.h (84%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/interpreter/SConscript (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/interpreter/iwasm_interp.cmake (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/interpreter/wasm.h (75%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/interpreter/wasm_interp.h (85%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/interpreter/wasm_interp_classic.c (84%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/interpreter/wasm_interp_fast.c (92%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/interpreter/wasm_loader.c (93%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/interpreter/wasm_loader.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/interpreter/wasm_mini_loader.c (92%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/interpreter/wasm_opcode.h (98%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/interpreter/wasm_runtime.c (62%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm_runtime.h rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/libraries/debug-engine/debug_engine.c (78%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/libraries/debug-engine/debug_engine.cmake (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/libraries/debug-engine/debug_engine.h (85%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/libraries/debug-engine/gdbserver.c (91%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/libraries/debug-engine/gdbserver.h (93%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/libraries/debug-engine/handler.c (84%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/libraries/debug-engine/handler.h (95%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/libraries/debug-engine/packets.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/libraries/debug-engine/packets.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/libraries/debug-engine/utils.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/libraries/debug-engine/utils.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/libraries/lib-pthread/SConscript (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/libraries/lib-pthread/lib_pthread.cmake (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c (98%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/libraries/lib-rats/lib_rats.cmake (75%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-rats/lib_rats_common.h create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-rats/lib_rats_wrapper.c create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-rats/lib_rats_wrapper.h rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/libraries/lib-socket/inc/wasi_socket_ext.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/libraries/lib-socket/lib_socket_wasi.cmake (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/libraries/lib-socket/src/wasi/wasi_socket_ext.c (100%) create mode 100755 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-socket/test/build.sh create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-socket/test/nslookup.c create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-socket/test/tcp_udp.c create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/lib_wasi_threads.cmake create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/lib_wasi_threads_wrapper.c create mode 100755 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/build.sh create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/common.h create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/create_threads_until_limit.c create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/global_atomic.c create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/global_lock.c create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/linear_memory_size_update.c create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_proc_exit_busy.c create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_proc_exit_busy.json create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_proc_exit_sleep.c create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_proc_exit_sleep.json create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_proc_exit_wait.c create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_proc_exit_wait.json create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_trap_busy.c create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_trap_busy.json create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_trap_sleep.c create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_trap_sleep.json create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_trap_wait.c create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_trap_wait.json create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_proc_exit_busy.c create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_proc_exit_busy.json create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_proc_exit_sleep.c create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_proc_exit_sleep.json create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_proc_exit_wait.c create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_proc_exit_wait.json create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_trap_busy.c create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_trap_busy.json create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_trap_sleep.c create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_trap_sleep.json create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_trap_wait.c create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_trap_wait.json create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/spawn_multiple_times.c create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/sync_primitives.h create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/trap_after_main_thread_finishes.c create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/trap_after_main_thread_finishes.json create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/update_shared_data_and_alloc_heap.c create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/tid_allocator.c create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/tid_allocator.h rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/libraries/libc-builtin/SConscript (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/libraries/libc-builtin/libc_builtin.cmake (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c (99%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/libraries/libc-emcc/SConscript (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/libraries/libc-emcc/libc_emcc.cmake (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/libraries/libc-emcc/libc_emcc_wrapper.c (99%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/libraries/libc-uvwasi/LICENSE_LIBUV (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/libraries/libc-uvwasi/LICENSE_UVWASI (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/libraries/libc-uvwasi/libc_uvwasi.cmake (97%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/libraries/libc-uvwasi/libc_uvwasi_wrapper.c (98%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/libraries/libc-wasi/SConscript (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/libraries/libc-wasi/libc_wasi.cmake (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c (94%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/LICENSE (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/LICENSE (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/wasmtime_ssp.h (96%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/LICENSE (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/README.md (100%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/gnuc.h rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/locking.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c (95%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/queue.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/random.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/random.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/refcount.h (74%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/rights.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/ssp_config.h (73%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/str.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/str.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/libraries/thread-mgr/SConscript (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/libraries/thread-mgr/thread_manager.c (60%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/libraries/thread-mgr/thread_manager.h (77%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/libraries/thread-mgr/thread_mgr.cmake (100%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/README.md create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/cmake/Findtensorflow_lite.cmake create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/src/utils/logger.h create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/src/utils/wasi_nn_app_native.c create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/src/utils/wasi_nn_app_native.h create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/src/wasi_nn.c create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/src/wasi_nn_private.h create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/src/wasi_nn_tensorflowlite.cpp create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/src/wasi_nn_tensorflowlite.hpp rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/libraries/wasi-nn/test/CMakeLists.txt (96%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/Dockerfile.compile create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/Dockerfile.cpu create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/Dockerfile.nvidia-gpu create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/Dockerfile.vx-delegate rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/libraries/wasi-nn/test/build.sh (82%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/libraries/wasi-nn/test/models/average.py (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/libraries/wasi-nn/test/models/max.py (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/libraries/wasi-nn/test/models/mult_dimension.py (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/libraries/wasi-nn/test/models/mult_outputs.py (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/libraries/wasi-nn/test/models/sum.py (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/iwasm/libraries/wasi-nn/test/models/utils.py (100%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/requirements.txt create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/test_tensorflow.c create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/utils.c create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/utils.h create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/wasi_nn.cmake create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/wasi_nn.h create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/wasi_nn_types.h rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/coap/er-coap/LICENSE.md (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/coap/er-coap/coap-constants.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/coap/extension/coap_ext.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/coap/lib_coap.cmake (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/mem-alloc/SConscript (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/mem-alloc/ems/ems_alloc.c (96%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/mem-alloc/ems/ems_gc.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/mem-alloc/ems/ems_gc_internal.h (80%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/mem-alloc/ems/ems_hmu.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/mem-alloc/ems/ems_kfc.c (84%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/mem-alloc/mem_alloc.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/mem-alloc/mem_alloc.cmake (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/mem-alloc/mem_alloc.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/README.md (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/alios/alios_platform.c (91%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/alios/alios_thread.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/alios/alios_time.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/alios/platform_internal.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/alios/shared_platform.cmake (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/android/platform_init.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/android/platform_internal.h (97%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/android/shared_platform.cmake (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/common/freertos/freertos_malloc.c (80%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/common/freertos/freertos_thread.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/common/freertos/freertos_time.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/common/freertos/platform_api_freertos.cmake (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/common/math/COPYRIGHT (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/common/math/math.c (99%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/common/math/platform_api_math.cmake (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/common/posix/platform_api_posix.cmake (100%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/common/posix/posix_malloc.c rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/common/posix/posix_memmap.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/common/posix/posix_socket.c (94%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/common/posix/posix_thread.c (95%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/common/posix/posix_time.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/darwin/platform_init.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/darwin/platform_internal.h (97%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/darwin/shared_platform.cmake (100%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/ego/platform_init.c create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/ego/platform_internal.h create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/ego/shared_platform.cmake rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/esp-idf/espidf_malloc.c (95%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/esp-idf/espidf_memmap.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/esp-idf/espidf_platform.c (97%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/esp-idf/espidf_socket.c rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/esp-idf/espidf_thread.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/esp-idf/platform_internal.h (97%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/esp-idf/shared_platform.cmake (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/linux => wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/freebsd}/platform_init.c (100%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/freebsd/platform_internal.h create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/freebsd/shared_platform.cmake rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/include/platform_api_extension.h (92%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/include/platform_api_vmcore.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/include/platform_common.h (98%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/linux-sgx/platform_internal.h (82%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/linux-sgx/sgx_file.c (95%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/linux-sgx/sgx_file.h (98%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/linux-sgx/sgx_ipfs.c (77%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/linux-sgx/sgx_ipfs.h (95%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/linux-sgx/sgx_platform.c (97%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/linux-sgx/sgx_pthread.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/linux-sgx/sgx_pthread.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/linux-sgx/sgx_rsrv_mem_mngr.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/linux-sgx/sgx_signal.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/linux-sgx/sgx_signal.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/linux-sgx/sgx_socket.c (98%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/linux-sgx/sgx_socket.h (99%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/linux-sgx/sgx_thread.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/linux-sgx/sgx_time.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/linux-sgx/sgx_time.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/linux-sgx/sgx_wamr.edl (97%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/linux-sgx/shared_platform.cmake (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/linux-sgx/untrusted/file.c (97%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/linux-sgx/untrusted/pthread.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/linux-sgx/untrusted/signal.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/linux-sgx/untrusted/socket.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/linux-sgx/untrusted/time.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/vxworks => wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux}/platform_init.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/linux/platform_internal.h (97%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/linux/shared_platform.cmake (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/nuttx/nuttx_platform.c (53%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/nuttx/platform_internal.h (96%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/nuttx/shared_platform.cmake (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/riot/platform_internal.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/riot/riot_platform.c (93%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/riot/riot_thread.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/riot/riot_time.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/riot/shared_platform.cmake (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/rt-thread/SConscript (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/rt-thread/platform_internal.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/rt-thread/rtt_platform.c (97%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/rt-thread/shared_platform.cmake (100%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/vxworks/platform_init.c rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/vxworks/platform_internal.h (96%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/vxworks/shared_platform.cmake (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/windows/platform_init.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/windows/platform_internal.h (72%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/windows/shared_platform.cmake (77%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/windows/win_atomic.cpp rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/windows/win_malloc.c (82%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/windows/win_memmap.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/windows/win_socket.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/windows/win_thread.c (90%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/windows/win_time.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/zephyr/platform_internal.h (80%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/zephyr/shared_platform.cmake (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/zephyr/zephyr_platform.c (98%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/zephyr/zephyr_thread.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/platform/zephyr/zephyr_time.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/utils/SConscript (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/utils/bh_assert.c (87%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/utils/bh_assert.h (85%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/utils/bh_common.c (53%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/utils/bh_common.h (81%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/utils/bh_hashmap.c (99%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/utils/bh_hashmap.h (97%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/utils/bh_list.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/utils/bh_list.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/utils/bh_log.c (76%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/utils/bh_log.h (92%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/utils/bh_platform.h (87%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/utils/bh_queue.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/utils/bh_queue.h (98%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/utils/bh_vector.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/utils/bh_vector.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/utils/runtime_timer.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/utils/runtime_timer.h (98%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/utils/shared_utils.cmake (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/utils/uncommon/SConscript (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/utils/uncommon/bh_getopt.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/utils/uncommon/bh_getopt.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/utils/uncommon/bh_read_file.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/utils/uncommon/bh_read_file.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/shared/utils/uncommon/shared_uncommon.cmake (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/core/version.h (54%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/doc/build_wamr.md rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/doc/build_wasm_app.md (94%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/doc/devcontainer.md (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/doc/embed_wamr.md (99%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/doc/export_native_api.md (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/doc/linux_sgx.md (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/doc/memory_tune.md (94%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/doc/memory_usage.md rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/doc/multi_module.md (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/doc/other_wasm_compilers.md (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/doc/pics/app_framework.PNG (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/doc/pics/embed.PNG (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/doc/pics/extend_library.PNG (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/doc/pics/multi_module_pic1.png (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/doc/pics/native_call_wasm.PNG (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/doc/pics/request.PNG (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/doc/pics/safe.PNG (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/doc/pics/sensor_callflow.PNG (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/doc/pics/sub.PNG (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/doc/pics/vgl_demo.png (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/doc/pics/vgl_demo2.png (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/doc/pics/vgl_demo_linux.png (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/doc/pics/vgl_linux.PNG (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/doc/pics/wamr-arch.JPG (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/doc/pics/wamr_memory_model.png (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/doc/pics/wamr_menu_config.png (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/doc/port_wamr.md (57%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/doc/pthread_impls.md rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/doc/pthread_library.md (98%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/doc/ref_types.md (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/doc/release_ack.md (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/doc/roadmap.md (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/doc/semantic_version.md (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/doc/socket_api.md (87%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/doc/source_debugging.md (82%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/doc/wamr_api.md (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/doc/wasm_c_api.md (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/doc/xip.md (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/language-bindings/go/README.md (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/language-bindings/go/build.sh (74%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/language-bindings/go/go.mod (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/language-bindings/go/go.sum (90%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/language-bindings/go/samples/build.sh (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/language-bindings/go/samples/run.sh (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/language-bindings/go/samples/test.go (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/language-bindings/go/samples/wasm-app/build.sh (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/language-bindings/go/samples/wasm-app/main.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/language-bindings/go/wamr/cgo.go (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/language-bindings/go/wamr/instance.go (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/language-bindings/go/wamr/instance_test.go (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/language-bindings/go/wamr/module.go (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/language-bindings/go/wamr/module_test.go (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/language-bindings/go/wamr/packaged/include/dummy.go (100%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/go/wamr/packaged/lib/darwin-aarch64/dummy.go rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/language-bindings/go/wamr/packaged/lib/darwin-amd64/dummy.go (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/language-bindings/go/wamr/packaged/lib/dummy.go (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/language-bindings/go/wamr/packaged/lib/linux-amd64/dummy.go (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/language-bindings/go/wamr/runtime.go (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/language-bindings/go/wamr/runtime_test.go (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/language-bindings/python/.gitignore (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/language-bindings/python/LICENSE (100%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/MANIFEST.in create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/README.md rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/language-bindings/python/pyproject.toml (52%) create mode 100755 lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/setup.py rename lib/{wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/devices => wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/src/wamr}/__init__.py (100%) mode change 100755 => 100644 rename lib/{wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/debug/linux => wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/src/wamr/libs}/.placeholder (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/devices/migrations => wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/src/wamr/wamrapi}/__init__.py (100%) mode change 100755 => 100644 create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/src/wamr/wamrapi/wamr.py rename lib/{wasm-micro-runtime-WAMR-1.1.1/language-bindings/python/wamr => wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/src/wamr/wasmcapi}/__init__.py (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1/language-bindings/python/wamr => wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/src/wamr/wasmcapi}/binding.py (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1/language-bindings/python/wamr => wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/src/wamr/wasmcapi}/ffi.py (99%) create mode 100755 lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/utils/create_lib.sh create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wamr-api/README.md create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wamr-api/requirements.txt create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wamr-api/samples/compile.sh create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wamr-api/samples/main.py create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wamr-api/samples/sum.c create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wasm-c-api/README.md rename lib/{wasm-micro-runtime-WAMR-1.1.1/language-bindings/python => wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wasm-c-api}/docs/design.md (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1/language-bindings/python => wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wasm-c-api}/docs/images/python_package_life_cycle.png (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1/language-bindings/python => wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wasm-c-api}/docs/setup_dev_env.md (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1/language-bindings/python => wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wasm-c-api}/requirements.txt (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1/language-bindings/python => wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wasm-c-api}/samples/hello.wat (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1/language-bindings/python => wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wasm-c-api}/samples/hello_oop.py (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1/language-bindings/python => wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wasm-c-api}/samples/hello_procedural.py (98%) rename lib/{wasm-micro-runtime-WAMR-1.1.1/language-bindings/python => wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wasm-c-api}/tests/__init__.py (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1/language-bindings/python => wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wasm-c-api}/tests/context.py (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1/language-bindings/python => wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wasm-c-api}/tests/test_advanced.py (99%) rename lib/{wasm-micro-runtime-WAMR-1.1.1/language-bindings/python => wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wasm-c-api}/tests/test_basic.py (99%) rename lib/{wasm-micro-runtime-WAMR-1.1.1/language-bindings/python => wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wasm-c-api}/utils/bindgen.py (98%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/README.md rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/product-mini/app-samples/hello-world-cmake/CMakeLists.txt (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/product-mini/app-samples/hello-world-cmake/build.sh (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/product-mini/app-samples/hello-world-cmake/main.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/product-mini/app-samples/hello-world-cmake/print.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/product-mini/app-samples/hello-world/build.sh (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/product-mini/app-samples/hello-world/main.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/product-mini/platforms/alios-things/aos.mk (91%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/product-mini/platforms/alios-things/src/main.c (92%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/product-mini/platforms/alios-things/src/test_wasm.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/product-mini/platforms/android/CMakeLists.txt (98%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/product-mini/platforms/android/build_jit.sh (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/product-mini/platforms/android/build_llvm.sh (71%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/product-mini/platforms/android/wasm-jni.cpp (97%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/product-mini/platforms/darwin/CMakeLists.txt (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/product-mini/platforms/darwin/build_jit.sh (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/product-mini/platforms/darwin/build_llvm.sh (71%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/product-mini/platforms/darwin/main.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/product-mini/platforms/esp-idf/.gitignore (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/product-mini/platforms/esp-idf/CMakeLists.txt (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/product-mini/platforms/esp-idf/build_and_run.sh (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/product-mini/platforms/esp-idf/main/CMakeLists.txt (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/product-mini/platforms/esp-idf/main/main.c (97%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/product-mini/platforms/esp-idf/main/test_wasm.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/product-mini/platforms/esp-idf/sdkconfig.defaults (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/product-mini/platforms/esp-idf/sdkconfig.defaults.esp32 (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/product-mini/platforms/esp-idf/sdkconfig.defaults.esp32c3 (100%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/freebsd/CMakeLists.txt create mode 100755 lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/freebsd/build_jit.sh rename lib/{wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/linux => wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/freebsd}/build_llvm.sh (69%) rename lib/{wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/linux => wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/freebsd}/main.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/product-mini/platforms/ios/CMakeLists.txt (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/product-mini/platforms/ios/generate_xcodeproj.sh (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/product-mini/platforms/linux-sgx/CMakeLists.txt (65%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/product-mini/platforms/linux-sgx/CMakeLists_minimal.txt (95%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/product-mini/platforms/linux-sgx/enclave-sample/Makefile (83%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/product-mini/platforms/linux-sgx/enclave-sample/Makefile_minimal (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/product-mini/platforms/linux/CMakeLists.txt (94%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/product-mini/platforms/linux/build_jit.sh (100%) create mode 100755 lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/linux/build_llvm.sh rename lib/{wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/nuttx => wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/linux}/main.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/vxworks => wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/nuttx}/main.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/product-mini/platforms/nuttx/wamr.mk (89%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/product-mini/platforms/posix/main.c (78%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/product-mini/platforms/riot/CMakeLists.txt (90%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/product-mini/platforms/riot/Makefile (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/product-mini/platforms/riot/iwasmt.c (94%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/product-mini/platforms/riot/test_wasm.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/product-mini/platforms/rt-thread/SConscript (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/product-mini/platforms/rt-thread/iwasm.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/product-mini/platforms/rt-thread/iwasm.cmake (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/product-mini/platforms/vxworks/CMakeLists.txt (100%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/vxworks/main.c rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/product-mini/platforms/windows/CMakeLists.txt (95%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/product-mini/platforms/windows/build_llvm.py (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/product-mini/platforms/windows/main.c (77%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/product-mini/platforms/zephyr/simple/CMakeLists.txt (82%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/product-mini/platforms/zephyr/simple/README_docker.md (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/product-mini/platforms/zephyr/simple/boards/esp32.conf (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/product-mini/platforms/zephyr/simple/boards/nucleo767zi.conf (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/product-mini/platforms/zephyr/simple/boards/qemu_arc.conf (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/product-mini/platforms/zephyr/simple/boards/qemu_cortex_a53.conf (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/product-mini/platforms/zephyr/simple/boards/qemu_riscv32.conf (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/product-mini/platforms/zephyr/simple/boards/qemu_riscv64.conf (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/product-mini/platforms/zephyr/simple/boards/qemu_x86_nommu.conf (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/product-mini/platforms/zephyr/simple/boards/qemu_xtensa.conf (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/product-mini/platforms/zephyr/simple/build_and_run.sh (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/product-mini/platforms/zephyr/simple/esp32_custom_linker.ld (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/product-mini/platforms/zephyr/simple/src/main.c (96%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/product-mini/platforms/zephyr/simple/src/test_wasm.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/product-mini/platforms/zephyr/simple/src/test_wasm_riscv64.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/product-mini/platforms/zephyr/simple/src/wasm-app-riscv64/build.sh (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/product-mini/platforms/zephyr/simple/src/wasm-app-riscv64/main.c (100%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/samples/README.md rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/basic/.gitignore (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/basic/CMakeLists.txt (94%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/basic/README.md (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/basic/build.sh (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/basic/run.sh (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/basic/src/main.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/basic/src/native_impl.c (93%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/basic/wasm-apps/testapp.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/file/CMakeLists.txt (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/file/README.md (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/file/src/CMakeLists.txt (94%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/file/src/main.c (92%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/file/wasm-app/CMakeLists.txt (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/file/wasm-app/main.c (62%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/gui/README.md (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/gui/build.sh (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/gui/lv_config/lv_conf.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/gui/lv_config/lv_drv_conf.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/gui/lv_config/system_header.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/gui/wamr_config_gui.cmake (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/gui/wasm-apps/build_apps.sh (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/gui/wasm-apps/decrease/Makefile (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/gui/wasm-apps/decrease/src/main.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/gui/wasm-apps/increase/CMakeLists.txt (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/gui/wasm-apps/increase/Makefile (86%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/gui/wasm-apps/increase/src/main.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/gui/wasm-runtime-wgl/src/platform/linux/iwasm_main.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/gui/wasm-runtime-wgl/src/platform/linux/lv_drv_conf.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/gui/wasm-runtime-wgl/src/platform/linux/main.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/gui/wasm-runtime-wgl/src/platform/zephyr/LICENSE (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/gui/wasm-runtime-wgl/src/platform/zephyr/XPT2046.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/gui/wasm-runtime-wgl/src/platform/zephyr/XPT2046.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/gui/wasm-runtime-wgl/src/platform/zephyr/board_config.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/gui/wasm-runtime-wgl/src/platform/zephyr/display.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/gui/wasm-runtime-wgl/src/platform/zephyr/display_ili9340.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/gui/wasm-runtime-wgl/src/platform/zephyr/display_ili9340.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/gui/wasm-runtime-wgl/src/platform/zephyr/display_ili9340_adafruit_1480.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/gui/wasm-runtime-wgl/src/platform/zephyr/iwasm_main.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/gui/wasm-runtime-wgl/src/platform/zephyr/main.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/gui/wasm-runtime-wgl/src/platform/zephyr/pin_config_jlf.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/gui/wasm-runtime-wgl/src/platform/zephyr/pin_config_stm32.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/littlevgl/LICENCE.txt (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/littlevgl/README.md (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/littlevgl/build.sh (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/littlevgl/lv_config/lv_conf.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/littlevgl/lv_config/lv_drv_conf.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/littlevgl/vgl-native-ui-app/CMakeLists.txt (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/littlevgl/vgl-native-ui-app/CMakeLists.txt.in (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/littlevgl/vgl-native-ui-app/lv-drivers/.gitignore (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/littlevgl/vgl-native-ui-app/lv-drivers/display_indev.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/littlevgl/vgl-native-ui-app/lv-drivers/indev/mouse.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/littlevgl/vgl-native-ui-app/lv-drivers/indev/mouse.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/littlevgl/vgl-native-ui-app/lv-drivers/linux_display_indev.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/littlevgl/vgl-native-ui-app/lv-drivers/system_header.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/littlevgl/vgl-native-ui-app/main.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/littlevgl/vgl-wasm-runtime/CMakeLists.txt (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/littlevgl/vgl-wasm-runtime/src/display_indev.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/littlevgl/vgl-wasm-runtime/src/platform/linux/display_indev.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/littlevgl/vgl-wasm-runtime/src/platform/linux/iwasm_main.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/littlevgl/vgl-wasm-runtime/src/platform/linux/main.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/littlevgl/vgl-wasm-runtime/src/platform/linux/mouse.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/LICENSE (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/XPT2046.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/XPT2046.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/board_config.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display_ili9340.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display_ili9340.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display_ili9340_adafruit_1480.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display_indev.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/iwasm_main.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/main.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/pin_config_jlf.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/pin_config_stm32.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/littlevgl/wamr_config_littlevgl.cmake (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/littlevgl/wasm-apps/Makefile_wasm_app (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/littlevgl/wasm-apps/Makefile_wasm_app_no_wasi (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/littlevgl/wasm-apps/build_wasm_app.sh (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/littlevgl/wasm-apps/src/display_indev.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/littlevgl/wasm-apps/src/main.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/littlevgl/wasm-apps/src/system_header.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/multi-module/CMakeLists.txt (96%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/multi-module/src/main.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/multi-module/wasm-apps/CMakeLists.txt (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/multi-module/wasm-apps/mA.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/multi-module/wasm-apps/mB.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/multi-module/wasm-apps/mC.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/multi-module/wasm-apps/mD.cpp (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/multi-module/wasm-apps/mE.cpp (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/multi-thread/CMakeLists.txt (93%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/multi-thread/wasm-apps/CMakeLists.txt (86%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/multi-thread/wasm-apps/main.c (100%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/samples/multi-thread/wasm-apps/main_global_atomic.c create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/samples/multi-thread/wasm-apps/main_thread_exception.c rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/native-lib/CMakeLists.txt (76%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/native-lib/README.md (71%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/native-lib/test_add.c (100%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/samples/native-lib/test_hello.c create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/samples/native-lib/test_hello2.c rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/native-lib/test_sqrt.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/native-lib/wasm-app/CMakeLists.txt (100%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/samples/native-lib/wasm-app/main.c rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/ref-types/CMakeLists.txt (85%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/ref-types/src/hello.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/ref-types/src/hello.wat (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/sgx-ra/CMakeLists.txt (90%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/samples/sgx-ra/README.md rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/sgx-ra/wasm-app/CMakeLists.txt (100%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/samples/sgx-ra/wasm-app/main.c rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/simple/.gitignore (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/simple/CMakeLists.txt (81%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/simple/README.md (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/simple/build.sh (97%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/simple/profiles/arm-interp/toolchain.cmake (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/simple/profiles/arm-interp/wamr_config_simple.cmake (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/simple/profiles/arm64-aot/toolchain.cmake (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/simple/profiles/arm64-aot/wamr_config_simple.cmake (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/simple/profiles/arm64-interp/toolchain.cmake (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/simple/profiles/arm64-interp/wamr_config_simple.cmake (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/simple/profiles/host-aot/wamr_config_simple.cmake (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/simple/profiles/host-interp/wamr_config_simple.cmake (100%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/samples/simple/profiles/macos-interp/wamr_config_simple.cmake create mode 100755 lib/wasm-micro-runtime-WAMR-1.2.2/samples/simple/sample_test_run.py rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/simple/src/iwasm_main.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/simple/src/main.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/simple/wasm-apps/connection.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/simple/wasm-apps/event_publisher.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/simple/wasm-apps/event_subscriber.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/simple/wasm-apps/request_handler.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/simple/wasm-apps/request_sender.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/simple/wasm-apps/sensor.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/simple/wasm-apps/timer.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/socket-api/CMakeLists.txt (97%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/socket-api/README.md (96%) create mode 100755 lib/wasm-micro-runtime-WAMR-1.2.2/samples/socket-api/sample_test_run.py rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/socket-api/wasm-src/CMakeLists.txt (96%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/socket-api/wasm-src/addr_resolve.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/socket-api/wasm-src/inc/.gitkeep (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/socket-api/wasm-src/multicast_client.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/socket-api/wasm-src/multicast_server.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/socket-api/wasm-src/send_recv.c (91%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/socket-api/wasm-src/socket_opts.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/socket-api/wasm-src/socket_utils.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/socket-api/wasm-src/tcp_client.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/socket-api/wasm-src/tcp_server.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/socket-api/wasm-src/timeout_client.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/socket-api/wasm-src/timeout_server.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/socket-api/wasm-src/udp_client.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/socket-api/wasm-src/udp_server.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/spawn-thread/CMakeLists.txt (93%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/spawn-thread/src/main.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/spawn-thread/wasm-apps/CMakeLists.txt (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/spawn-thread/wasm-apps/sum.c (100%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasi-threads/CMakeLists.txt create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasi-threads/README.md create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasi-threads/wasm-apps/CMakeLists.txt create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasi-threads/wasm-apps/no_pthread.c create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasi-threads/wasm-apps/wasi_thread_start.S create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasi-threads/wasm-apps/wasi_thread_start.h create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api-imports/.gitignore create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api-imports/CMakeLists.txt create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api-imports/README.md create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api-imports/host/CMakeLists.txt create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api-imports/host/example1.c create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api-imports/wasm/CMakeLists.txt rename lib/{wasm-micro-runtime-WAMR-1.1.1/core/iwasm/README.md => wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api-imports/wasm/inc/.gitkeep} (100%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api-imports/wasm/send_recv.c rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/wasm-c-api/CMakeLists.txt (72%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/wasm-c-api/README.md (91%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/wasm-c-api/src/LICENSE (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/wasm-c-api/src/callback.c (96%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/wasm-c-api/src/callback.wat (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/wasm-c-api/src/callback_chain.c (99%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/wasm-c-api/src/callback_chain.wat (93%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/clone.c create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/clone.wat rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/wasm-c-api/src/empty_imports.c (90%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/wasm-c-api/src/empty_imports.wat (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/wasm-c-api/src/global.c (87%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/wasm-c-api/src/global.wat (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/wasm-c-api/src/globalexportimport-0.wat (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/wasm-c-api/src/globalexportimport-1.wat (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/wasm-c-api/src/globalexportimport.c (85%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/wasm-c-api/src/hello.c (94%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/wasm-c-api/src/hello.wat (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/wasm-c-api/src/hostref.c (90%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/wasm-c-api/src/hostref.wat (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/wasm-c-api/src/memory.c (93%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/wasm-c-api/src/memory.wat (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/wasm-c-api/src/multi.c (96%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/wasm-c-api/src/multi.wat (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/wasm-c-api/src/reflect.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/wasm-c-api/src/reflect.wat (80%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/serialize.c create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/serialize.wat rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/wasm-c-api/src/table.c (95%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/wasm-c-api/src/table.wat (100%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/threads.c create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/threads.wat rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/wasm-c-api/src/trap.c (97%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/wasm-c-api/src/trap.wat (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/wasm-c-api/src/utils/multi_module_utils.c (100%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/CMakeLists.txt rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/workload/README.md (59%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/workload/XNNPACK/.gitignore (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/workload/XNNPACK/CMakeLists.txt (58%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/workload/XNNPACK/README.md (83%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/workload/XNNPACK/benchmark.patch (100%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/XNNPACK/xnnpack.patch rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/workload/bwa/.gitignore (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/workload/bwa/CMakeLists.bwa_wasm.txt (89%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/bwa/CMakeLists.txt rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/workload/bwa/README.md (90%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/workload/bwa/bwa.patch (100%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/cmake/FindBinaryen.cmake create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/cmake/FindWASISDK.cmake rename lib/{wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/mysite/__init__.py => wasm-micro-runtime-WAMR-1.2.2/samples/workload/include/.gitkeep} (100%) mode change 100755 => 100644 rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/workload/meshoptimizer/.gitignore (100%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/meshoptimizer/CMakeLists.txt rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/workload/meshoptimizer/README.md (92%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/workload/meshoptimizer/codecbench.patch (92%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/workload/preparation.sh (93%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/workload/tensorflow/README.md (56%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/workload/tensorflow/build.sh (59%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/workload/tensorflow/tf_lite.patch (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/workload/wasm-av1/.gitignore (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/workload/wasm-av1/CMakeLists.avx_wasm.txt (84%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/wasm-av1/CMakeLists.txt rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/workload/wasm-av1/README.md (90%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/workload/wasm-av1/av1-clang.patch (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/workload/wasm-av1/build.sh (94%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/samples/workload/wasm-av1/wasm-av1.patch (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/.gitignore (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/IoT-APP-Store-Demo/README.md (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/IoT-APP-Store-Demo/docker-compose.yml (100%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/Dockerfile rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/IoT-APP-Store-Demo/wasm_django/db.sqlite3 (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/harness => wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/devices}/__init__.py (100%) mode change 100644 => 100755 rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/IoT-APP-Store-Demo/wasm_django/devices/admin.py (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/IoT-APP-Store-Demo/wasm_django/devices/apps.py (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle => wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/devices/migrations}/__init__.py (100%) mode change 100644 => 100755 rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/IoT-APP-Store-Demo/wasm_django/devices/models.py (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/IoT-APP-Store-Demo/wasm_django/devices/templates/application.html (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/IoT-APP-Store-Demo/wasm_django/devices/templates/appstore.html (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/IoT-APP-Store-Demo/wasm_django/devices/templates/empty.html (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/IoT-APP-Store-Demo/wasm_django/devices/templates/help.html (94%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/IoT-APP-Store-Demo/wasm_django/devices/templates/mysite.html (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/IoT-APP-Store-Demo/wasm_django/devices/tests.py (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/IoT-APP-Store-Demo/wasm_django/devices/views.py (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/IoT-APP-Store-Demo/wasm_django/manage.py (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/cases/01-install => wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/mysite}/__init__.py (100%) mode change 100644 => 100755 rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/IoT-APP-Store-Demo/wasm_django/mysite/settings.py (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/IoT-APP-Store-Demo/wasm_django/mysite/urls.py (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/IoT-APP-Store-Demo/wasm_django/mysite/wsgi.py (100%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/server/Dockerfile rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/IoT-APP-Store-Demo/wasm_django/server/wasm_server.py (96%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/IoT-APP-Store-Demo/wasm_django/static/css/application.css (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/IoT-APP-Store-Demo/wasm_django/static/css/appstore.css (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/IoT-APP-Store-Demo/wasm_django/static/css/index.css (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/IoT-APP-Store-Demo/wasm_django/static/js/application.js (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/IoT-APP-Store-Demo/wasm_django/static/js/appstore.js (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/IoT-APP-Store-Demo/wasm_django/static/js/index.js (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/IoT-APP-Store-Demo/wasm_django/static/photo/app(1).png (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/IoT-APP-Store-Demo/wasm_django/static/photo/application.png (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/IoT-APP-Store-Demo/wasm_django/static/photo/delete.png (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/IoT-APP-Store-Demo/wasm_django/static/photo/download(1).png (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/IoT-APP-Store-Demo/wasm_django/static/photo/menu.png (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/IoT-APP-Store-Demo/wasm_django/static/photo/milky-way-2695569_1280.jpg (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/IoT-APP-Store-Demo/wasm_django/static/photo/net_device.png (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/IoT-APP-Store-Demo/wasm_django/static/photo/software-icon-32081.png (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/IoT-APP-Store-Demo/wasm_django/static/photo/totalblack.png (100%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/connection.wasm create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/event_publisher.wasm create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/event_subscriber.wasm create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/request_handler.wasm create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/request_sender.wasm create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/sensor.wasm create mode 100755 lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/simple create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/sys/connection.wasm create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/sys/event_publisher.wasm create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/sys/event_subscriber.wasm create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/sys/request_handler.wasm create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/sys/request_sender.wasm create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/sys/timer.wasm create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/timer.wasm create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/ui_app.wasm create mode 100755 lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/wasm_runtime_wgl rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/binarydump-tool/CMakeLists.txt (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/binarydump-tool/binarydump.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/component-test/README.md (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/component-test/__init__.py (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/component-test/framework/__init__.py (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/component-test/framework/case_base.py (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/component-test/framework/engine.py (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/component-test/framework/framework.py (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/component-test/framework/suite.py (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/component-test/framework/test_api.py (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/component-test/framework/test_utils.py (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/cases/02-request => wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/harness}/__init__.py (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/component-test/harness/harness_api.py (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/component-test/host-clients/src/host_app_sample.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/component-test/host-clients/src/makefile (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/component-test/set_dev_env.sh (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/component-test/start.py (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/cases/03-event => wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle}/__init__.py (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/cases/04-request-internal => wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/cases/01-install}/__init__.py (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/component-test/suites/01-life-cycle/cases/01-install/case.py (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/cases/05-event-internal => wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/cases/02-request}/__init__.py (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/component-test/suites/01-life-cycle/cases/02-request/case.py (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/cases/06-timer => wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/cases/03-event}/__init__.py (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/component-test/suites/01-life-cycle/cases/03-event/case.py (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/cases/07-sensor => wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/cases/04-request-internal}/__init__.py (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/component-test/suites/01-life-cycle/cases/04-request-internal/case.py (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/cases/08-on-destroy => wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/cases/05-event-internal}/__init__.py (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/component-test/suites/01-life-cycle/cases/05-event-internal/case.py (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/cases => wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/cases/06-timer}/__init__.py (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/component-test/suites/01-life-cycle/cases/06-timer/case.py (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites => wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/cases/07-sensor}/__init__.py (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/component-test/suites/01-life-cycle/cases/07-sensor/case.py (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/debug/osx/.placeholder => wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/cases/08-on-destroy/__init__.py} (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/component-test/suites/01-life-cycle/cases/08-on-destroy/case.py (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/debug/windows/.placeholder => wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/cases/__init__.py} (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/component-test/suites/01-life-cycle/suite_setup.py (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/component-test/suites/01-life-cycle/test-app/01_install.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/component-test/suites/01-life-cycle/test-app/02_request.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/component-test/suites/01-life-cycle/test-app/03_event.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/component-test/suites/01-life-cycle/test-app/04_request_internal_req.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/component-test/suites/01-life-cycle/test-app/04_request_internal_resp.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/component-test/suites/01-life-cycle/test-app/05_event_internal_provider.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/component-test/suites/01-life-cycle/test-app/05_event_internal_subscriber.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/component-test/suites/01-life-cycle/test-app/06_timer.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/component-test/suites/01-life-cycle/test-app/07_sensor.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/component-test/suites/01-life-cycle/test-app/08_on_destroy.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/component-test/suites/01-life-cycle/test-app/build.sh (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/component-test/suites/01-life-cycle/tools/product/start.sh (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/component-test/suites/01-life-cycle/tools/product/stop.sh (100%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/__init__.py rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/component-test/suites/readme.txt (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/host-tool/CMakeLists.txt (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/host-tool/external/cJSON/LICENSE (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/host-tool/external/cJSON/cJSON.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/host-tool/external/cJSON/cJSON.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/host-tool/external/cJSON/cjson.cmake (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/host-tool/src/host_tool_utils.c (79%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/host-tool/src/host_tool_utils.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/host-tool/src/main.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/host-tool/src/transport.c (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/host-tool/src/transport.h (100%) create mode 100755 lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/pick-up-emscripten-headers/collect_files.py rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/.gitattributes (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/Media/Config_building_target.png (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/Media/build_folder.png (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/Media/build_terminal.png (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/Media/change_workspace_dialog.png (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/Media/compilation_config.png (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/Media/compilation_config_2.png (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/Media/debug.png (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/Media/decoration_for_files.png (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/Media/docker_config.jpg (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/Media/docker_engine_config.png (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/Media/docker_images.png (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/Media/install_from_vsix.png (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/Media/new_project_page.png (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/Media/open_project_page.png (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/Media/project_template.png (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/Media/right_click_menus_1.png (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/Media/right_click_menus_2.png (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/Media/run.png (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/Media/save_configuration.png (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/Media/set_up_workspace_message.png (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/Media/wamr_ide_main_menu.png (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/README.md (62%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/Script/build.bat (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/Script/build.sh (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/VSCode-Extension/.eslintrc.json (66%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/VSCode-Extension/.gitignore (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/VSCode-Extension/.prettierrc.json (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/VSCode-Extension/.vscode/extensions.json (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/VSCode-Extension/.vscode/launch.json (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/VSCode-Extension/.vscode/tasks.json (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/VSCode-Extension/.vscodeignore (100%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/CONTRIBUTING.md rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/VSCode-Extension/LICENSE (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/VSCode-Extension/README.md (54%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/VSCode-Extension/package.json (96%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/debug/README.md create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/debug/darwin/.placeholder create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/debug/linux/.placeholder create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/debug/windows/.placeholder rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/VSCode-Extension/resource/scripts/CMakeLists.txt (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/VSCode-Extension/resource/scripts/boot_debugger_server.bat (88%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/VSCode-Extension/resource/scripts/boot_debugger_server.sh (89%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/VSCode-Extension/resource/scripts/build.bat (90%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/VSCode-Extension/resource/scripts/build.sh (89%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/VSCode-Extension/resource/scripts/destroy.bat (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/VSCode-Extension/resource/scripts/destroy.sh (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/VSCode-Extension/resource/scripts/project.cmake (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/VSCode-Extension/resource/scripts/run.bat (87%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/VSCode-Extension/resource/scripts/run.sh (88%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/assert.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/ctype.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/errno.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/fcntl.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/inttypes.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/limits.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/pthread.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/stdarg.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/stdbool.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/stdint.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/stdio.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/stdlib.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/string.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/strings.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/VSCode-Extension/resource/webview/css/style.css (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/VSCode-Extension/resource/webview/js/configbuildtarget.js (77%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/VSCode-Extension/resource/webview/js/newproj.js (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/VSCode-Extension/resource/webview/page/configBuildTarget.html (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/VSCode-Extension/resource/webview/page/newProject.html (100%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/src/constants.ts create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/src/debugConfigurationProvider.ts rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/VSCode-Extension/src/decorationProvider.ts (62%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/VSCode-Extension/src/extension.ts (69%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/VSCode-Extension/src/taskProvider.ts (91%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/src/utilities/directoryUtilities.ts create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/src/utilities/dockerUtilities.ts rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/VSCode-Extension/src/utilities/getUri.ts (97%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/src/utilities/lldbUtilities.ts rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/VSCode-Extension/src/view/NewProjectPanel.ts (74%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/VSCode-Extension/src/view/TargetConfigPanel.ts (66%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/tsconfig.json create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/WASM-Debug-Server/Docker/Dockerfile rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/WASM-Debug-Server/Docker/README.md (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/WASM-Debug-Server/Docker/build_docker_image.bat (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/WASM-Debug-Server/Docker/build_docker_image.sh (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/WASM-Debug-Server/Docker/resource/debug.sh (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/WASM-Debug-Server/Docker/resource/run.sh (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/WASM-Toolchain/Docker/.dockerignore (100%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/WASM-Toolchain/Docker/Dockerfile rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/WASM-Toolchain/Docker/README.md (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/WASM-Toolchain/Docker/build_docker_image.bat (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/WASM-Toolchain/Docker/build_docker_image.sh (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/WASM-Toolchain/Docker/resource/build_wasm.sh (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/test-tools/wamr-ide/WASM-Toolchain/Docker/resource/wamr_toolchain.cmake (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/tests/benchmarks/coremark/README.md (92%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/tests/benchmarks/coremark/build.sh (85%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/tests/benchmarks/coremark/run.sh (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/tests/benchmarks/jetstream/README.md (95%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/tests/benchmarks/jetstream/build.sh (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/tests/benchmarks/jetstream/jetstream.patch (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/tests/benchmarks/jetstream/run_aot.sh (100%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/tests/benchmarks/libsodium/README.md create mode 100755 lib/wasm-micro-runtime-WAMR-1.2.2/tests/benchmarks/libsodium/build.sh create mode 100755 lib/wasm-micro-runtime-WAMR-1.2.2/tests/benchmarks/libsodium/test_aot.sh rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/tests/benchmarks/polybench/README.md (94%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/tests/benchmarks/polybench/build.sh (96%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/tests/benchmarks/polybench/run_aot.sh (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/tests/benchmarks/polybench/run_interp.sh (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/tests/benchmarks/sightglass/README.md (94%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/tests/benchmarks/sightglass/build.sh (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/tests/benchmarks/sightglass/run_aot.sh (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/tests/benchmarks/sightglass/run_interp.sh (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/tests/wamr-test-suites/README.md (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/tests/wamr-test-suites/spec-test-script/CHANGES (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/tests/wamr-test-suites/spec-test-script/all.py (75%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/tests/wamr-test-suites/spec-test-script/all.sh (100%) create mode 100755 lib/wasm-micro-runtime-WAMR-1.2.2/tests/wamr-test-suites/spec-test-script/collect_coverage.sh rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/tests/wamr-test-suites/spec-test-script/ignore_cases.patch (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/tests/wamr-test-suites/spec-test-script/runtest.py (81%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/tests/wamr-test-suites/spec-test-script/simd_ignore_cases.patch (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/tests/wamr-test-suites/spec-test-script/tail-call/return_call.wast (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/tests/wamr-test-suites/spec-test-script/tail-call/return_call_indirect.wast (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/tests/wamr-test-suites/spec-test-script/thread_proposal_fix_atomic_case.patch (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/tests/wamr-test-suites/spec-test-script/thread_proposal_ignore_cases.patch (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/tests/wamr-test-suites/test_wamr.sh (59%) create mode 100755 lib/wasm-micro-runtime-WAMR-1.2.2/tests/wamr-test-suites/wasi-test-script/run_wasi_tests.sh rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/wamr-compiler/CMakeLists.txt (93%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/wamr-compiler/README.md rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/wamr-compiler/build_llvm.py (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/wamr-compiler/build_llvm.sh (70%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/wamr-compiler/build_llvm_arc.sh (71%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/wamr-compiler/build_llvm_xtensa.sh (72%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/wamr-compiler/main.c (93%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/wamr-sdk/Kconfig (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/wamr-sdk/Makefile (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/wamr-sdk/README.md (86%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/wamr-sdk/app/CMakeLists.txt (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/wamr-sdk/app/libc-builtin-sysroot/include/assert.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/wamr-sdk/app/libc-builtin-sysroot/include/ctype.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/wamr-sdk/app/libc-builtin-sysroot/include/errno.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/wamr-sdk/app/libc-builtin-sysroot/include/fcntl.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/wamr-sdk/app/libc-builtin-sysroot/include/inttypes.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/wamr-sdk/app/libc-builtin-sysroot/include/limits.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/wamr-sdk/app/libc-builtin-sysroot/include/pthread.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/wamr-sdk/app/libc-builtin-sysroot/include/semaphore.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/wamr-sdk/app/libc-builtin-sysroot/include/stdarg.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/wamr-sdk/app/libc-builtin-sysroot/include/stdbool.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/wamr-sdk/app/libc-builtin-sysroot/include/stdint.h (52%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/wamr-sdk/app/libc-builtin-sysroot/include/stdio.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/wamr-sdk/app/libc-builtin-sysroot/include/stdlib.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/wamr-sdk/app/libc-builtin-sysroot/include/string.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/wamr-sdk/app/libc-builtin-sysroot/include/strings.h (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/wamr-sdk/app/libc-builtin-sysroot/share/defined-symbols.txt (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/wamr-sdk/app/wamr_toolchain.cmake (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/wamr-sdk/app/wasi_toolchain.cmake (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/wamr-sdk/build_sdk.sh (98%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/wamr-sdk/menuconfig.sh (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/wamr-sdk/runtime/CMakeLists.txt (100%) rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/wamr-sdk/wamr_config_default.cmake (100%) create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/wamr-sdk/wamr_config_macos_release.cmake create mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/wamr-sdk/wamr_config_ubuntu_release.cmake rename lib/{wasm-micro-runtime-WAMR-1.1.1 => wasm-micro-runtime-WAMR-1.2.2}/zephyr/module.yml (100%) diff --git a/cmake/libraries.cmake b/cmake/libraries.cmake index 1c653ca2c19..098b4dba191 100644 --- a/cmake/libraries.cmake +++ b/cmake/libraries.cmake @@ -23,4 +23,4 @@ set(FLB_PATH_LIB_CARES "lib/c-ares-1.19.0") set(FLB_PATH_LIB_SNAPPY "lib/snappy-fef67ac") set(FLB_PATH_LIB_RDKAFKA "lib/librdkafka-2.1.0") set(FLB_PATH_LIB_RING_BUFFER "lib/lwrb") -set(FLB_PATH_LIB_WASM_MICRO_RUNTIME "lib/wasm-micro-runtime-WAMR-1.1.1") +set(FLB_PATH_LIB_WASM_MICRO_RUNTIME "lib/wasm-micro-runtime-WAMR-1.2.2") diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/.github/workflows/compilation_on_android_ubuntu.yml b/lib/wasm-micro-runtime-WAMR-1.1.1/.github/workflows/compilation_on_android_ubuntu.yml deleted file mode 100644 index 97021f171b9..00000000000 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/.github/workflows/compilation_on_android_ubuntu.yml +++ /dev/null @@ -1,573 +0,0 @@ -# Copyright (C) 2019 Intel Corporation. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -name: compilation on android, ubuntu-20.04, ubuntu-22.04 - -on: - # will be triggered on PR events - pull_request: - paths-ignore: - - "assembly-script/**" - - "ci/**" - - "doc/**" - - "test-tools/**" - - ".github/workflows/compilation_on_android_ubuntu.yml" - # will be triggered on push events - push: - paths-ignore: - - "assembly-script/**" - - "ci/**" - - "doc/**" - - "test-tools/**" - - ".github/workflows/compilation_on_android_ubuntu.yml" - # allow to be triggered manually - workflow_dispatch: - -# Cancel any in-flight jobs for the same PR/branch so there's only one active -# at a time -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -env: - # For BUILD - AOT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=0 -DWAMR_BUILD_LAZY_JIT=0" - CLASSIC_INTERP_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=0 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=1 -DWAMR_BUILD_JIT=0 -DWAMR_BUILD_LAZY_JIT=0" - FAST_INTERP_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=0 -DWAMR_BUILD_FAST_INTERP=1 -DWAMR_BUILD_INTERP=1 -DWAMR_BUILD_JIT=0 -DWAMR_BUILD_LAZY_JIT=0" - LAZY_JIT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=1" - MC_JIT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=0" - # LLVM - LLVM_CACHE_SUFFIX: "build-llvm_libraries_ex" - # For Spec Test - DEFAULT_TEST_OPTIONS: "-s spec -P" - MULTI_MODULES_TEST_OPTIONS: "-s spec -M -P" - SIMD_TEST_OPTIONS: "-s spec -S -P" - THREADS_TEST_OPTIONS: "-s spec -p -P" - X86_32_TARGET_TEST_OPTIONS: "-m x86_32 -P" - -jobs: - # Cancel any in-flight jobs for the same PR/branch so there's only one active - # at a time - cancel_previous: - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-20.04, ubuntu-22.04] - steps: - - name: Cancel Workflow Action - uses: styfle/cancel-workflow-action@0.9.1 - with: - access_token: ${{ github.token }} - - # set different traffic lights based on the current repo and the running OS. - # according to light colors, the workflow will run different jobs - # it is used to separate between the public repo and the private repo - check_repo: - needs: cancel_previous - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-20.04, ubuntu-22.04] - outputs: - traffic_light_on_ubuntu_2004: ${{ steps.do_check_on_ubuntu_2004.outputs.light }} - traffic_light_on_ubuntu_2204: ${{ steps.do_check_on_ubuntu_2204.outputs.light }} - steps: - - name: do_check_on_ubuntu_2004 - id: do_check_on_ubuntu_2004 - if: ${{ matrix.os == 'ubuntu-20.04' }} - run: | - if [[ ${{ github.repository }} == */wasm-micro-runtime ]]; then - echo "::set-output name=light::green" - else - echo "::set-output name=light::red" - fi - - - name: do_check_on_ubuntu_2204 - id: do_check_on_ubuntu_2204 - if: ${{ matrix.os == 'ubuntu-22.04' }} - run: | - if [[ ${{ github.repository }} == */wasm-micro-runtime ]]; then - echo "::set-output name=light::green" - else - echo "::set-output name=light::green" - fi - - build_llvm_libraries: - needs: check_repo - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-20.04, ubuntu-22.04] - include: - - os: ubuntu-20.04 - light: ${{ needs.check_repo.outputs.traffic_light_on_ubuntu_2004 }} - - os: ubuntu-22.04 - light: ${{ needs.check_repo.outputs.traffic_light_on_ubuntu_2204 }} - steps: - - name: light status - run: echo "matrix.os=${{ matrix.os }}, light=${{ matrix.light }}" - - - name: checkout - if: ${{ matrix.light == 'green' }} - uses: actions/checkout@v3 - - - name: Cache LLVM libraries - id: cache_llvm - if: ${{ matrix.light == 'green' }} - uses: actions/cache@v3 - with: - path: | - ./core/deps/llvm/build/bin - ./core/deps/llvm/build/include - ./core/deps/llvm/build/lib - ./core/deps/llvm/build/libexec - ./core/deps/llvm/build/share - key: ${{ matrix.os }}-${{ env.LLVM_CACHE_SUFFIX }} - - - name: Build llvm and clang from source - id: build_llvm - if: ${{ matrix.light == 'green' && steps.cache_llvm.outputs.cache-hit != 'true' }} - run: /usr/bin/env python3 ./build_llvm.py --arch X86 WebAssembly --project clang lldb - working-directory: build-scripts - - build_wamrc: - needs: [build_llvm_libraries, check_repo] - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-20.04, ubuntu-22.04] - include: - - os: ubuntu-20.04 - light: ${{ needs.check_repo.outputs.traffic_light_on_ubuntu_2004 }} - - os: ubuntu-22.04 - light: ${{ needs.check_repo.outputs.traffic_light_on_ubuntu_2204 }} - steps: - - name: light status - run: echo "matrix.os=${{ matrix.os }}, light=${{ matrix.light }}" - - - name: checkout - if: ${{ matrix.light == 'green' }} - uses: actions/checkout@v3 - - - name: Get LLVM libraries - id: cache_llvm - if: ${{ matrix.light == 'green' }} - uses: actions/cache@v3 - with: - path: | - ./core/deps/llvm/build/bin - ./core/deps/llvm/build/include - ./core/deps/llvm/build/lib - ./core/deps/llvm/build/libexec - ./core/deps/llvm/build/share - key: ${{ matrix.os }}-${{ env.LLVM_CACHE_SUFFIX }} - - - name: Quit if cache miss - if: ${{ matrix.light == 'green' && steps.cache_llvm.outputs.cache-hit != 'true' }} - run: echo "::error::can not get prebuilt llvm libraries" && exit 1 - - - name: Build wamrc - if: ${{ matrix.light == 'green' }} - run: | - mkdir build && cd build - cmake .. - cmake --build . --config Release --parallel 4 - working-directory: wamr-compiler - - build_iwasm: - needs: [build_llvm_libraries, check_repo] - runs-on: ${{ matrix.os }} - strategy: - matrix: - make_options_run_mode: [ - # Running mode - $AOT_BUILD_OPTIONS, - $CLASSIC_INTERP_BUILD_OPTIONS, - $FAST_INTERP_BUILD_OPTIONS, - $LAZY_JIT_BUILD_OPTIONS, - $MC_JIT_BUILD_OPTIONS, - ] - make_options_feature: [ - # Features - "-DWAMR_BUILD_CUSTOM_NAME_SECTION=1", - "-DWAMR_BUILD_DEBUG_AOT=1", - "-DWAMR_BUILD_DEBUG_INTERP=1", - "-DWAMR_BUILD_DUMP_CALL_STACK=1", - "-DWAMR_BUILD_LIB_PTHREAD=1", - "-DWAMR_BUILD_LOAD_CUSTOM_SECTION=1", - "-DWAMR_BUILD_MINI_LOADER=1", - "-DWAMR_BUILD_MEMORY_PROFILING=1", - "-DWAMR_BUILD_MULTI_MODULE=1", - "-DWAMR_BUILD_PERF_PROFILING=1", - "-DWAMR_BUILD_REF_TYPES=1", - "-DWAMR_BUILD_SIMD=1", - "-DWAMR_BUILD_TAIL_CALL=1", - "-DWAMR_DISABLE_HW_BOUND_CHECK=1", - ] - os: [ubuntu-20.04, ubuntu-22.04] - platform: [android, linux] - exclude: - # uncompatiable feature and platform - # uncompatiable mode and feature - # MULTI_MODULE only on INTERP mode - - make_options_run_mode: $LAZY_JIT_BUILD_OPTIONS - make_options_feature: "-DWAMR_BUILD_MULTI_MODULE=1" - - make_options_run_mode: $AOT_BUILD_OPTIONS - make_options_feature: "-DWAMR_BUILD_MULTI_MODULE=1" - - make_options_run_mode: $MC_JIT_BUILD_OPTIONS - make_options_feature: "-DWAMR_BUILD_MULTI_MODULE=1" - # SIMD only on JIT/AOT mode - - make_options_run_mode: $CLASSIC_INTERP_BUILD_OPTIONS - make_options_feature: "-DWAMR_BUILD_SIMD=1" - - make_options_run_mode: $FAST_INTERP_BUILD_OPTIONS - make_options_feature: "-DWAMR_BUILD_SIMD=1" - # DEBUG_INTERP only on CLASSIC INTERP mode - - make_options_run_mode: $AOT_BUILD_OPTIONS - make_options_feature: "-DWAMR_BUILD_DEBUG_INTERP=1" - - make_options_run_mode: $LAZY_JIT_BUILD_OPTIONS - make_options_feature: "-DWAMR_BUILD_DEBUG_INTERP=1" - - make_options_run_mode: $MC_JIT_BUILD_OPTIONS - make_options_feature: "-DWAMR_BUILD_DEBUG_INTERP=1" - - make_options_run_mode: $FAST_INTERP_BUILD_OPTIONS - make_options_feature: "-DWAMR_BUILD_DEBUG_INTERP=1" - # DEBUG_AOT only on JIT/AOT mode - - make_options_run_mode: $CLASSIC_INTERP_BUILD_OPTIONS - make_options_feature: "-DWAMR_BUILD_DEBUG_AOT=1" - - make_options_run_mode: $FAST_INTERP_BUILD_OPTIONS - make_options_feature: "-DWAMR_BUILD_DEBUG_AOT=1" - # TODO: DEBUG_AOT on JIT - - make_options_run_mode: $LAZY_JIT_BUILD_OPTIONS - make_options_feature: "-DWAMR_BUILD_DEBUG_AOT=1" - - make_options_run_mode: $MC_JIT_BUILD_OPTIONS - make_options_feature: "-DWAMR_BUILD_DEBUG_AOT=1" - # MINI_LOADER only on INTERP mode - - make_options_run_mode: $AOT_BUILD_OPTIONS - make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1" - - make_options_run_mode: $LAZY_JIT_BUILD_OPTIONS - make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1" - - make_options_run_mode: $MC_JIT_BUILD_OPTIONS - make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1" - include: - - os: ubuntu-20.04 - light: ${{ needs.check_repo.outputs.traffic_light_on_ubuntu_2004 }} - - os: ubuntu-22.04 - light: ${{ needs.check_repo.outputs.traffic_light_on_ubuntu_2204 }} - steps: - - name: light status - run: echo "matrix.os=${{ matrix.os }}, light=${{ matrix.light }}" - - - name: checkout - if: ${{ matrix.light == 'green' }} - uses: actions/checkout@v3 - - # only download llvm cache when needed - - name: Get LLVM libraries - id: cache_llvm - if: (matrix.light == 'green') && (endsWith(matrix.make_options_run_mode, '_JIT_BUILD_OPTIONS')) - uses: actions/cache@v3 - with: - path: | - ./core/deps/llvm/build/bin - ./core/deps/llvm/build/include - ./core/deps/llvm/build/lib - ./core/deps/llvm/build/libexec - ./core/deps/llvm/build/share - key: ${{ matrix.os }}-${{ env.LLVM_CACHE_SUFFIX }} - - - name: Quit if cache miss - if: (matrix.light == 'green') && (endsWith(matrix.make_options_run_mode, '_JIT_BUILD_OPTIONS')) && (steps.cache_llvm.outputs.cache-hit != 'true') - run: echo "::error::can not get prebuilt llvm libraries" && exit 1 - - - name: Build iwasm - if: ${{ matrix.light == 'green' }} - run: | - mkdir build && cd build - cmake .. ${{ matrix.make_options_run_mode }} ${{ matrix.make_options_feature }} - cmake --build . --config Release --parallel 4 - working-directory: product-mini/platforms/${{ matrix.platform }} - - build_samples_wasm_c_api: - needs: [build_iwasm, build_llvm_libraries, build_wamrc, check_repo] - runs-on: ${{ matrix.os }} - strategy: - matrix: - make_options: [ - # Running mode - $CLASSIC_INTERP_BUILD_OPTIONS, - $FAST_INTERP_BUILD_OPTIONS, - $LAZY_JIT_BUILD_OPTIONS, - $MC_JIT_BUILD_OPTIONS, - $AOT_BUILD_OPTIONS, - ] - os: [ubuntu-20.04, ubuntu-22.04] - include: - - os: ubuntu-20.04 - light: ${{ needs.check_repo.outputs.traffic_light_on_ubuntu_2004 }} - wasi_sdk_release: https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-12/wasi-sdk-12.0-linux.tar.gz - wabt_release: https://github.com/WebAssembly/wabt/releases/download/1.0.24/wabt-1.0.24-ubuntu.tar.gz - - os: ubuntu-22.04 - light: ${{ needs.check_repo.outputs.traffic_light_on_ubuntu_2204 }} - wasi_sdk_release: https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-12/wasi-sdk-12.0-linux.tar.gz - wabt_release: https://github.com/WebAssembly/wabt/releases/download/1.0.24/wabt-1.0.24-ubuntu.tar.gz - steps: - - name: light status - run: echo "matrix.os=${{ matrix.os }}, light=${{ matrix.light }}" - - - name: checkout - if: ${{ matrix.light == 'green' }} - uses: actions/checkout@v3 - - - name: Get LLVM libraries - id: cache_llvm - if: (matrix.light == 'green') && (!endsWith(matrix.make_options, '_INTERP_BUILD_OPTIONS')) - uses: actions/cache@v3 - with: - path: | - ./core/deps/llvm/build/bin - ./core/deps/llvm/build/include - ./core/deps/llvm/build/lib - ./core/deps/llvm/build/libexec - ./core/deps/llvm/build/share - key: ${{ matrix.os }}-${{ env.LLVM_CACHE_SUFFIX }} - - - name: Quit if cache miss - if: (matrix.light == 'green') && (!endsWith(matrix.make_options, '_INTERP_BUILD_OPTIONS')) && (steps.cache_llvm.outputs.cache-hit != 'true') - run: echo "::error::can not get prebuilt llvm libraries" && exit 1 - - - name: download and install wabt - if: ${{ matrix.light == 'green' }} - run: | - cd /opt - sudo wget ${{ matrix.wabt_release }} - sudo tar -xzf wabt-1.0.24-*.tar.gz - sudo mv wabt-1.0.24 wabt - - - name: Build wamrc - if: (matrix.light == 'green') && (!endsWith(matrix.make_options, '_INTERP_BUILD_OPTIONS')) - run: | - mkdir build && cd build - cmake .. - cmake --build . --config Release --parallel 4 - working-directory: wamr-compiler - - - name: Build Sample [wasm-c-api] - if: ${{ matrix.light == 'green' }} - run: | - mkdir build && cd build - cmake .. ${{ matrix.make_options }} - cmake --build . --config Release --parallel 4 - ./callback - ./callback_chain - ./empty_imports - ./global - ./hello - ./hostref - ./memory - ./reflect - ./table - ./trap - working-directory: samples/wasm-c-api - - build_samples_others: - needs: [build_iwasm, check_repo] - runs-on: ${{ matrix.os }} - strategy: - matrix: - include: - - os: ubuntu-20.04 - light: ${{ needs.check_repo.outputs.traffic_light_on_ubuntu_2004 }} - wasi_sdk_release: https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-12/wasi-sdk-12.0-linux.tar.gz - wabt_release: https://github.com/WebAssembly/wabt/releases/download/1.0.24/wabt-1.0.24-ubuntu.tar.gz - - os: ubuntu-22.04 - light: ${{ needs.check_repo.outputs.traffic_light_on_ubuntu_2204 }} - wasi_sdk_release: https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-12/wasi-sdk-12.0-linux.tar.gz - wabt_release: https://github.com/WebAssembly/wabt/releases/download/1.0.24/wabt-1.0.24-ubuntu.tar.gz - steps: - - name: light status - run: echo "matrix.os=${{ matrix.os }}, light=${{ matrix.light }}" - - - name: checkout - if: ${{ matrix.light == 'green' }} - uses: actions/checkout@v3 - - - name: download and install wasi-sdk - if: ${{ matrix.light == 'green' }} - run: | - cd /opt - sudo wget ${{ matrix.wasi_sdk_release }} - sudo tar -xzf wasi-sdk-12.0-*.tar.gz - sudo mv wasi-sdk-12.0 wasi-sdk - - - name: download and install wabt - if: ${{ matrix.light == 'green' }} - run: | - cd /opt - sudo wget ${{ matrix.wabt_release }} - sudo tar -xzf wabt-1.0.24-*.tar.gz - sudo mv wabt-1.0.24 wabt - - - name: Build Sample [basic] - if: ${{ matrix.light == 'green' }} - run: | - cd samples/basic - ./build.sh - ./run.sh - - - name: Build Sample [file] - if: ${{ matrix.light == 'green' }} - run: | - cd samples/file - mkdir build && cd build - cmake .. - cmake --build . --config Release --parallel 4 - ./src/iwasm -f wasm-app/file.wasm -d . - - - name: Build Sample [multi-thread] - if: ${{ matrix.light == 'green' }} - run: | - cd samples/multi-thread - mkdir build && cd build - cmake .. - cmake --build . --config Release --parallel 4 - ./iwasm wasm-apps/test.wasm - - - name: Build Sample [multi-module] - if: ${{ matrix.light == 'green' }} - run: | - cd samples/multi-module - mkdir build && cd build - cmake .. - cmake --build . --config Release --parallel 4 - ./multi_module - - - name: Build Sample [spawn-thread] - if: ${{ matrix.light == 'green' }} - run: | - cd samples/spawn-thread - mkdir build && cd build - cmake .. - cmake --build . --config Release --parallel 4 - ./spawn_thread - - - name: Build Sample [ref-types] - if: ${{ matrix.light == 'green' }} - run: | - cd samples/ref-types - mkdir build && cd build - cmake .. - cmake --build . --config Release --parallel 4 - ./hello - - spec_test_default: - needs: [build_iwasm, build_llvm_libraries, build_wamrc, check_repo] - runs-on: ubuntu-20.04 - strategy: - matrix: - test_option: [$DEFAULT_TEST_OPTIONS] - steps: - - name: checkout - uses: actions/checkout@v3 - - - name: Get LLVM libraries - id: cache_llvm - uses: actions/cache@v3 - with: - path: | - ./core/deps/llvm/build/bin - ./core/deps/llvm/build/include - ./core/deps/llvm/build/lib - ./core/deps/llvm/build/libexec - ./core/deps/llvm/build/share - key: ubuntu-20.04-${{ env.LLVM_CACHE_SUFFIX }} - - - name: Quit if cache miss - if: steps.cache_llvm.outputs.cache-hit != 'true' - run: echo "::error::can not get prebuilt llvm libraries" && exit 1 - - - name: install Ninja - run: sudo apt install -y ninja-build - - - name: run spec tests - run: ./test_wamr.sh ${{ matrix.test_option }} - working-directory: ./tests/wamr-test-suites - - spec_test_extra: - if: ${{ endsWith(github.repository, 'wasm-micro-runtime') }} - needs: [build_iwasm, build_llvm_libraries, build_wamrc, check_repo] - runs-on: ubuntu-20.04 - strategy: - matrix: - running_mode: ["classic-interp", "fast-interp", "jit", "aot"] - test_option: - [ - $MULTI_MODULES_TEST_OPTIONS, - $SIMD_TEST_OPTIONS, - $THREADS_TEST_OPTIONS, - ] - steps: - - name: checkout - uses: actions/checkout@v3 - - - name: Get LLVM libraries - id: cache_llvm - uses: actions/cache@v3 - with: - path: | - ./core/deps/llvm/build/bin - ./core/deps/llvm/build/include - ./core/deps/llvm/build/lib - ./core/deps/llvm/build/libexec - ./core/deps/llvm/build/share - key: ubuntu-20.04-${{ env.LLVM_CACHE_SUFFIX }} - - - name: Quit if cache miss - if: steps.cache_llvm.outputs.cache-hit != 'true' - run: echo "::error::can not get prebuilt llvm libraries" && exit 1 - - - name: install Ninja - run: sudo apt install -y ninja-build - - - name: run spec tests - run: ./test_wamr.sh ${{ matrix.test_option }} -t ${{ matrix.running_mode }} - working-directory: ./tests/wamr-test-suites - - spec_test_x86_32: - if: ${{ endsWith(github.repository, 'wasm-micro-runtime') }} - needs: [build_iwasm, build_llvm_libraries, build_wamrc, check_repo] - runs-on: ubuntu-20.04 - strategy: - matrix: - running_mode: ["classic-interp", "fast-interp", "jit", "aot"] - test_option: [$DEFAULT_TEST_OPTIONS, $THREADS_TEST_OPTIONS] - steps: - - name: checkout - uses: actions/checkout@v3 - - - name: Get LLVM libraries - id: cache_llvm - uses: actions/cache@v3 - with: - path: | - ./core/deps/llvm/build/bin - ./core/deps/llvm/build/include - ./core/deps/llvm/build/lib - ./core/deps/llvm/build/libexec - ./core/deps/llvm/build/share - key: ubuntu-20.04-${{ env.LLVM_CACHE_SUFFIX }} - - - name: Quit if cache miss - if: steps.cache_llvm.outputs.cache-hit != 'true' - run: echo "::error::can not get prebuilt llvm libraries" && exit 1 - - - name: install Ninja and x32 support libraries - run: - # Add another apt repository as some packages cannot - # be downloaded with the github default repository - sudo curl -sSL https://packages.microsoft.com/keys/microsoft.asc | sudo tee /etc/apt/trusted.gpg.d/microsoft.asc && - sudo apt-add-repository https://packages.microsoft.com/ubuntu/20.04/prod && - sudo apt-get update && - sudo apt install -y g++-multilib lib32gcc-9-dev ninja-build - - - name: run spec tests - run: ./test_wamr.sh ${{ env.X86_32_TARGET_TEST_OPTIONS }} ${{ matrix.test_option }} -t ${{ matrix.running_mode }} - working-directory: ./tests/wamr-test-suites diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/.github/workflows/compilation_on_windows.yml b/lib/wasm-micro-runtime-WAMR-1.1.1/.github/workflows/compilation_on_windows.yml deleted file mode 100644 index 408bdc25e29..00000000000 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/.github/workflows/compilation_on_windows.yml +++ /dev/null @@ -1,115 +0,0 @@ -# Copyright (C) 2019 Intel Corporation. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -name: compilation on windows-latest - -on: - # will be triggered on PR events - pull_request: - paths-ignore: - - "assembly-script/**" - - "ci/**" - - "doc/**" - - "test-tools/**" - - ".github/workflows/compilation_on_windows.yml" - # will be triggered on push events - push: - paths-ignore: - - "assembly-script/**" - - "ci/**" - - "doc/**" - - "test-tools/**" - - ".github/workflows/compilation_on_windows.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: - # Cancel any in-flight jobs for the same PR/branch so there's only one active - # at a time - cancel_previous: - runs-on: windows-latest - steps: - - name: Cancel Workflow Action - uses: styfle/cancel-workflow-action@0.9.1 - with: - access_token: ${{ github.token }} - - build: - needs: cancel_previous - runs-on: windows-latest - steps: - - uses: actions/checkout@v3 - - - name: clone uvwasi library - run: | - cd core/deps - git clone https://github.com/nodejs/uvwasi.git - - name: Build iwasm [default] - run: | - cd product-mini/platforms/windows - mkdir build && cd build - cmake .. - cmake --build . --config Release --parallel 4 - cd .. && rm -force -r build - - name: Build iwasm [aot only] - run: | - cd product-mini/platforms/windows - mkdir build && cd build - cmake .. -DWAMR_BUILD_AOT=1 -DWAMR_BUILD_INTERP=0 - cmake --build . --config Release --parallel 4 - cd .. && rm -force -r build - - name: Build iwasm [interp only] - run: | - cd product-mini/platforms/windows - mkdir build && cd build - cmake .. -DWAMR_BUILD_AOT=0 - cmake --build . --config Release --parallel 4 - cd .. && rm -force -r build - - name: Build iwasm [tail call] - run: | - cd product-mini/platforms/windows - mkdir build && cd build - cmake .. -DWAMR_BUILD_TAIL_CALL=1 - cmake --build . --config Release --parallel 4 - cd .. && rm -force -r build - - name: Build iwasm [custom name section] - run: | - cd product-mini/platforms/windows - mkdir build && cd build - cmake .. -DWAMR_BUILD_CUSTOM_NAME_SECTION=1 - cmake --build . --config Release --parallel 4 - cd .. && rm -force -r build - - name: Build iwasm [disable hardware boundary check] - run: | - cd product-mini/platforms/windows - mkdir build && cd build - cmake .. -DWAMR_DISABLE_HW_BOUND_CHECK=1 - cmake --build . --config Release --parallel 4 - cd .. && rm -force -r build - - name: Build iwasm [reference types] - run: | - cd product-mini/platforms/windows - mkdir build && cd build - cmake .. -DWAMR_BUILD_REF_TYPES=1 - cmake --build . --config Release --parallel 4 - cd .. && rm -force -r build - - name: Build iwasm [128-bit SIMD] - run: | - cd product-mini/platforms/windows - mkdir build && cd build - cmake .. -DWAMR_BUILD_SIMD=1 - cmake --build . --config Release --parallel 4 - cd .. && rm -force -r build - - name: Build iwasm [source debugger] - run: | - cd product-mini/platforms/windows - mkdir build && cd build - cmake .. -DWAMR_BUILD_DEBUG_INTERP=1 - cmake --build . --config Release --parallel 4 - cd .. && rm -force -r build diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/README.md b/lib/wasm-micro-runtime-WAMR-1.1.1/README.md deleted file mode 100644 index 84bee711591..00000000000 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/README.md +++ /dev/null @@ -1,194 +0,0 @@ -WebAssembly Micro Runtime -========================= -[Build WAMR](./doc/build_wamr.md) | [Build AOT Compiler](./README.md#build-wamrc-aot-compiler) | [Embed WAMR](./doc/embed_wamr.md) | [Export Native API](./doc/export_native_api.md) | [Build WASM Apps](./doc/build_wasm_app.md) | [Samples](./README.md#samples) - -**A [Bytecode Alliance][BA] project** - -[BA]: https://bytecodealliance.org/ - -WebAssembly Micro Runtime (WAMR) is a lightweight standalone WebAssembly (WASM) runtime with small footprint, high performance and highly configurable features for applications cross from embedded, IoT, edge to Trusted Execution Environment (TEE), smart contract, cloud native and so on. It includes a few parts as below: -- The [**"iwasm" VM core**](./README.md#iwasm-vm-core) to run WASM applications, supporting interpreter mode, AOT mode (Ahead-of-Time compilation) and JIT modes (Just-in-Time compilation, LLVM JIT and Fast JIT are supported) - -- The [**"wamrc" AOT compiler**](./README.md#build-wamrc-aot-compiler) to compile WASM file into AOT file for best performance and smaller runtime footprint, which is run by "iwasm" VM Core - -- The [**application framework**](./README.md#application-framework) and the supporting APIs for the WASM applications - -- The [**dynamic management**](./README.md#remote-application-management) of the WASM applications - -Getting started -================== -- [Build iwasm VM core](./doc/build_wamr.md) on [Linux](./doc/build_wamr.md#linux), [SGX](./doc/linux_sgx.md), [MacOS](./doc/build_wamr.md#macos) and [Windows](./doc/build_wamr.md#windows), and [Build wamrc AOT compiler](./README.md#build-wamrc-aot-compiler) -- [Embed WAMR into host applications](./doc/embed_wamr.md) - - [Embed into C/C++](./doc/embed_wamr.md), [Embed into Python](./language-bindings/python), [Embed into Go](./language-bindings/go) - -- [Register native APIs for WASM applications](./doc/export_native_api.md) -- [Build WASM applications](./doc/build_wasm_app.md) -- [Port WAMR to a new platform](./doc/port_wamr.md) -- [Benchmarks](./tests/benchmarks) and [Samples](./samples) -- [VS Code development container](./doc/devcontainer.md) - -iwasm VM core -========================= - -### Key features - -- Full compliant to the W3C WASM MVP -- Small runtime binary size (~85K for interpreter and ~50K for AOT) and low memory usage -- Near to native speed by AOT and JIT -- Self-implemented AOT module loader to enable AOT working on Linux, Windows, MacOS, Android, SGX and MCU systems -- Choices of WASM application libc support: the built-in libc subset for the embedded environment or [WASI](https://github.com/WebAssembly/WASI) for the standard libc -- [The simple C APIs to embed WAMR into host environment](./doc/embed_wamr.md), see [how to integrate WAMR](./doc/embed_wamr.md) and the [API list](./core/iwasm/include/wasm_export.h) -- [The mechanism to export native APIs to WASM applications](./doc/export_native_api.md), see [how to register native APIs](./doc/export_native_api.md) -- [Multiple modules as dependencies](./doc/multi_module.md), ref to [document](./doc/multi_module.md) and [sample](samples/multi-module) -- [Multi-thread, pthread APIs and thread management](./doc/pthread_library.md), ref to [document](./doc/pthread_library.md) and [sample](samples/multi-thread) -- [Linux SGX (Intel Software Guard Extension) support](./doc/linux_sgx.md), ref to [document](./doc/linux_sgx.md) -- [Source debugging support](./doc/source_debugging.md), ref to [document](./doc/source_debugging.md) -- [WAMR-IDE (Experimental)](./test-tools/wamr-ide) to develop WebAssembly applications with build, run and debug support, ref to [document](./test-tools/wamr-ide) -- [XIP (Execution In Place) support](./doc/xip.md), ref to [document](./doc/xip.md) -- [Berkeley/Posix Socket support](./doc/socket_api.md), ref to [document](./doc/socket_api.md) and [sample](./samples/socket-api) -- Language bindings: [Go](./language-bindings/go/README.md), [Python](./language-bindings/python/README.md) - -### WASM post-MVP features -- [wasm-c-api](https://github.com/WebAssembly/wasm-c-api), ref to [document](doc/wasm_c_api.md) and [sample](samples/wasm-c-api) -- [128-bit SIMD](https://github.com/WebAssembly/simd), ref to [samples/workload](samples/workload) -- [Reference Types](https://github.com/WebAssembly/reference-types), ref to [document](doc/ref_types.md) and [sample](samples/ref-types) -- [Non-trapping float-to-int conversions](https://github.com/WebAssembly/nontrapping-float-to-int-conversions) -- [Sign-extension operators](https://github.com/WebAssembly/sign-extension-ops), [Bulk memory operations](https://github.com/WebAssembly/bulk-memory-operations) -- [Multi-value](https://github.com/WebAssembly/multi-value), [Tail-call](https://github.com/WebAssembly/tail-call), [Shared memory](https://github.com/WebAssembly/threads/blob/main/proposals/threads/Overview.md#shared-linear-memory) - -### Supported architectures and platforms - -The iwasm supports the following architectures: - -- X86-64, X86-32 -- ARM, THUMB (ARMV7 Cortex-M7 and Cortex-A15 are tested) -- AArch64 (Cortex-A57 and Cortex-A53 are tested) -- RISCV64, RISCV32 (RISC-V LP64 and RISC-V LP64D are tested) -- XTENSA, MIPS, ARC - -The following platforms are supported, click each link below for how to build iwasm on that platform. Refer to [WAMR porting guide](./doc/port_wamr.md) for how to port WAMR to a new platform. - -- [Linux](./doc/build_wamr.md#linux), [Linux SGX (Intel Software Guard Extension)](./doc/linux_sgx.md), [MacOS](./doc/build_wamr.md#macos), [Android](./doc/build_wamr.md#android), [Windows](./doc/build_wamr.md#windows), [Windows (MinGW)](./doc/build_wamr.md#mingw) -- [Zephyr](./doc/build_wamr.md#zephyr), [AliOS-Things](./doc/build_wamr.md#alios-things), [VxWorks](./doc/build_wamr.md#vxworks), [NuttX](./doc/build_wamr.md#nuttx), [RT-Thread](./doc/build_wamr.md#RT-Thread), [ESP-IDF](./doc/build_wamr.md#esp-idf) - -### Build iwasm VM core (mini product) - -WAMR supports building the iwasm VM core only (no app framework) to the mini product. The WAMR mini product takes the WASM application file name or AOT file name as input and then executes it. For the detailed procedure, please see **[build WAMR VM core](./doc/build_wamr.md)** and **[build and run WASM application](./doc/build_wasm_app.md)**. Also we can click the link of each platform above to see how to build iwasm on it. - -### Build wamrc AOT compiler - -Both wasm binary file and AOT file are supported by iwasm. The wamrc AOT compiler is to compile wasm binary file to AOT file which can also be run by iwasm. Execute following commands to build **wamrc** compiler for Linux: - -```shell -cd wamr-compiler -./build_llvm.sh (or "./build_llvm_xtensa.sh" to support xtensa target) -mkdir build && cd build -cmake .. (or "cmake .. -DWAMR_BUILD_PLATFORM=darwin" for MacOS) -make -# wamrc is generated under current directory -``` - -For **Windows**: -```shell -cd wamr-compiler -python build_llvm.py -mkdir build && cd build -cmake .. -cmake --build . --config Release -# wamrc.exe is generated under .\Release directory -``` - -### Performance and Footprint - -- [Performance and footprint data](https://github.com/bytecodealliance/wasm-micro-runtime/wiki/Performance): checkout [here](https://github.com/bytecodealliance/wasm-micro-runtime/wiki/Performance) for the performance and footprint data -- [Memory usage tunning](./doc/memory_tune.md): checkout [here](./doc/memory_tune.md) for the memory model and how to tune the memory usage -- [Memory usage profiling](./doc/build_wamr.md#enable-memory-profiling-experiment): checkout [here](./doc/build_wamr.md#enable-memory-profiling-experiment) for how to profile the memory usage -- [Benchmarks](./tests/benchmarks): checkout these links for how to run the benchmarks: [PolyBench](./tests/benchmarks/polybench), [CoreMark](./tests/benchmarks/coremark), [Sightglass](./tests/benchmarks/sightglass), [JetStream2](./tests/benchmarks/jetstream) - -### User cases - -WAMR is widely used in a lot areas, here are some cases: -- [Hyperledger Private Data Objects](https://github.com/hyperledger-labs/private-data-objects/blob/main/common/interpreter/wawaka_wasm/README.md) -- [Inclavare Containers](https://github.com/alibaba/inclavare-containers) -- [Fassm](https://github.com/faasm/faasm) -- [Waft](https://developer.aliyun.com/article/787582) -- [Envoy Proxy](https://github.com/envoyproxy/envoy) -- [Apache Teaclave](https://teaclave.apache.org/docs/executing-wasm) - -Application framework -=================================== - -By using the iwasm VM core, we are flexible to build different application frameworks for the specific domains, although it would take quite some effort. - -The WAMR has offered a comprehensive framework for programming WASM applications for device and IoT usages. The framework supports running multiple applications, that are based on the event driven programming model. Here are the supporting API sets by the [WAMR application framework library](./doc/wamr_api.md) : - -- Timer, Inter-app communication (request/response and pub/sub), Sensor, Connectivity and data transmission, 2D graphic UI - -Browse the folder [core/app-framework](./core/app-framework) for how to extend the application framework. - -# Remote application management - -The WAMR application manager supports [remote application management](./core/app-mgr) from the host environment or the cloud through any physical communications such as TCP, UPD, UART, BLE, etc. Its modular design makes it able to support application management for different managed runtimes. - -The tool [host_tool](./test-tools/host-tool) communicates to the WAMR app manager for installing/uninstalling the WASM applications on companion chip from the host system. And the [IoT App Store Demo](./test-tools/IoT-APP-Store-Demo/) shows the conception of remotely managing the device applications from the cloud. - - -WAMR SDK -========== - -Usually there are two tasks for integrating the WAMR into a particular project: - -- Select what WAMR components (vmcore, libc, app-mgr, app-framework components) to be integrated, and get the associated source files added into the project building configuration -- Generate the APP SDK for developing the WASM apps on the selected libc and framework components - -The **[WAMR SDK](./wamr-sdk)** tools is helpful to finish the two tasks quickly. It supports menu configuration for selecting WAMR components and builds the WAMR to a SDK package that includes **runtime SDK** and **APP SDK**. The runtime SDK is used for building the native application and the APP SDK should be shipped to WASM application developers. - - -Samples -================= - -The WAMR [samples](./samples) integrate the iwasm VM core, application manager and selected application framework components. - -- [**basic**](./samples/basic): Demonstrating how to use runtime exposed API's to call WASM functions, how to register native functions and call them, and how to call WASM function from native function. -- **[simple](./samples/simple/README.md)**: The runtime is integrated with most of the WAMR APP libraries, and a few WASM applications are provided for testing the WAMR APP API set. It uses **built-in libc** and executes apps in **interpreter** mode by default. -- **[file](./samples/file/README.md)**: Demonstrating the supported file interaction API of WASI. This sample can also demonstrate the SGX IPFS (Intel Protected File System), enabling an enclave to seal and unseal data at rest. -- **[littlevgl](./samples/littlevgl/README.md)**: Demonstrating the graphic user interface application usage on WAMR. The whole [LVGL](https://github.com/lvgl/lvgl) 2D user graphic library and the UI application are built into WASM application. It uses **WASI libc** and executes apps in **AOT mode** by default. -- **[gui](./samples/gui/README.md)**: Move the [LVGL](https://github.com/lvgl/lvgl) library into the runtime and define a WASM application interface by wrapping the littlevgl API. It uses **WASI libc** and executes apps in **interpreter** mode by default. -- **[multi-thread](./samples/multi-thread/)**: Demonstrating how to run wasm application which creates multiple threads to execute wasm functions concurrently, and uses mutex/cond by calling pthread related API's. -- **[spawn-thread](./samples/spawn-thread)**: Demonstrating how to execute wasm functions of the same wasm application concurrently, in threads created by host embedder or runtime, but not the wasm application itself. -- **[multi-module](./samples/multi-module)**: Demonstrating the [multiple modules as dependencies](./doc/multi_module.md) feature which implements the [load-time dynamic linking](https://webassembly.org/docs/dynamic-linking/). -- **[ref-types](./samples/ref-types)**: Demonstrating how to call wasm functions with argument of externref type introduced by [reference types proposal](https://github.com/WebAssembly/reference-types). -- **[wasm-c-api](./samples/wasm-c-api/README.md)**: Demonstrating how to run some samples from [wasm-c-api proposal](https://github.com/WebAssembly/wasm-c-api) and showing the supported API's. -- **[socket-api](./samples/socket-api/README.md)**: Demonstrating how to run wasm tcp server and tcp client applications, and how they communicate with each other. -- **[workload](./samples/workload/README.md)**: Demonstrating how to build and run some complex workloads, e.g. tensorflow-lite, XNNPACK, wasm-av1, meshoptimizer and bwa. -- **[sgx-ra](./samples/sgx-ra/README.md)**: Demonstrating how to execute Remote Attestation on SGX with [librats](https://github.com/inclavare-containers/librats), which enables mutual attestation with other runtimes or other entities that support librats to ensure that each is running within the TEE. - - -Project Technical Steering Committee -==================================== -The [WAMR PTSC Charter](./TSC_Charter.md) governs the operations of the project TSC. -The current TSC members: -- [lum1n0us](https://github.com/lum1n0us) - **Liang He**, -- [no1wudi](https://github.com/no1wudi) **Qi Huang**, -- [qinxk-inter](https://github.com/qinxk-inter) - **Xiaokang Qin**, -- [wei-tang](https://github.com/wei-tang) - **Wei Tang**, -- [wenyongh](https://github.com/wenyongh) - **Wenyong Huang**, -- [xujuntwt95329](https://github.com/xujuntwt95329) - **Jun Xu**, -- [xwang98](https://github.com/xwang98) - **Xin Wang**, (chair) - -License -======= -WAMR uses the same license as LLVM: the `Apache 2.0 license` with the LLVM -exception. See the LICENSE file for details. This license allows you to freely -use, modify, distribute and sell your own products based on WAMR. -Any contributions you make will be under the same license. - -# More resources - -Check out the [Wiki documents ](https://github.com/bytecodealliance/wasm-micro-runtime/wiki) for more resources: - -- [Community news and events](https://github.com/bytecodealliance/wasm-micro-runtime/wiki/Events) -- [Roadmap](https://github.com/bytecodealliance/wasm-micro-runtime/wiki/Roadmap) -- [WAMR TSC meetings](https://github.com/bytecodealliance/wasm-micro-runtime/wiki/TSC-meeting) -- Technical documents - diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-mgr/README.md b/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-mgr/README.md deleted file mode 100644 index d5e05881523..00000000000 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-mgr/README.md +++ /dev/null @@ -1,10 +0,0 @@ -WASM application management -======= - -## structure - - - - - - diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/wasm_memory.c b/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/wasm_memory.c deleted file mode 100644 index 49a9b08679c..00000000000 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/wasm_memory.c +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Copyright (C) 2019 Intel Corporation. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - */ - -#include "wasm_runtime_common.h" -#include "bh_platform.h" -#include "mem_alloc.h" - -typedef enum Memory_Mode { - MEMORY_MODE_UNKNOWN = 0, - MEMORY_MODE_POOL, - MEMORY_MODE_ALLOCATOR -} Memory_Mode; - -static Memory_Mode memory_mode = MEMORY_MODE_UNKNOWN; - -static mem_allocator_t pool_allocator = NULL; - -static void *(*malloc_func)(unsigned int size) = NULL; -static void *(*realloc_func)(void *ptr, unsigned int size) = NULL; -static void (*free_func)(void *ptr) = NULL; - -static unsigned int global_pool_size; - -static bool -wasm_memory_init_with_pool(void *mem, unsigned int bytes) -{ - mem_allocator_t _allocator = mem_allocator_create(mem, bytes); - - if (_allocator) { - memory_mode = MEMORY_MODE_POOL; - pool_allocator = _allocator; - global_pool_size = bytes; - return true; - } - LOG_ERROR("Init memory with pool (%p, %u) failed.\n", mem, bytes); - return false; -} - -static bool -wasm_memory_init_with_allocator(void *_malloc_func, void *_realloc_func, - void *_free_func) -{ - if (_malloc_func && _free_func && _malloc_func != _free_func) { - memory_mode = MEMORY_MODE_ALLOCATOR; - malloc_func = _malloc_func; - realloc_func = _realloc_func; - free_func = _free_func; - return true; - } - LOG_ERROR("Init memory with allocator (%p, %p, %p) failed.\n", _malloc_func, - _realloc_func, _free_func); - return false; -} - -bool -wasm_runtime_memory_init(mem_alloc_type_t mem_alloc_type, - const MemAllocOption *alloc_option) -{ - if (mem_alloc_type == Alloc_With_Pool) - return wasm_memory_init_with_pool(alloc_option->pool.heap_buf, - alloc_option->pool.heap_size); - else if (mem_alloc_type == Alloc_With_Allocator) - return wasm_memory_init_with_allocator( - alloc_option->allocator.malloc_func, - alloc_option->allocator.realloc_func, - alloc_option->allocator.free_func); - else if (mem_alloc_type == Alloc_With_System_Allocator) - return wasm_memory_init_with_allocator(os_malloc, os_realloc, os_free); - else - return false; -} - -void -wasm_runtime_memory_destroy() -{ - if (memory_mode == MEMORY_MODE_POOL) { -#if BH_ENABLE_GC_VERIFY == 0 - (void)mem_allocator_destroy(pool_allocator); -#else - int ret = mem_allocator_destroy(pool_allocator); - if (ret != 0) { - /* Memory leak detected */ - exit(-1); - } -#endif - } - memory_mode = MEMORY_MODE_UNKNOWN; -} - -unsigned -wasm_runtime_memory_pool_size() -{ - if (memory_mode == MEMORY_MODE_POOL) - return global_pool_size; - else - return UINT32_MAX; -} - -static inline void * -wasm_runtime_malloc_internal(unsigned int size) -{ - if (memory_mode == MEMORY_MODE_UNKNOWN) { - LOG_WARNING( - "wasm_runtime_malloc failed: memory hasn't been initialize.\n"); - return NULL; - } - else if (memory_mode == MEMORY_MODE_POOL) { - return mem_allocator_malloc(pool_allocator, size); - } - else { - return malloc_func(size); - } -} - -static inline void * -wasm_runtime_realloc_internal(void *ptr, unsigned int size) -{ - if (memory_mode == MEMORY_MODE_UNKNOWN) { - LOG_WARNING( - "wasm_runtime_realloc failed: memory hasn't been initialize.\n"); - return NULL; - } - else if (memory_mode == MEMORY_MODE_POOL) { - return mem_allocator_realloc(pool_allocator, ptr, size); - } - else { - if (realloc_func) - return realloc_func(ptr, size); - else - return NULL; - } -} - -static inline void -wasm_runtime_free_internal(void *ptr) -{ - if (!ptr) { - LOG_WARNING("warning: wasm_runtime_free with NULL pointer\n"); - return; - } - - if (memory_mode == MEMORY_MODE_UNKNOWN) { - LOG_WARNING("warning: wasm_runtime_free failed: " - "memory hasn't been initialize.\n"); - } - else if (memory_mode == MEMORY_MODE_POOL) { - mem_allocator_free(pool_allocator, ptr); - } - else { - free_func(ptr); - } -} - -void * -wasm_runtime_malloc(unsigned int size) -{ - if (size == 0) { - LOG_WARNING("warning: wasm_runtime_malloc with size zero\n"); - /* At lease alloc 1 byte to avoid malloc failed */ - size = 1; - } - - return wasm_runtime_malloc_internal(size); -} - -void * -wasm_runtime_realloc(void *ptr, unsigned int size) -{ - return wasm_runtime_realloc_internal(ptr, size); -} - -void -wasm_runtime_free(void *ptr) -{ - wasm_runtime_free_internal(ptr); -} - -bool -wasm_runtime_get_mem_alloc_info(mem_alloc_info_t *mem_alloc_info) -{ - if (memory_mode == MEMORY_MODE_POOL) { - return mem_allocator_get_alloc_info(pool_allocator, mem_alloc_info); - } - return false; -} diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/fe/jit_emit_function.c b/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/fe/jit_emit_function.c deleted file mode 100644 index 257615f0c7d..00000000000 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/fe/jit_emit_function.c +++ /dev/null @@ -1,540 +0,0 @@ -/* - * Copyright (C) 2019 Intel Corporation. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - */ - -#include "jit_emit_function.h" -#include "jit_emit_exception.h" -#include "../jit_frontend.h" -#include "../jit_codegen.h" -#include "../../interpreter/wasm_runtime.h" - -extern bool -jit_invoke_native(WASMExecEnv *exec_env, uint32 func_idx, - WASMInterpFrame *prev_frame); - -/* Prepare parameters for the function to call */ -static bool -pre_call(JitCompContext *cc, const WASMType *func_type) -{ - JitReg value; - uint32 i, outs_off; - /* Prepare parameters for the function to call */ - outs_off = - cc->total_frame_size + offsetof(WASMInterpFrame, lp) - + wasm_get_cell_num(func_type->types, func_type->param_count) * 4; - - for (i = 0; i < func_type->param_count; i++) { - switch (func_type->types[func_type->param_count - 1 - i]) { - case VALUE_TYPE_I32: -#if WASM_ENABLE_REF_TYPES != 0 - case VALUE_TYPE_EXTERNREF: - case VALUE_TYPE_FUNCREF: -#endif - POP_I32(value); - outs_off -= 4; - GEN_INSN(STI32, value, cc->fp_reg, NEW_CONST(I32, outs_off)); - break; - case VALUE_TYPE_I64: - POP_I64(value); - outs_off -= 8; - GEN_INSN(STI64, value, cc->fp_reg, NEW_CONST(I32, outs_off)); - break; - case VALUE_TYPE_F32: - POP_F32(value); - outs_off -= 4; - GEN_INSN(STF32, value, cc->fp_reg, NEW_CONST(I32, outs_off)); - break; - case VALUE_TYPE_F64: - POP_F64(value); - outs_off -= 8; - GEN_INSN(STF64, value, cc->fp_reg, NEW_CONST(I32, outs_off)); - break; - default: - bh_assert(0); - goto fail; - } - } - - /* Commit sp as the callee may use it to store the results */ - gen_commit_sp_ip(cc->jit_frame); - - return true; -fail: - return false; -} - -/* Push results */ -static bool -post_return(JitCompContext *cc, const WASMType *func_type, JitReg first_res) -{ - uint32 i, n; - JitReg value; - - n = cc->jit_frame->sp - cc->jit_frame->lp; - for (i = 0; i < func_type->result_count; i++) { - switch (func_type->types[func_type->param_count + i]) { - case VALUE_TYPE_I32: -#if WASM_ENABLE_REF_TYPES != 0 - case VALUE_TYPE_EXTERNREF: - case VALUE_TYPE_FUNCREF: -#endif - if (i == 0 && first_res) { - bh_assert(jit_reg_kind(first_res) == JIT_REG_KIND_I32); - value = first_res; - } - else { - value = jit_cc_new_reg_I32(cc); - GEN_INSN(LDI32, value, cc->fp_reg, - NEW_CONST(I32, offset_of_local(n))); - } - PUSH_I32(value); - n++; - break; - case VALUE_TYPE_I64: - if (i == 0 && first_res) { - bh_assert(jit_reg_kind(first_res) == JIT_REG_KIND_I64); - value = first_res; - } - else { - value = jit_cc_new_reg_I64(cc); - GEN_INSN(LDI64, value, cc->fp_reg, - NEW_CONST(I32, offset_of_local(n))); - } - PUSH_I64(value); - n += 2; - break; - case VALUE_TYPE_F32: - if (i == 0 && first_res) { - bh_assert(jit_reg_kind(first_res) == JIT_REG_KIND_F32); - value = first_res; - } - else { - value = jit_cc_new_reg_F32(cc); - GEN_INSN(LDF32, value, cc->fp_reg, - NEW_CONST(I32, offset_of_local(n))); - } - PUSH_F32(value); - n++; - break; - case VALUE_TYPE_F64: - if (i == 0 && first_res) { - bh_assert(jit_reg_kind(first_res) == JIT_REG_KIND_F64); - value = first_res; - } - else { - value = jit_cc_new_reg_F64(cc); - GEN_INSN(LDF64, value, cc->fp_reg, - NEW_CONST(I32, offset_of_local(n))); - } - PUSH_F64(value); - n += 2; - break; - default: - bh_assert(0); - goto fail; - } - } - - /* Update the committed_sp as the callee has updated the frame sp */ - cc->jit_frame->committed_sp = cc->jit_frame->sp; - - return true; -fail: - return false; -} - -bool -jit_compile_op_call(JitCompContext *cc, uint32 func_idx, bool tail_call) -{ - WASMModule *wasm_module = cc->cur_wasm_module; - WASMFunctionImport *func_import; - WASMFunction *func; - WASMType *func_type; - JitFrame *jit_frame = cc->jit_frame; - JitReg native_ret; - JitReg fast_jit_func_ptrs, jitted_code = 0; - uint32 jitted_func_idx; - - if (func_idx >= wasm_module->import_function_count) { - fast_jit_func_ptrs = get_fast_jit_func_ptrs_reg(jit_frame); - jitted_code = jit_cc_new_reg_ptr(cc); - /* jitted_code = func_ptrs[func_idx - import_function_count] */ - jitted_func_idx = func_idx - wasm_module->import_function_count; - GEN_INSN(LDPTR, jitted_code, fast_jit_func_ptrs, - NEW_CONST(I32, (uint32)sizeof(void *) * jitted_func_idx)); - } - - if (func_idx < wasm_module->import_function_count) { - func_import = &wasm_module->import_functions[func_idx].u.function; - func_type = func_import->func_type; - } - else { - func = wasm_module - ->functions[func_idx - wasm_module->import_function_count]; - func_type = func->func_type; - } - - if (!pre_call(cc, func_type)) { - goto fail; - } - - if (func_idx < wasm_module->import_function_count) { - JitReg arg_regs[3]; - - native_ret = jit_cc_new_reg_I32(cc); - arg_regs[0] = cc->exec_env_reg; - arg_regs[1] = NEW_CONST(I32, func_idx); - arg_regs[2] = cc->fp_reg; - - if (!jit_emit_callnative(cc, jit_invoke_native, native_ret, arg_regs, - 3)) { - return false; - } - /* Convert bool to uint32 */ - GEN_INSN(AND, native_ret, native_ret, NEW_CONST(I32, 0xFF)); - - /* Check whether there is exception thrown */ - GEN_INSN(CMP, cc->cmp_reg, native_ret, NEW_CONST(I32, 0)); - if (!jit_emit_exception(cc, JIT_EXCE_ALREADY_THROWN, JIT_OP_BEQ, - cc->cmp_reg, NULL)) { - return false; - } - - if (!post_return(cc, func_type, 0)) { - goto fail; - } - } - else { - JitReg res = 0; - - if (func_type->result_count > 0) { - switch (func_type->types[func_type->param_count]) { - case VALUE_TYPE_I32: -#if WASM_ENABLE_REF_TYPES != 0 - case VALUE_TYPE_EXTERNREF: - case VALUE_TYPE_FUNCREF: -#endif - res = jit_cc_new_reg_I32(cc); - break; - case VALUE_TYPE_I64: - res = jit_cc_new_reg_I64(cc); - break; - case VALUE_TYPE_F32: - res = jit_cc_new_reg_F32(cc); - break; - case VALUE_TYPE_F64: - res = jit_cc_new_reg_F64(cc); - break; - default: - bh_assert(0); - goto fail; - } - } - - GEN_INSN(CALLBC, res, 0, jitted_code); - - if (!post_return(cc, func_type, res)) { - goto fail; - } - } - - /* Clear part of memory regs and table regs as their values - may be changed in the function call */ - if (cc->cur_wasm_module->possible_memory_grow) - clear_memory_regs(jit_frame); - clear_table_regs(jit_frame); - - /* Ignore tail call currently */ - (void)tail_call; - return true; -fail: - return false; -} - -static JitReg -pack_argv(JitCompContext *cc) -{ - /* reuse the stack of the next frame */ - uint32 stack_base; - JitReg argv; - - stack_base = cc->total_frame_size + offsetof(WASMInterpFrame, lp); - argv = jit_cc_new_reg_ptr(cc); - GEN_INSN(ADD, argv, cc->fp_reg, NEW_CONST(PTR, stack_base)); - if (jit_get_last_error(cc)) { - return (JitReg)0; - } - return argv; -} - -static bool -unpack_argv(JitCompContext *cc, const WASMType *func_type, JitReg argv) -{ - uint32 i, offset_by_cell = 0; - JitReg value; - - /* push results in argv to stack */ - for (i = 0; i < func_type->result_count; i++) { - switch (func_type->types[func_type->param_count + i]) { - case VALUE_TYPE_I32: -#if WASM_ENABLE_REF_TYPES != 0 - case VALUE_TYPE_EXTERNREF: - case VALUE_TYPE_FUNCREF: -#endif - { - value = jit_cc_new_reg_I32(cc); - GEN_INSN(LDI32, value, argv, NEW_CONST(I32, offset_by_cell)); - PUSH_I32(value); - offset_by_cell += 4; - break; - } - case VALUE_TYPE_I64: - { - value = jit_cc_new_reg_I64(cc); - GEN_INSN(LDI64, value, argv, NEW_CONST(I32, offset_by_cell)); - PUSH_I64(value); - offset_by_cell += 8; - break; - } - case VALUE_TYPE_F32: - { - value = jit_cc_new_reg_F32(cc); - GEN_INSN(LDF32, value, argv, NEW_CONST(I32, offset_by_cell)); - PUSH_F32(value); - offset_by_cell += 4; - break; - } - case VALUE_TYPE_F64: - { - value = jit_cc_new_reg_F64(cc); - GEN_INSN(LDF64, value, argv, NEW_CONST(I32, offset_by_cell)); - PUSH_F64(value); - offset_by_cell += 8; - break; - } - default: - { - bh_assert(0); - goto fail; - } - } - } - - /* Update the committed_sp as the callee has updated the frame sp */ - cc->jit_frame->committed_sp = cc->jit_frame->sp; - - return true; -fail: - return false; -} - -bool -jit_compile_op_call_indirect(JitCompContext *cc, uint32 type_idx, - uint32 tbl_idx) -{ - JitReg elem_idx, native_ret, argv, arg_regs[6]; - WASMType *func_type; - - POP_I32(elem_idx); - - func_type = cc->cur_wasm_module->types[type_idx]; - if (!pre_call(cc, func_type)) { - goto fail; - } - - argv = pack_argv(cc); - if (!argv) { - goto fail; - } - native_ret = jit_cc_new_reg_I32(cc); - arg_regs[0] = cc->exec_env_reg; - arg_regs[1] = NEW_CONST(I32, tbl_idx); - arg_regs[2] = elem_idx; - arg_regs[3] = NEW_CONST(I32, type_idx); - arg_regs[4] = NEW_CONST(I32, func_type->param_cell_num); - arg_regs[5] = argv; - - if (!jit_emit_callnative(cc, jit_call_indirect, native_ret, arg_regs, 6)) { - return false; - } - /* Convert bool to uint32 */ - GEN_INSN(AND, native_ret, native_ret, NEW_CONST(I32, 0xFF)); - - /* Check whether there is exception thrown */ - GEN_INSN(CMP, cc->cmp_reg, native_ret, NEW_CONST(I32, 0)); - if (!jit_emit_exception(cc, JIT_EXCE_ALREADY_THROWN, JIT_OP_BEQ, - cc->cmp_reg, NULL)) { - return false; - } - - if (!unpack_argv(cc, func_type, argv)) { - goto fail; - } - - /* Clear part of memory regs and table regs as their values - may be changed in the function call */ - if (cc->cur_wasm_module->possible_memory_grow) - clear_memory_regs(cc->jit_frame); - clear_table_regs(cc->jit_frame); - return true; -fail: - return false; -} - -#if WASM_ENABLE_REF_TYPES != 0 -bool -jit_compile_op_ref_null(JitCompContext *cc, uint32 ref_type) -{ - PUSH_I32(NEW_CONST(I32, NULL_REF)); - (void)ref_type; - return true; -fail: - return false; -} - -bool -jit_compile_op_ref_is_null(JitCompContext *cc) -{ - JitReg ref, res; - - POP_I32(ref); - - GEN_INSN(CMP, cc->cmp_reg, ref, NEW_CONST(I32, NULL_REF)); - res = jit_cc_new_reg_I32(cc); - GEN_INSN(SELECTEQ, res, cc->cmp_reg, NEW_CONST(I32, 1), NEW_CONST(I32, 0)); - PUSH_I32(res); - - return true; -fail: - return false; -} - -bool -jit_compile_op_ref_func(JitCompContext *cc, uint32 func_idx) -{ - PUSH_I32(NEW_CONST(I32, func_idx)); - return true; -fail: - return false; -} -#endif - -#if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64) -bool -jit_emit_callnative(JitCompContext *cc, void *native_func, JitReg res, - JitReg *params, uint32 param_count) -{ - JitInsn *insn; - char *i64_arg_names[] = { "rdi", "rsi", "rdx", "rcx", "r8", "r9" }; - char *f32_arg_names[] = { "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" }; - char *f64_arg_names[] = { "xmm0_f64", "xmm1_f64", "xmm2_f64", - "xmm3_f64", "xmm4_f64", "xmm5_f64" }; - JitReg i64_arg_regs[6], f32_arg_regs[6], f64_arg_regs[6], res_hreg = 0; - JitReg eax_hreg = jit_codegen_get_hreg_by_name("eax"); - JitReg rax_hreg = jit_codegen_get_hreg_by_name("rax"); - JitReg xmm0_hreg = jit_codegen_get_hreg_by_name("xmm0"); - JitReg xmm0_f64_hreg = jit_codegen_get_hreg_by_name("xmm0_f64"); - uint32 i, i64_reg_idx, float_reg_idx; - - bh_assert(param_count <= 6); - - for (i = 0; i < 6; i++) { - i64_arg_regs[i] = jit_codegen_get_hreg_by_name(i64_arg_names[i]); - f32_arg_regs[i] = jit_codegen_get_hreg_by_name(f32_arg_names[i]); - f64_arg_regs[i] = jit_codegen_get_hreg_by_name(f64_arg_names[i]); - } - - i64_reg_idx = float_reg_idx = 0; - for (i = 0; i < param_count; i++) { - switch (jit_reg_kind(params[i])) { - case JIT_REG_KIND_I32: - GEN_INSN(I32TOI64, i64_arg_regs[i64_reg_idx++], params[i]); - break; - case JIT_REG_KIND_I64: - GEN_INSN(MOV, i64_arg_regs[i64_reg_idx++], params[i]); - break; - case JIT_REG_KIND_F32: - GEN_INSN(MOV, f32_arg_regs[float_reg_idx++], params[i]); - break; - case JIT_REG_KIND_F64: - GEN_INSN(MOV, f64_arg_regs[float_reg_idx++], params[i]); - break; - default: - bh_assert(0); - return false; - } - } - - if (res) { - switch (jit_reg_kind(res)) { - case JIT_REG_KIND_I32: - res_hreg = eax_hreg; - break; - case JIT_REG_KIND_I64: - res_hreg = rax_hreg; - break; - case JIT_REG_KIND_F32: - res_hreg = xmm0_hreg; - break; - case JIT_REG_KIND_F64: - res_hreg = xmm0_f64_hreg; - break; - default: - bh_assert(0); - return false; - } - } - - insn = GEN_INSN(CALLNATIVE, res_hreg, - NEW_CONST(PTR, (uintptr_t)native_func), param_count); - if (!insn) { - return false; - } - - i64_reg_idx = float_reg_idx = 0; - for (i = 0; i < param_count; i++) { - switch (jit_reg_kind(params[i])) { - case JIT_REG_KIND_I32: - case JIT_REG_KIND_I64: - *(jit_insn_opndv(insn, i + 2)) = i64_arg_regs[i64_reg_idx++]; - break; - case JIT_REG_KIND_F32: - *(jit_insn_opndv(insn, i + 2)) = f32_arg_regs[float_reg_idx++]; - break; - case JIT_REG_KIND_F64: - *(jit_insn_opndv(insn, i + 2)) = f64_arg_regs[float_reg_idx++]; - break; - default: - bh_assert(0); - return false; - } - } - - if (res) { - GEN_INSN(MOV, res, res_hreg); - } - - return true; -} -#else -bool -jit_emit_callnative(JitCompContext *cc, void *native_func, JitReg res, - JitReg *params, uint32 param_count) -{ - JitInsn *insn; - uint32 i; - - bh_assert(param_count <= 6); - - insn = GEN_INSN(CALLNATIVE, res, NEW_CONST(PTR, (uintptr_t)native_func), - param_count); - if (!insn) - return false; - - for (i = 0; i < param_count; i++) { - *(jit_insn_opndv(insn, i + 2)) = params[i]; - } - return true; -} -#endif diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/fe/jit_emit_memory.c b/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/fe/jit_emit_memory.c deleted file mode 100644 index 6daf5c0d8f6..00000000000 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/fe/jit_emit_memory.c +++ /dev/null @@ -1,782 +0,0 @@ -/* - * Copyright (C) 2019 Intel Corporation. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - */ - -#include "jit_emit_memory.h" -#include "jit_emit_exception.h" -#include "jit_emit_function.h" -#include "../jit_frontend.h" -#include "../jit_codegen.h" -#include "../../interpreter/wasm_runtime.h" - -#ifndef OS_ENABLE_HW_BOUND_CHECK -static JitReg -get_memory_boundary(JitCompContext *cc, uint32 mem_idx, uint32 bytes) -{ - JitReg memory_boundary; - - switch (bytes) { - case 1: - { - memory_boundary = - get_mem_bound_check_1byte_reg(cc->jit_frame, mem_idx); - break; - } - case 2: - { - memory_boundary = - get_mem_bound_check_2bytes_reg(cc->jit_frame, mem_idx); - break; - } - case 4: - { - memory_boundary = - get_mem_bound_check_4bytes_reg(cc->jit_frame, mem_idx); - break; - } - case 8: - { - memory_boundary = - get_mem_bound_check_8bytes_reg(cc->jit_frame, mem_idx); - break; - } - case 16: - { - memory_boundary = - get_mem_bound_check_16bytes_reg(cc->jit_frame, mem_idx); - break; - } - default: - { - bh_assert(0); - goto fail; - } - } - - return memory_boundary; -fail: - return 0; -} -#endif - -#if UINTPTR_MAX == UINT64_MAX -static JitReg -check_and_seek_on_64bit_platform(JitCompContext *cc, JitReg addr, JitReg offset, - JitReg memory_boundary) -{ - JitReg long_addr, offset1; - - /* long_addr = (int64_t)addr */ - long_addr = jit_cc_new_reg_I64(cc); - GEN_INSN(U32TOI64, long_addr, addr); - - /* offset1 = offset + long_addr */ - offset1 = jit_cc_new_reg_I64(cc); - GEN_INSN(ADD, offset1, offset, long_addr); - -#ifndef OS_ENABLE_HW_BOUND_CHECK - /* if (offset1 > memory_boundary) goto EXCEPTION */ - GEN_INSN(CMP, cc->cmp_reg, offset1, memory_boundary); - if (!jit_emit_exception(cc, JIT_EXCE_OUT_OF_BOUNDS_MEMORY_ACCESS, - JIT_OP_BGTU, cc->cmp_reg, NULL)) { - goto fail; - } -#endif - - return offset1; -#ifndef OS_ENABLE_HW_BOUND_CHECK -fail: - return 0; -#endif -} -#else -static JitReg -check_and_seek_on_32bit_platform(JitCompContext *cc, JitReg addr, JitReg offset, - JitReg memory_boundary) -{ - JitReg offset1; - - /* offset1 = offset + addr */ - offset1 = jit_cc_new_reg_I32(cc); - GEN_INSN(ADD, offset1, offset, addr); - - /* if (offset1 < addr) goto EXCEPTION */ - GEN_INSN(CMP, cc->cmp_reg, offset1, addr); - if (!jit_emit_exception(cc, JIT_EXCE_OUT_OF_BOUNDS_MEMORY_ACCESS, - JIT_OP_BLTU, cc->cmp_reg, NULL)) { - goto fail; - } - -#ifndef OS_ENABLE_HW_BOUND_CHECK - /* if (offset1 > memory_boundary) goto EXCEPTION */ - GEN_INSN(CMP, cc->cmp_reg, offset1, memory_boundary); - if (!jit_emit_exception(cc, JIT_EXCE_OUT_OF_BOUNDS_MEMORY_ACCESS, - JIT_OP_BGTU, cc->cmp_reg, NULL)) { - goto fail; - } -#endif - - return offset1; -fail: - return 0; -} -#endif - -static JitReg -check_and_seek(JitCompContext *cc, JitReg addr, uint32 offset, uint32 bytes) -{ - JitReg memory_boundary = 0, offset1; -#ifndef OS_ENABLE_HW_BOUND_CHECK - /* the default memory */ - uint32 mem_idx = 0; -#endif - -#ifndef OS_ENABLE_HW_BOUND_CHECK - /* ---------- check ---------- */ - /* 1. shortcut if the memory size is 0 */ - if (0 == cc->cur_wasm_module->memories[mem_idx].init_page_count) { - JitReg memory_inst, cur_mem_page_count; - - /* if (cur_mem_page_count == 0) goto EXCEPTION */ - memory_inst = get_memory_inst_reg(cc->jit_frame, mem_idx); - cur_mem_page_count = jit_cc_new_reg_I32(cc); - GEN_INSN(LDI32, cur_mem_page_count, memory_inst, - NEW_CONST(I32, offsetof(WASMMemoryInstance, cur_page_count))); - GEN_INSN(CMP, cc->cmp_reg, cur_mem_page_count, NEW_CONST(I32, 0)); - if (!jit_emit_exception(cc, JIT_EXCE_OUT_OF_BOUNDS_MEMORY_ACCESS, - JIT_OP_BEQ, cc->cmp_reg, NULL)) { - goto fail; - } - } - - /* 2. a complete boundary check */ - memory_boundary = get_memory_boundary(cc, mem_idx, bytes); - if (!memory_boundary) - goto fail; -#endif - -#if UINTPTR_MAX == UINT64_MAX - offset1 = check_and_seek_on_64bit_platform(cc, addr, NEW_CONST(I64, offset), - memory_boundary); - if (!offset1) - goto fail; -#else - offset1 = check_and_seek_on_32bit_platform(cc, addr, NEW_CONST(I32, offset), - memory_boundary); - if (!offset1) - goto fail; -#endif - - return offset1; -fail: - return 0; -} - -bool -jit_compile_op_i32_load(JitCompContext *cc, uint32 align, uint32 offset, - uint32 bytes, bool sign, bool atomic) -{ - JitReg addr, offset1, value, memory_data; - - POP_I32(addr); - - offset1 = check_and_seek(cc, addr, offset, bytes); - if (!offset1) { - goto fail; - } - - memory_data = get_memory_data_reg(cc->jit_frame, 0); - - value = jit_cc_new_reg_I32(cc); - switch (bytes) { - case 1: - { - if (sign) { - GEN_INSN(LDI8, value, memory_data, offset1); - } - else { - GEN_INSN(LDU8, value, memory_data, offset1); - } - break; - } - case 2: - { - if (sign) { - GEN_INSN(LDI16, value, memory_data, offset1); - } - else { - GEN_INSN(LDU16, value, memory_data, offset1); - } - break; - } - case 4: - { - if (sign) { - GEN_INSN(LDI32, value, memory_data, offset1); - } - else { - GEN_INSN(LDU32, value, memory_data, offset1); - } - break; - } - default: - { - bh_assert(0); - goto fail; - } - } - - PUSH_I32(value); - return true; -fail: - return false; -} - -bool -jit_compile_op_i64_load(JitCompContext *cc, uint32 align, uint32 offset, - uint32 bytes, bool sign, bool atomic) -{ - JitReg addr, offset1, value, memory_data; - - POP_I32(addr); - - offset1 = check_and_seek(cc, addr, offset, bytes); - if (!offset1) { - goto fail; - } - - memory_data = get_memory_data_reg(cc->jit_frame, 0); - - value = jit_cc_new_reg_I64(cc); - switch (bytes) { - case 1: - { - if (sign) { - GEN_INSN(LDI8, value, memory_data, offset1); - } - else { - GEN_INSN(LDU8, value, memory_data, offset1); - } - break; - } - case 2: - { - if (sign) { - GEN_INSN(LDI16, value, memory_data, offset1); - } - else { - GEN_INSN(LDU16, value, memory_data, offset1); - } - break; - } - case 4: - { - if (sign) { - GEN_INSN(LDI32, value, memory_data, offset1); - } - else { - GEN_INSN(LDU32, value, memory_data, offset1); - } - break; - } - case 8: - { - if (sign) { - GEN_INSN(LDI64, value, memory_data, offset1); - } - else { - GEN_INSN(LDU64, value, memory_data, offset1); - } - break; - } - default: - { - bh_assert(0); - goto fail; - } - } - - PUSH_I64(value); - return true; -fail: - return false; -} - -bool -jit_compile_op_f32_load(JitCompContext *cc, uint32 align, uint32 offset) -{ - JitReg addr, offset1, value, memory_data; - - POP_I32(addr); - - offset1 = check_and_seek(cc, addr, offset, 4); - if (!offset1) { - goto fail; - } - - memory_data = get_memory_data_reg(cc->jit_frame, 0); - - value = jit_cc_new_reg_F32(cc); - GEN_INSN(LDF32, value, memory_data, offset1); - - PUSH_F32(value); - return true; -fail: - return false; -} - -bool -jit_compile_op_f64_load(JitCompContext *cc, uint32 align, uint32 offset) -{ - JitReg addr, offset1, value, memory_data; - - POP_I32(addr); - - offset1 = check_and_seek(cc, addr, offset, 8); - if (!offset1) { - goto fail; - } - - memory_data = get_memory_data_reg(cc->jit_frame, 0); - - value = jit_cc_new_reg_F64(cc); - GEN_INSN(LDF64, value, memory_data, offset1); - - PUSH_F64(value); - return true; -fail: - return false; -} - -bool -jit_compile_op_i32_store(JitCompContext *cc, uint32 align, uint32 offset, - uint32 bytes, bool atomic) -{ - JitReg value, addr, offset1, memory_data; - - POP_I32(value); - POP_I32(addr); - - offset1 = check_and_seek(cc, addr, offset, bytes); - if (!offset1) { - goto fail; - } - - memory_data = get_memory_data_reg(cc->jit_frame, 0); - - switch (bytes) { - case 1: - { - GEN_INSN(STI8, value, memory_data, offset1); - break; - } - case 2: - { - GEN_INSN(STI16, value, memory_data, offset1); - break; - } - case 4: - { - GEN_INSN(STI32, value, memory_data, offset1); - break; - } - default: - { - bh_assert(0); - goto fail; - } - } - - return true; -fail: - return false; -} - -bool -jit_compile_op_i64_store(JitCompContext *cc, uint32 align, uint32 offset, - uint32 bytes, bool atomic) -{ - JitReg value, addr, offset1, memory_data; - - POP_I64(value); - POP_I32(addr); - - offset1 = check_and_seek(cc, addr, offset, bytes); - if (!offset1) { - goto fail; - } - - if (jit_reg_is_const(value) && bytes < 8) { - value = NEW_CONST(I32, (int32)jit_cc_get_const_I64(cc, value)); - } - - memory_data = get_memory_data_reg(cc->jit_frame, 0); - - switch (bytes) { - case 1: - { - GEN_INSN(STI8, value, memory_data, offset1); - break; - } - case 2: - { - GEN_INSN(STI16, value, memory_data, offset1); - break; - } - case 4: - { - GEN_INSN(STI32, value, memory_data, offset1); - break; - } - case 8: - { - GEN_INSN(STI64, value, memory_data, offset1); - break; - } - default: - { - bh_assert(0); - goto fail; - } - } - - return true; -fail: - return false; -} - -bool -jit_compile_op_f32_store(JitCompContext *cc, uint32 align, uint32 offset) -{ - JitReg value, addr, offset1, memory_data; - - POP_F32(value); - POP_I32(addr); - - offset1 = check_and_seek(cc, addr, offset, 4); - if (!offset1) { - goto fail; - } - - memory_data = get_memory_data_reg(cc->jit_frame, 0); - - GEN_INSN(STF32, value, memory_data, offset1); - - return true; -fail: - return false; -} - -bool -jit_compile_op_f64_store(JitCompContext *cc, uint32 align, uint32 offset) -{ - JitReg value, addr, offset1, memory_data; - - POP_F64(value); - POP_I32(addr); - - offset1 = check_and_seek(cc, addr, offset, 8); - if (!offset1) { - goto fail; - } - - memory_data = get_memory_data_reg(cc->jit_frame, 0); - - GEN_INSN(STF64, value, memory_data, offset1); - - return true; -fail: - return false; -} - -bool -jit_compile_op_memory_size(JitCompContext *cc, uint32 mem_idx) -{ - JitReg mem_inst, res; - - mem_inst = get_memory_inst_reg(cc->jit_frame, mem_idx); - - res = jit_cc_new_reg_I32(cc); - GEN_INSN(LDI32, res, mem_inst, - NEW_CONST(I32, offsetof(WASMMemoryInstance, cur_page_count))); - - PUSH_I32(res); - - return true; -fail: - return false; -} - -bool -jit_compile_op_memory_grow(JitCompContext *cc, uint32 mem_idx) -{ - JitReg memory_inst, grow_res, res; - JitReg prev_page_count, inc_page_count, args[2]; - - /* Get current page count */ - memory_inst = get_memory_inst_reg(cc->jit_frame, mem_idx); - prev_page_count = jit_cc_new_reg_I32(cc); - GEN_INSN(LDI32, prev_page_count, memory_inst, - NEW_CONST(I32, offsetof(WASMMemoryInstance, cur_page_count))); - - /* Call wasm_enlarge_memory */ - POP_I32(inc_page_count); - - grow_res = jit_cc_new_reg_I32(cc); - args[0] = get_module_inst_reg(cc->jit_frame); - args[1] = inc_page_count; - - if (!jit_emit_callnative(cc, wasm_enlarge_memory, grow_res, args, 2)) { - goto fail; - } - /* Convert bool to uint32 */ - GEN_INSN(AND, grow_res, grow_res, NEW_CONST(I32, 0xFF)); - - /* return different values according to memory.grow result */ - res = jit_cc_new_reg_I32(cc); - GEN_INSN(CMP, cc->cmp_reg, grow_res, NEW_CONST(I32, 0)); - GEN_INSN(SELECTNE, res, cc->cmp_reg, prev_page_count, - NEW_CONST(I32, (int32)-1)); - PUSH_I32(res); - - /* Ensure a refresh in next get memory related registers */ - clear_memory_regs(cc->jit_frame); - - return true; -fail: - return false; -} - -#if WASM_ENABLE_BULK_MEMORY != 0 -static int -wasm_init_memory(WASMModuleInstance *inst, uint32 mem_idx, uint32 seg_idx, - uint32 len, uint32 mem_offset, uint32 data_offset) -{ - WASMMemoryInstance *mem_inst; - WASMDataSeg *data_segment; - uint32 mem_size; - uint8 *mem_addr, *data_addr; - - /* if d + n > the length of mem.data */ - mem_inst = inst->memories[mem_idx]; - mem_size = mem_inst->cur_page_count * mem_inst->num_bytes_per_page; - if (mem_size < mem_offset || mem_size - mem_offset < len) - goto out_of_bounds; - - /* if s + n > the length of data.data */ - bh_assert(seg_idx < inst->module->data_seg_count); - data_segment = inst->module->data_segments[seg_idx]; - if (data_segment->data_length < data_offset - || data_segment->data_length - data_offset < len) - goto out_of_bounds; - - mem_addr = mem_inst->memory_data + mem_offset; - data_addr = data_segment->data + data_offset; - bh_memcpy_s(mem_addr, mem_size - mem_offset, data_addr, len); - - return 0; -out_of_bounds: - wasm_set_exception(inst, "out of bounds memory access"); - return -1; -} - -bool -jit_compile_op_memory_init(JitCompContext *cc, uint32 mem_idx, uint32 seg_idx) -{ - JitReg len, mem_offset, data_offset, res; - JitReg args[6] = { 0 }; - - POP_I32(len); - POP_I32(data_offset); - POP_I32(mem_offset); - - res = jit_cc_new_reg_I32(cc); - args[0] = get_module_inst_reg(cc->jit_frame); - args[1] = NEW_CONST(I32, mem_idx); - args[2] = NEW_CONST(I32, seg_idx); - args[3] = len; - args[4] = mem_offset; - args[5] = data_offset; - - if (!jit_emit_callnative(cc, wasm_init_memory, res, args, - sizeof(args) / sizeof(args[0]))) - goto fail; - - GEN_INSN(CMP, cc->cmp_reg, res, NEW_CONST(I32, 0)); - if (!jit_emit_exception(cc, JIT_EXCE_ALREADY_THROWN, JIT_OP_BLTS, - cc->cmp_reg, NULL)) - goto fail; - - return true; -fail: - return false; -} - -bool -jit_compile_op_data_drop(JitCompContext *cc, uint32 seg_idx) -{ - JitReg module = get_module_reg(cc->jit_frame); - JitReg data_segments = jit_cc_new_reg_ptr(cc); - JitReg data_segment = jit_cc_new_reg_ptr(cc); - - GEN_INSN(LDPTR, data_segments, module, - NEW_CONST(I32, offsetof(WASMModule, data_segments))); - GEN_INSN(LDPTR, data_segment, data_segments, - NEW_CONST(I32, seg_idx * sizeof(WASMDataSeg *))); - GEN_INSN(STI32, NEW_CONST(I32, 0), data_segment, - NEW_CONST(I32, offsetof(WASMDataSeg, data_length))); - - return true; -} - -static int -wasm_copy_memory(WASMModuleInstance *inst, uint32 src_mem_idx, - uint32 dst_mem_idx, uint32 len, uint32 src_offset, - uint32 dst_offset) -{ - WASMMemoryInstance *src_mem, *dst_mem; - uint32 src_mem_size, dst_mem_size; - uint8 *src_addr, *dst_addr; - - src_mem = inst->memories[src_mem_idx]; - dst_mem = inst->memories[dst_mem_idx]; - src_mem_size = src_mem->cur_page_count * src_mem->num_bytes_per_page; - dst_mem_size = dst_mem->cur_page_count * dst_mem->num_bytes_per_page; - - /* if s + n > the length of mem.data */ - if (src_mem_size < src_offset || src_mem_size - src_offset < len) - goto out_of_bounds; - - /* if d + n > the length of mem.data */ - if (dst_mem_size < dst_offset || dst_mem_size - dst_offset < len) - goto out_of_bounds; - - src_addr = src_mem->memory_data + src_offset; - dst_addr = dst_mem->memory_data + dst_offset; - /* allowing the destination and source to overlap */ - bh_memmove_s(dst_addr, dst_mem_size - dst_offset, src_addr, len); - - return 0; -out_of_bounds: - wasm_set_exception(inst, "out of bounds memory access"); - return -1; -} - -bool -jit_compile_op_memory_copy(JitCompContext *cc, uint32 src_mem_idx, - uint32 dst_mem_idx) -{ - JitReg len, src, dst, res; - JitReg args[6] = { 0 }; - - POP_I32(len); - POP_I32(src); - POP_I32(dst); - - res = jit_cc_new_reg_I32(cc); - args[0] = get_module_inst_reg(cc->jit_frame); - args[1] = NEW_CONST(I32, src_mem_idx); - args[2] = NEW_CONST(I32, dst_mem_idx); - args[3] = len; - args[4] = src; - args[5] = dst; - - if (!jit_emit_callnative(cc, wasm_copy_memory, res, args, - sizeof(args) / sizeof(args[0]))) - goto fail; - - GEN_INSN(CMP, cc->cmp_reg, res, NEW_CONST(I32, 0)); - if (!jit_emit_exception(cc, JIT_EXCE_ALREADY_THROWN, JIT_OP_BLTS, - cc->cmp_reg, NULL)) - goto fail; - - return true; -fail: - return false; -} - -static int -wasm_fill_memory(WASMModuleInstance *inst, uint32 mem_idx, uint32 len, - uint32 val, uint32 dst) -{ - WASMMemoryInstance *mem_inst; - uint32 mem_size; - uint8 *dst_addr; - - mem_inst = inst->memories[mem_idx]; - mem_size = mem_inst->cur_page_count * mem_inst->num_bytes_per_page; - - if (mem_size < dst || mem_size - dst < len) - goto out_of_bounds; - - dst_addr = mem_inst->memory_data + dst; - memset(dst_addr, val, len); - - return 0; -out_of_bounds: - wasm_set_exception(inst, "out of bounds memory access"); - return -1; -} - -bool -jit_compile_op_memory_fill(JitCompContext *cc, uint32 mem_idx) -{ - JitReg res, len, val, dst; - JitReg args[5] = { 0 }; - - POP_I32(len); - POP_I32(val); - POP_I32(dst); - - res = jit_cc_new_reg_I32(cc); - args[0] = get_module_inst_reg(cc->jit_frame); - args[1] = NEW_CONST(I32, mem_idx); - args[2] = len; - args[3] = val; - args[4] = dst; - - if (!jit_emit_callnative(cc, wasm_fill_memory, res, args, - sizeof(args) / sizeof(args[0]))) - goto fail; - - GEN_INSN(CMP, cc->cmp_reg, res, NEW_CONST(I32, 0)); - if (!jit_emit_exception(cc, JIT_EXCE_ALREADY_THROWN, JIT_OP_BLTS, - cc->cmp_reg, NULL)) - goto fail; - - return true; -fail: - return false; -} -#endif - -#if WASM_ENABLE_SHARED_MEMORY != 0 -bool -jit_compile_op_atomic_rmw(JitCompContext *cc, uint8 atomic_op, uint8 op_type, - uint32 align, uint32 offset, uint32 bytes) -{ - return false; -} - -bool -jit_compile_op_atomic_cmpxchg(JitCompContext *cc, uint8 op_type, uint32 align, - uint32 offset, uint32 bytes) -{ - return false; -} - -bool -jit_compile_op_atomic_wait(JitCompContext *cc, uint8 op_type, uint32 align, - uint32 offset, uint32 bytes) -{ - return false; -} - -bool -jit_compiler_op_atomic_notify(JitCompContext *cc, uint32 align, uint32 offset, - uint32 bytes) -{ - return false; -} -#endif diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/jit_compiler.c b/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/jit_compiler.c deleted file mode 100644 index c10a409949b..00000000000 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/jit_compiler.c +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright (C) 2021 Intel Corporation. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - */ - -#include "jit_compiler.h" -#include "jit_ir.h" -#include "jit_codegen.h" -#include "jit_codecache.h" -#include "../interpreter/wasm.h" - -typedef struct JitCompilerPass { - /* Name of the pass. */ - const char *name; - /* The entry of the compiler pass. */ - bool (*run)(JitCompContext *cc); -} JitCompilerPass; - -/* clang-format off */ -static JitCompilerPass compiler_passes[] = { - { NULL, NULL }, -#define REG_PASS(name) { #name, jit_pass_##name } - REG_PASS(dump), - REG_PASS(update_cfg), - REG_PASS(frontend), - REG_PASS(lower_cg), - REG_PASS(regalloc), - REG_PASS(codegen), - REG_PASS(register_jitted_code) -#undef REG_PASS -}; - -/* Number of compiler passes. */ -#define COMPILER_PASS_NUM (sizeof(compiler_passes) / sizeof(compiler_passes[0])) - -#if WASM_ENABLE_FAST_JIT_DUMP == 0 -static const uint8 compiler_passes_without_dump[] = { - 3, 4, 5, 6, 7, 0 -}; -#else -static const uint8 compiler_passes_with_dump[] = { - 3, 2, 1, 4, 1, 5, 1, 6, 1, 7, 0 -}; -#endif - -/* The exported global data of JIT compiler. */ -static JitGlobals jit_globals = { -#if WASM_ENABLE_FAST_JIT_DUMP == 0 - .passes = compiler_passes_without_dump, -#else - .passes = compiler_passes_with_dump, -#endif - .return_to_interp_from_jitted = NULL -}; -/* clang-format on */ - -static bool -apply_compiler_passes(JitCompContext *cc) -{ - const uint8 *p = jit_globals.passes; - - for (; *p; p++) { - /* Set the pass NO. */ - cc->cur_pass_no = p - jit_globals.passes; - bh_assert(*p < COMPILER_PASS_NUM); - - if (!compiler_passes[*p].run(cc) || jit_get_last_error(cc)) { - LOG_VERBOSE("JIT: compilation failed at pass[%td] = %s\n", - p - jit_globals.passes, compiler_passes[*p].name); - return false; - } - } - - return true; -} - -bool -jit_compiler_init(const JitCompOptions *options) -{ - uint32 code_cache_size = options->code_cache_size > 0 - ? options->code_cache_size - : FAST_JIT_DEFAULT_CODE_CACHE_SIZE; - - LOG_VERBOSE("JIT: compiler init with code cache size: %u\n", - code_cache_size); - - if (!jit_code_cache_init(code_cache_size)) - return false; - - if (!jit_codegen_init()) - goto fail1; - - return true; - -fail1: - jit_code_cache_destroy(); - return false; -} - -void -jit_compiler_destroy() -{ - jit_codegen_destroy(); - - jit_code_cache_destroy(); -} - -JitGlobals * -jit_compiler_get_jit_globals() -{ - return &jit_globals; -} - -const char * -jit_compiler_get_pass_name(unsigned i) -{ - return i < COMPILER_PASS_NUM ? compiler_passes[i].name : NULL; -} - -bool -jit_compiler_compile(WASMModule *module, uint32 func_idx) -{ - JitCompContext *cc; - char *last_error; - bool ret = true; - - /* Initialize compilation context. */ - if (!(cc = jit_calloc(sizeof(*cc)))) - return false; - - if (!jit_cc_init(cc, 64)) { - jit_free(cc); - return false; - } - - cc->cur_wasm_module = module; - cc->cur_wasm_func = - module->functions[func_idx - module->import_function_count]; - cc->cur_wasm_func_idx = func_idx; - cc->mem_space_unchanged = (!cc->cur_wasm_func->has_op_memory_grow - && !cc->cur_wasm_func->has_op_func_call) - || (!module->possible_memory_grow); - - /* Apply compiler passes. */ - if (!apply_compiler_passes(cc) || jit_get_last_error(cc)) { - last_error = jit_get_last_error(cc); - os_printf("fast jit compilation failed: %s\n", - last_error ? last_error : "unknown error"); - ret = false; - } - - /* Delete the compilation context. */ - jit_cc_delete(cc); - - return ret; -} - -bool -jit_compiler_compile_all(WASMModule *module) -{ - uint32 i; - - for (i = 0; i < module->function_count; i++) { - if (!jit_compiler_compile(module, module->import_function_count + i)) { - return false; - } - } - - return true; -} - -int -jit_interp_switch_to_jitted(void *exec_env, JitInterpSwitchInfo *info, void *pc) -{ - return jit_codegen_interp_jitted_glue(exec_env, info, pc); -} diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/interpreter/wasm_runtime.h b/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/interpreter/wasm_runtime.h deleted file mode 100644 index 4cdbf5badc0..00000000000 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/interpreter/wasm_runtime.h +++ /dev/null @@ -1,502 +0,0 @@ -/* - * Copyright (C) 2019 Intel Corporation. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - */ - -#ifndef _WASM_RUNTIME_H -#define _WASM_RUNTIME_H - -#include "wasm.h" -#include "bh_hashmap.h" -#include "../common/wasm_runtime_common.h" -#include "../common/wasm_exec_env.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct WASMModuleInstance WASMModuleInstance; -typedef struct WASMFunctionInstance WASMFunctionInstance; -typedef struct WASMMemoryInstance WASMMemoryInstance; -typedef struct WASMTableInstance WASMTableInstance; -typedef struct WASMGlobalInstance WASMGlobalInstance; - -struct WASMMemoryInstance { - /* Module type */ - uint32 module_type; - /* Shared memory flag */ - bool is_shared; - - /* Number bytes per page */ - uint32 num_bytes_per_page; - /* Current page count */ - uint32 cur_page_count; - /* Maximum page count */ - uint32 max_page_count; - /* Memory data size */ - uint32 memory_data_size; - - /** - * Memory data begin address, Note: - * the app-heap might be inserted in to the linear memory, - * when memory is re-allocated, the heap data and memory data - * must be copied to new memory also - */ - uint8 *memory_data; - /* Memory data end address */ - uint8 *memory_data_end; - - /* Heap data base address */ - uint8 *heap_data; - /* Heap data end address */ - uint8 *heap_data_end; - /* The heap created */ - void *heap_handle; - -#if WASM_ENABLE_SHARED_MEMORY != 0 - /* mutex lock for the memory, used in atomic operation */ - korp_mutex mem_lock; -#endif - -#if WASM_ENABLE_FAST_JIT != 0 -#if UINTPTR_MAX == UINT64_MAX - uint64 mem_bound_check_1byte; - uint64 mem_bound_check_2bytes; - uint64 mem_bound_check_4bytes; - uint64 mem_bound_check_8bytes; - uint64 mem_bound_check_16bytes; -#else - uint32 mem_bound_check_1byte; - uint32 mem_bound_check_2bytes; - uint32 mem_bound_check_4bytes; - uint32 mem_bound_check_8bytes; - uint32 mem_bound_check_16bytes; -#endif -#endif -}; - -struct WASMTableInstance { - /* The element type, VALUE_TYPE_FUNCREF/EXTERNREF currently */ - uint8 elem_type; - /* Current size */ - uint32 cur_size; - /* Maximum size */ - uint32 max_size; -#if WASM_ENABLE_MULTI_MODULE != 0 - /* just for import, keep the reference here */ - WASMTableInstance *table_inst_linked; -#endif - /* Base address */ - uint8 base_addr[1]; -}; - -struct WASMGlobalInstance { - /* value type, VALUE_TYPE_I32/I64/F32/F64 */ - uint8 type; - /* mutable or constant */ - bool is_mutable; - /* data offset to base_addr of WASMMemoryInstance */ - uint32 data_offset; - /* initial value */ - WASMValue initial_value; -#if WASM_ENABLE_MULTI_MODULE != 0 - /* just for import, keep the reference here */ - WASMModuleInstance *import_module_inst; - WASMGlobalInstance *import_global_inst; -#endif -}; - -struct WASMFunctionInstance { - /* whether it is import function or WASM function */ - bool is_import_func; - /* parameter count */ - uint16 param_count; - /* local variable count, 0 for import function */ - uint16 local_count; - /* cell num of parameters */ - uint16 param_cell_num; - /* cell num of return type */ - uint16 ret_cell_num; - /* cell num of local variables, 0 for import function */ - uint16 local_cell_num; -#if WASM_ENABLE_FAST_INTERP != 0 - /* cell num of consts */ - uint16 const_cell_num; -#endif - uint16 *local_offsets; - /* parameter types */ - uint8 *param_types; - /* local types, NULL for import function */ - uint8 *local_types; - union { - WASMFunctionImport *func_import; - WASMFunction *func; - } u; -#if WASM_ENABLE_MULTI_MODULE != 0 - WASMModuleInstance *import_module_inst; - WASMFunctionInstance *import_func_inst; -#endif -#if WASM_ENABLE_PERF_PROFILING != 0 - /* total execution time */ - uint64 total_exec_time; - /* total execution count */ - uint32 total_exec_cnt; -#endif -}; - -typedef struct WASMExportFuncInstance { - char *name; - WASMFunctionInstance *function; -} WASMExportFuncInstance; - -#if WASM_ENABLE_MULTI_MODULE != 0 -typedef struct WASMExportGlobInstance { - char *name; - WASMGlobalInstance *global; -} WASMExportGlobInstance; - -typedef struct WASMExportTabInstance { - char *name; - WASMTableInstance *table; -} WASMExportTabInstance; - -typedef struct WASMExportMemInstance { - char *name; - WASMMemoryInstance *memory; -} WASMExportMemInstance; -#endif - -struct WASMModuleInstance { - /* Module instance type, for module instance loaded from - WASM bytecode binary, this field is Wasm_Module_Bytecode; - for module instance loaded from AOT file, this field is - Wasm_Module_AoT, and this structure should be treated as - AOTModuleInstance structure. */ - uint32 module_type; - - uint32 memory_count; - uint32 table_count; - uint32 global_count; - uint32 function_count; - - uint32 export_func_count; -#if WASM_ENABLE_MULTI_MODULE != 0 - uint32 export_glob_count; - uint32 export_mem_count; - uint32 export_tab_count; -#endif - - /* Array of function pointers to import functions */ - void **import_func_ptrs; -#if WASM_ENABLE_FAST_JIT != 0 - /* point to JITed functions */ - void **fast_jit_func_ptrs; - uint32 *func_type_indexes; -#endif - - WASMMemoryInstance **memories; - WASMTableInstance **tables; - WASMGlobalInstance *globals; - WASMFunctionInstance *functions; - - WASMExportFuncInstance *export_functions; -#if WASM_ENABLE_MULTI_MODULE != 0 - WASMExportGlobInstance *export_globals; - WASMExportMemInstance *export_memories; - WASMExportTabInstance *export_tables; -#endif - - WASMMemoryInstance *default_memory; - WASMTableInstance *default_table; - /* Global data of global instances */ - uint8 *global_data; - - WASMFunctionInstance *start_function; - WASMFunctionInstance *malloc_function; - WASMFunctionInstance *free_function; - WASMFunctionInstance *retain_function; - - WASMModule *module; - -#if WASM_ENABLE_LIBC_WASI != 0 - WASIContext *wasi_ctx; -#endif - - WASMExecEnv *exec_env_singleton; - - /* Default WASM stack size of threads of this Module instance. */ - uint32 default_wasm_stack_size; - - /* The exception buffer of wasm interpreter for current thread. */ - char cur_exception[128]; - -#if WASM_ENABLE_DUMP_CALL_STACK != 0 - Vector *frames; -#endif - - /* The custom data that can be set/get by - * wasm_set_custom_data/wasm_get_custom_data */ - void *custom_data; - -#if WASM_ENABLE_MULTI_MODULE != 0 - /* TODO: add mutex for mutli-threads? */ - bh_list sub_module_inst_list_head; - bh_list *sub_module_inst_list; -#endif - -#if WASM_ENABLE_MEMORY_PROFILING != 0 - uint32 max_aux_stack_used; -#endif -}; - -struct WASMInterpFrame; -typedef struct WASMInterpFrame WASMRuntimeFrame; - -#if WASM_ENABLE_MULTI_MODULE != 0 -typedef struct WASMSubModInstNode { - bh_list_link l; - /* point to a string pool */ - const char *module_name; - WASMModuleInstance *module_inst; -} WASMSubModInstNode; -#endif - -/** - * Return the code block of a function. - * - * @param func the WASM function instance - * - * @return the code block of the function - */ -static inline uint8 * -wasm_get_func_code(WASMFunctionInstance *func) -{ -#if WASM_ENABLE_FAST_INTERP == 0 - return func->is_import_func ? NULL : func->u.func->code; -#else - return func->is_import_func ? NULL : func->u.func->code_compiled; -#endif -} - -/** - * Return the code block end of a function. - * - * @param func the WASM function instance - * - * @return the code block end of the function - */ -static inline uint8 * -wasm_get_func_code_end(WASMFunctionInstance *func) -{ -#if WASM_ENABLE_FAST_INTERP == 0 - return func->is_import_func ? NULL - : func->u.func->code + func->u.func->code_size; -#else - return func->is_import_func - ? NULL - : func->u.func->code_compiled + func->u.func->code_compiled_size; -#endif -} - -WASMModule * -wasm_load(uint8 *buf, uint32 size, char *error_buf, uint32 error_buf_size); - -WASMModule * -wasm_load_from_sections(WASMSection *section_list, char *error_buf, - uint32 error_buf_size); - -void -wasm_unload(WASMModule *module); - -WASMModuleInstance * -wasm_instantiate(WASMModule *module, bool is_sub_inst, uint32 stack_size, - uint32 heap_size, char *error_buf, uint32 error_buf_size); - -void -wasm_dump_perf_profiling(const WASMModuleInstance *module_inst); - -void -wasm_deinstantiate(WASMModuleInstance *module_inst, bool is_sub_inst); - -WASMFunctionInstance * -wasm_lookup_function(const WASMModuleInstance *module_inst, const char *name, - const char *signature); - -#if WASM_ENABLE_MULTI_MODULE != 0 -WASMGlobalInstance * -wasm_lookup_global(const WASMModuleInstance *module_inst, const char *name); - -WASMMemoryInstance * -wasm_lookup_memory(const WASMModuleInstance *module_inst, const char *name); - -WASMTableInstance * -wasm_lookup_table(const WASMModuleInstance *module_inst, const char *name); -#endif - -bool -wasm_call_function(WASMExecEnv *exec_env, WASMFunctionInstance *function, - unsigned argc, uint32 argv[]); - -bool -wasm_create_exec_env_and_call_function(WASMModuleInstance *module_inst, - WASMFunctionInstance *function, - unsigned argc, uint32 argv[]); - -bool -wasm_create_exec_env_singleton(WASMModuleInstance *module_inst); - -void -wasm_set_exception(WASMModuleInstance *module, const char *exception); - -const char * -wasm_get_exception(WASMModuleInstance *module); - -uint32 -wasm_module_malloc(WASMModuleInstance *module_inst, uint32 size, - void **p_native_addr); - -uint32 -wasm_module_realloc(WASMModuleInstance *module_inst, uint32 ptr, uint32 size, - void **p_native_addr); - -void -wasm_module_free(WASMModuleInstance *module_inst, uint32 ptr); - -uint32 -wasm_module_dup_data(WASMModuleInstance *module_inst, const char *src, - uint32 size); - -bool -wasm_validate_app_addr(WASMModuleInstance *module_inst, uint32 app_offset, - uint32 size); - -bool -wasm_validate_app_str_addr(WASMModuleInstance *module_inst, uint32 app_offset); - -bool -wasm_validate_native_addr(WASMModuleInstance *module_inst, void *native_ptr, - uint32 size); - -void * -wasm_addr_app_to_native(WASMModuleInstance *module_inst, uint32 app_offset); - -uint32 -wasm_addr_native_to_app(WASMModuleInstance *module_inst, void *native_ptr); - -bool -wasm_get_app_addr_range(WASMModuleInstance *module_inst, uint32 app_offset, - uint32 *p_app_start_offset, uint32 *p_app_end_offset); - -bool -wasm_get_native_addr_range(WASMModuleInstance *module_inst, uint8 *native_ptr, - uint8 **p_native_start_addr, - uint8 **p_native_end_addr); - -bool -wasm_enlarge_memory(WASMModuleInstance *module, uint32 inc_page_count); - -bool -wasm_call_indirect(WASMExecEnv *exec_env, uint32 tbl_idx, uint32 elem_idx, - uint32 argc, uint32 argv[]); - -#if WASM_ENABLE_FAST_JIT != 0 -bool -jit_call_indirect(WASMExecEnv *exec_env, uint32 tbl_idx, uint32 elem_idx, - uint32 type_idx, uint32 argc, uint32 argv[]); -#endif - -#if WASM_ENABLE_THREAD_MGR != 0 -bool -wasm_set_aux_stack(WASMExecEnv *exec_env, uint32 start_offset, uint32 size); - -bool -wasm_get_aux_stack(WASMExecEnv *exec_env, uint32 *start_offset, uint32 *size); -#endif - -#ifdef OS_ENABLE_HW_BOUND_CHECK -#ifndef BH_PLATFORM_WINDOWS -void -wasm_signal_handler(WASMSignalInfo *sig_info); -#else -LONG -wasm_exception_handler(WASMSignalInfo *sig_info); -#endif -#endif - -void -wasm_get_module_mem_consumption(const WASMModule *module, - WASMModuleMemConsumption *mem_conspn); - -void -wasm_get_module_inst_mem_consumption(const WASMModuleInstance *module, - WASMModuleInstMemConsumption *mem_conspn); - -#if WASM_ENABLE_REF_TYPES != 0 -static inline bool -wasm_elem_is_active(uint32 mode) -{ - return (mode & 0x1) == 0x0; -} - -static inline bool -wasm_elem_is_passive(uint32 mode) -{ - return (mode & 0x1) == 0x1; -} - -static inline bool -wasm_elem_is_declarative(uint32 mode) -{ - return (mode & 0x3) == 0x3; -} - -bool -wasm_enlarge_table(WASMModuleInstance *module_inst, uint32 table_idx, - uint32 inc_entries, uint32 init_val); -#endif /* WASM_ENABLE_REF_TYPES != 0 */ - -static inline WASMTableInstance * -wasm_get_table_inst(const WASMModuleInstance *module_inst, const uint32 tbl_idx) -{ - /* careful, it might be a table in another module */ - WASMTableInstance *tbl_inst = module_inst->tables[tbl_idx]; -#if WASM_ENABLE_MULTI_MODULE != 0 - if (tbl_inst->table_inst_linked) { - tbl_inst = tbl_inst->table_inst_linked; - } -#endif - bh_assert(tbl_inst); - return tbl_inst; -} - -#if WASM_ENABLE_DUMP_CALL_STACK != 0 -bool -wasm_interp_create_call_stack(struct WASMExecEnv *exec_env); - -/** - * @brief Dump wasm call stack or get the size - * - * @param exec_env the execution environment - * @param print whether to print to stdout or not - * @param buf buffer to store the dumped content - * @param len length of the buffer - * - * @return when print is true, return the bytes printed out to stdout; when - * print is false and buf is NULL, return the size required to store the - * callstack content; when print is false and buf is not NULL, return the size - * dumped to the buffer, 0 means error and data in buf may be invalid - */ -uint32 -wasm_interp_dump_call_stack(struct WASMExecEnv *exec_env, bool print, char *buf, - uint32 len); -#endif - -const uint8 * -wasm_loader_get_custom_section(WASMModule *module, const char *name, - uint32 *len); - -#ifdef __cplusplus -} -#endif - -#endif /* end of _WASM_RUNTIME_H */ diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/lib-rats/lib_rats_wrapper.c b/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/lib-rats/lib_rats_wrapper.c deleted file mode 100644 index e89337fd488..00000000000 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/lib-rats/lib_rats_wrapper.c +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2022 Intel Corporation - * Copyright (c) 2020-2021 Alibaba Cloud - * - * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - */ - -#include -#include -#include - -#include "wasm_export.h" -#include "bh_common.h" - -static uint32 -librats_collect_wrapper(wasm_exec_env_t exec_env, const uint8_t *hash) -{ - char *json = NULL; - char *str_ret; - uint32 len; - uint32 str_ret_offset = 0; - wasm_module_inst_t module_inst = get_module_inst(exec_env); - int code = librats_collect_evidence_to_json(hash, &json); - if (code != 0) { - return str_ret_offset; - } - if (json) { - len = (uint32)strlen(json) + 1; - - str_ret_offset = module_malloc(len, (void **)&str_ret); - if (str_ret_offset) { - bh_memcpy_s(str_ret, len, json, len); - } - } - return str_ret_offset; -} - -static int -librats_verify_wrapper(wasm_exec_env_t exec_env, const char *evidence_json, - const uint8_t *hash) -{ - return librats_verify_evidence_from_json(evidence_json, hash); -} - -/* clang-format off */ -#define REG_NATIVE_FUNC(func_name, signature) \ - { #func_name, func_name##_wrapper, signature, NULL } -/* clang-format on */ - -static NativeSymbol native_symbols_lib_rats[] = { - REG_NATIVE_FUNC(librats_collect, "($)i"), - REG_NATIVE_FUNC(librats_verify, "($$)i") -}; - -uint32_t -get_lib_rats_export_apis(NativeSymbol **p_lib_rats_apis) -{ - *p_lib_rats_apis = native_symbols_lib_rats; - return sizeof(native_symbols_lib_rats) / sizeof(NativeSymbol); -} \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/lib-rats/lib_rats_wrapper.h b/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/lib-rats/lib_rats_wrapper.h deleted file mode 100644 index 348b3b00c85..00000000000 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/lib-rats/lib_rats_wrapper.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright (c) 2022 Intel Corporation - * Copyright (c) 2020-2021 Alibaba Cloud - * - * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - */ - -#ifndef _RATS_WAMR_API_H -#define _RATS_WAMR_API_H - -#include - -char * -librats_collect(const uint8_t *hash); -int -librats_verify(const char *json_string, const uint8_t *hash); - -#endif \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/numeric_limits.h b/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/numeric_limits.h deleted file mode 100644 index 233f3733b6a..00000000000 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/numeric_limits.h +++ /dev/null @@ -1,42 +0,0 @@ -// Part of the Wasmtime Project, under the Apache License v2.0 with LLVM -// Exceptions. See -// https://github.com/bytecodealliance/wasmtime/blob/main/LICENSE for license -// information. -// -// Significant parts of this file are derived from cloudabi-utils. See -// https://github.com/bytecodealliance/wasmtime/blob/main/lib/wasi/sandboxed-system-primitives/src/LICENSE -// for license information. -// -// The upstream file contains the following copyright notice: -// -// Copyright (c) 2015 Nuxi, https://nuxi.nl/ - -#ifndef COMMON_LIMITS_H -#define COMMON_LIMITS_H - -#define NUMERIC_MIN(t) \ - _Generic((t)0, char \ - : CHAR_MIN, signed char \ - : SCHAR_MIN, unsigned char : 0, short \ - : SHRT_MIN, unsigned short : 0, int \ - : INT_MIN, unsigned int : 0, long \ - : LONG_MIN, unsigned long : 0, long long \ - : LLONG_MIN, unsigned long long : 0, default \ - : (void)0) - -#define NUMERIC_MAX(t) \ - _Generic((t)0, char \ - : CHAR_MAX, signed char \ - : SCHAR_MAX, unsigned char \ - : UCHAR_MAX, short \ - : SHRT_MAX, unsigned short \ - : USHRT_MAX, int \ - : INT_MAX, unsigned int \ - : UINT_MAX, long \ - : LONG_MAX, unsigned long \ - : ULONG_MAX, long long \ - : LLONG_MAX, unsigned long long \ - : ULLONG_MAX, default \ - : (void)0) - -#endif diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/wasi-nn/.dockerignore b/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/wasi-nn/.dockerignore deleted file mode 100644 index 0e2be498d55..00000000000 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/wasi-nn/.dockerignore +++ /dev/null @@ -1 +0,0 @@ -**/Dockerfile diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/wasi-nn/README.md b/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/wasi-nn/README.md deleted file mode 100644 index 22ef13db022..00000000000 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/wasi-nn/README.md +++ /dev/null @@ -1,43 +0,0 @@ -# WASI-NN - -## How to use - -Enable WASI-NN in the WAMR by spefiying it in the cmake building configuration as follows, - -``` -set (WAMR_BUILD_WASI_NN 1) -``` - -The definition of the functions provided by WASI-NN is in the header file `core/iwasm/libraries/wasi-nn/wasi_nn.h`. - -By only including this file in your WASM application you will bind WASI-NN into your module. - -## Tests - -To run the tests we assume that the current directory is the root of the repository. - - -1. Build the docker image, - -``` -docker build -t wasi-nn -f core/iwasm/libraries/wasi-nn/test/Dockerfile . -``` - -2. Run the container - -``` -docker run wasi-nn -``` - -If all the tests have run properly you will the the following message in the terminal, - -``` -Tests: passed! -``` - -## What is missing - -* Only 1 model at a time is supported. - * `graph` and `graph-execution-context` are ignored. -* Only `tensorflow` (lite) is supported. -* Only `cpu` is supported. diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/wasi-nn/logger.h b/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/wasi-nn/logger.h deleted file mode 100644 index 25588eb6b90..00000000000 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/wasi-nn/logger.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2019 Intel Corporation. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - */ - -#ifndef WASI_NN_LOGGER_H -#define WASI_NN_LOGGER_H - -#include -#include - -#define __FILENAME__ \ - (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) - -/* Disable a level by removing the define */ -#define ENABLE_ERR_LOG -#define ENABLE_WARN_LOG -#define ENABLE_DBG_LOG -#define ENABLE_INFO_LOG - -// Definition of the levels -#ifdef ENABLE_ERR_LOG -#define NN_ERR_PRINTF(fmt, ...) \ - printf("[%s:%d] " fmt, __FILENAME__, __LINE__, ##__VA_ARGS__); \ - printf("\n"); \ - fflush(stdout) -#else -#define NN_ERR_PRINTF(fmt, ...) -#endif -#ifdef ENABLE_WARN_LOG -#define NN_WARN_PRINTF(fmt, ...) \ - printf("[%s:%d] " fmt, __FILENAME__, __LINE__, ##__VA_ARGS__); \ - printf("\n"); \ - fflush(stdout) -#else -#define NN_WARN_PRINTF(fmt, ...) -#endif -#ifdef ENABLE_DBG_LOG -#define NN_DBG_PRINTF(fmt, ...) \ - printf("[%s:%d] " fmt, __FILENAME__, __LINE__, ##__VA_ARGS__); \ - printf("\n"); \ - fflush(stdout) -#else -#define NN_DBG_PRINTF(fmt, ...) -#endif -#ifdef ENABLE_INFO_LOG -#define NN_INFO_PRINTF(fmt, ...) \ - printf("[%s:%d] " fmt, __FILENAME__, __LINE__, ##__VA_ARGS__); \ - printf("\n"); \ - fflush(stdout) -#else -#define NN_INFO_PRINTF(fmt, ...) -#endif - -#endif diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/wasi-nn/test/requirements.txt b/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/wasi-nn/test/requirements.txt deleted file mode 100644 index 29123d4cd3c..00000000000 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/wasi-nn/test/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -tensorflow==2.10.0 \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/wasi-nn/test/test_tensorflow.c b/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/wasi-nn/test/test_tensorflow.c deleted file mode 100755 index 0e5e6a98680..00000000000 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/wasi-nn/test/test_tensorflow.c +++ /dev/null @@ -1,301 +0,0 @@ -/* - * Copyright (C) 2019 Intel Corporation. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - */ - -#include -#include -#include -#include -#include -#include -#include "wasi_nn.h" - -#include -#include - -#define MAX_MODEL_SIZE 85000000 -#define MAX_OUTPUT_TENSOR_SIZE 200 -#define INPUT_TENSOR_DIMS 4 -#define EPSILON 1e-8 - -typedef struct { - float *input_tensor; - uint32_t *dim; - uint32_t elements; -} input_info; - -// WASI-NN wrappers - -error -wasm_load(char *model_name, graph *graph) -{ - FILE *pFile = fopen(model_name, "r"); - if (pFile == NULL) - return invalid_argument; - - uint8_t *buffer; - size_t result; - - // allocate memory to contain the whole file: - buffer = (uint8_t *)malloc(sizeof(uint8_t) * MAX_MODEL_SIZE); - if (buffer == NULL) { - fclose(pFile); - return missing_memory; - } - - result = fread(buffer, 1, MAX_MODEL_SIZE, pFile); - if (result <= 0) { - fclose(pFile); - free(buffer); - return missing_memory; - } - - graph_builder_array arr; - - arr.size = 1; - arr.buf = (graph_builder *)malloc(sizeof(graph_builder)); - if (arr.buf == NULL) { - fclose(pFile); - free(buffer); - return missing_memory; - } - - arr.buf[0].size = result; - arr.buf[0].buf = buffer; - - error res = load(&arr, tensorflow, cpu, graph); - - fclose(pFile); - free(buffer); - free(arr.buf); - return res; -} - -error -wasm_init_execution_context(graph graph, graph_execution_context *ctx) -{ - return init_execution_context(graph, ctx); -} - -error -wasm_input(graph_execution_context ctx, float *input_tensor, uint32_t *dim) -{ - tensor_dimensions dims; - dims.size = INPUT_TENSOR_DIMS; - dims.buf = (uint32_t *)malloc(dims.size * sizeof(uint32_t)); - if (dims.buf == NULL) - return missing_memory; - - tensor tensor; - tensor.dimensions = &dims; - for (int i = 0; i < tensor.dimensions->size; ++i) - tensor.dimensions->buf[i] = dim[i]; - tensor.type = fp32; - tensor.data = (uint8_t *)input_tensor; - error err = set_input(ctx, 0, &tensor); - - free(dims.buf); - return err; -} - -error -wasm_compute(graph_execution_context ctx) -{ - return compute(ctx); -} - -error -wasm_get_output(graph_execution_context ctx, uint32_t index, float *out_tensor, - uint32_t *out_size) -{ - return get_output(ctx, index, (uint8_t *)out_tensor, out_size); -} - -// Inference - -float * -run_inference(float *input, uint32_t *input_size, uint32_t *output_size, - char *model_name, uint32_t num_output_tensors) -{ - graph graph; - if (wasm_load(model_name, &graph) != success) { - fprintf(stderr, "Error when loading model."); - exit(1); - } - - graph_execution_context ctx; - if (wasm_init_execution_context(graph, &ctx) != success) { - fprintf(stderr, "Error when initialixing execution context."); - exit(1); - } - - if (wasm_input(ctx, input, input_size) != success) { - fprintf(stderr, "Error when setting input tensor."); - exit(1); - } - - if (wasm_compute(ctx) != success) { - fprintf(stderr, "Error when running inference."); - exit(1); - } - - float *out_tensor = (float *)malloc(sizeof(float) * MAX_OUTPUT_TENSOR_SIZE); - if (out_tensor == NULL) { - fprintf(stderr, "Error when allocating memory for output tensor."); - exit(1); - } - - uint32_t offset = 0; - for (int i = 0; i < num_output_tensors; ++i) { - *output_size = MAX_OUTPUT_TENSOR_SIZE - *output_size; - if (wasm_get_output(ctx, i, &out_tensor[offset], output_size) - != success) { - fprintf(stderr, "Error when getting input ."); - exit(1); - } - - offset += *output_size; - } - *output_size = offset; - return out_tensor; -} - -// UTILS - -input_info -create_input(int *dims) -{ - input_info input = { .dim = NULL, .input_tensor = NULL, .elements = 1 }; - - input.dim = malloc(INPUT_TENSOR_DIMS * sizeof(uint32_t)); - if (input.dim) - for (int i = 0; i < INPUT_TENSOR_DIMS; ++i) { - input.dim[i] = dims[i]; - input.elements *= dims[i]; - } - - input.input_tensor = malloc(input.elements * sizeof(float)); - for (int i = 0; i < input.elements; ++i) - input.input_tensor[i] = i; - - return input; -} - -// TESTS - -void -test_sum() -{ - int dims[] = { 1, 5, 5, 1 }; - input_info input = create_input(dims); - - uint32_t output_size = 0; - float *output = run_inference(input.input_tensor, input.dim, &output_size, - "models/sum.tflite", 1); - - assert(output_size == 1); - assert(fabs(output[0] - 300.0) < EPSILON); - - free(input.dim); - free(input.input_tensor); - free(output); -} - -void -test_max() -{ - int dims[] = { 1, 5, 5, 1 }; - input_info input = create_input(dims); - - uint32_t output_size = 0; - float *output = run_inference(input.input_tensor, input.dim, &output_size, - "models/max.tflite", 1); - - assert(output_size == 1); - assert(fabs(output[0] - 24.0) < EPSILON); - printf("Result: max is %f\n", output[0]); - - free(input.dim); - free(input.input_tensor); - free(output); -} - -void -test_average() -{ - int dims[] = { 1, 5, 5, 1 }; - input_info input = create_input(dims); - - uint32_t output_size = 0; - float *output = run_inference(input.input_tensor, input.dim, &output_size, - "models/average.tflite", 1); - - assert(output_size == 1); - assert(fabs(output[0] - 12.0) < EPSILON); - printf("Result: average is %f\n", output[0]); - - free(input.dim); - free(input.input_tensor); - free(output); -} - -void -test_mult_dimensions() -{ - int dims[] = { 1, 3, 3, 1 }; - input_info input = create_input(dims); - - uint32_t output_size = 0; - float *output = run_inference(input.input_tensor, input.dim, &output_size, - "models/mult_dim.tflite", 1); - - assert(output_size == 9); - for (int i = 0; i < 9; i++) - assert(fabs(output[i] - i) < EPSILON); - - free(input.dim); - free(input.input_tensor); - free(output); -} - -void -test_mult_outputs() -{ - int dims[] = { 1, 4, 4, 1 }; - input_info input = create_input(dims); - - uint32_t output_size = 0; - float *output = run_inference(input.input_tensor, input.dim, &output_size, - "models/mult_out.tflite", 2); - - assert(output_size == 8); - // first tensor check - for (int i = 0; i < 4; i++) - assert(fabs(output[i] - (i * 4 + 24)) < EPSILON); - // second tensor check - for (int i = 0; i < 4; i++) - assert(fabs(output[i + 4] - (i + 6)) < EPSILON); - - free(input.dim); - free(input.input_tensor); - free(output); -} - -int -main() -{ - printf("################### Testing sum...\n"); - test_sum(); - printf("################### Testing max...\n"); - test_max(); - printf("################### Testing average...\n"); - test_average(); - printf("################### Testing multiple dimensions...\n"); - test_mult_dimensions(); - printf("################### Testing multiple outputs...\n"); - test_mult_outputs(); - - printf("Tests: passed!\n"); - return 0; -} diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/wasi-nn/wasi_nn.cmake b/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/wasi-nn/wasi_nn.cmake deleted file mode 100644 index 6d34b5efe61..00000000000 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/wasi-nn/wasi_nn.cmake +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright (C) 2019 Intel Corporation. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -set (WASI_NN_DIR ${CMAKE_CURRENT_LIST_DIR}) - -add_definitions (-DWASM_ENABLE_WASI_NN=1) - -set (LIBC_WASI_NN_SOURCE ${WASI_NN_DIR}/wasi_nn_native.c ${WASI_NN_DIR}/wasi_nn_tensorflow.cpp) - -set (TENSORFLOW_LIB tensorflow-lite) diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/wasi-nn/wasi_nn.h b/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/wasi-nn/wasi_nn.h deleted file mode 100644 index 115ac928aa7..00000000000 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/wasi-nn/wasi_nn.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (C) 2019 Intel Corporation. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - */ - -#ifndef WASI_NN_WASM_H -#define WASI_NN_WASM_H - -#include "wasi_nn_common.h" - -/** - * Following definition from: - * [Aug 10th, 2022] - * https://github.com/WebAssembly/wasi-nn/blob/e5e1a6c31f424c7cd63026cd270e9746775675a0/wasi-nn.wit.md - */ - -/* The graph initialization data. */ - -// This consists of an array of buffers because implementing backends may encode -// their graph IR in parts (e.g., OpenVINO stores its IR and weights -// separately). -typedef struct { - uint8_t *buf; - uint32_t size; -} graph_builder; - -typedef struct { - graph_builder *buf; - uint32_t size; -} graph_builder_array; - -/* The dimensions of a tensor. */ - -// The array length matches the tensor rank and each element in the array -// describes the size of each dimension. -typedef struct { - uint32_t *buf; - uint32_t size; -} tensor_dimensions; - -/* The tensor data. */ - -// Initially conceived as a sparse representation, each empty cell would be -// filled with zeros and the array length must match the product of all of the -// dimensions and the number of bytes in the type (e.g., a 2x2 tensor with -// 4-byte f32 elements would have a data array of length 16). Naturally, this -// representation requires some knowledge of how to lay out data in -// memory--e.g., using row-major ordering--and could perhaps be improved. -typedef uint8_t *tensor_data; - -/* A tensor. */ - -typedef struct { - // Describe the size of the tensor (e.g., 2x2x2x2 -> [2, 2, 2, 2]). To - // represent a tensor containing a single value, use `[1]` for the tensor - // dimensions. - tensor_dimensions *dimensions; - // Describe the type of element in the tensor (e.g., f32). - tensor_type type; - // Contains the tensor data. - tensor_data data; -} tensor; - -/** - * @brief Load an opaque sequence of bytes to use for inference. - * - * @param builder Model builder. - * @param encoding Model encoding. - * @param target Execution target. - * @param graph Graph. - * @return error Execution status. - */ -error -load(graph_builder_array *builder, graph_encoding encoding, - execution_target target, graph *graph) - __attribute__((export_module("wasi_nn"))) - __attribute__((import_module("wasi_nn"))); - -/** - * @brief Create an execution instance of a loaded graph. - * - * @param graph Graph. - * @param ctx Execution context. - * @return error Execution status. - */ -error -init_execution_context(graph graph, graph_execution_context *ctx) - __attribute__((export_module("wasi_nn"))) - __attribute__((import_module("wasi_nn"))); - -/** - * @brief Define the inputs to use for inference. - * - * @param ctx Execution context. - * @param index Input tensor index. - * @param tensor Input tensor. - * @return error Execution status. - */ -error -set_input(graph_execution_context ctx, uint32_t index, tensor *tensor) - __attribute__((export_module("wasi_nn"))) - __attribute__((import_module("wasi_nn"))); - -/** - * @brief Compute the inference on the given inputs. - * - * @param ctx Execution context. - * @return error Execution status. - */ -error -compute(graph_execution_context ctx) __attribute__((export_module("wasi_nn"))) -__attribute__((import_module("wasi_nn"))); - -/** - * @brief Extract the outputs after inference. - * - * @param ctx Execution context. - * @param index Output tensor index. - * @param output_tensor Buffer where output tensor with index `index` is - * copied. - * @param output_tensor_size Pointer to `output_tensor` maximum size. - * After the function call it is updated with the - * copied number of bytes. - * @return error Execution status. - */ -error -get_output(graph_execution_context ctx, uint32_t index, - tensor_data output_tensor, uint32_t *output_tensor_size) - __attribute__((export_module("wasi_nn"))) - __attribute__((import_module("wasi_nn"))); - -#endif diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/wasi-nn/wasi_nn_common.h b/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/wasi-nn/wasi_nn_common.h deleted file mode 100644 index 103185bd1d5..00000000000 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/wasi-nn/wasi_nn_common.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2019 Intel Corporation. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - */ - -#ifndef WASI_NN_COMMON_H -#define WASI_NN_COMMON_H - -#include - -// The type of the elements in a tensor. -typedef enum { fp16 = 0, fp32, up8, ip32 } tensor_type; - -// Describes the encoding of the graph. This allows the API to be implemented by -// various backends that encode (i.e., serialize) their graph IR with different -// formats. -typedef enum { openvino = 0, onnx, tensorflow, pytorch } graph_encoding; - -// Define where the graph should be executed. -typedef enum { cpu = 0, gpu, tpu } execution_target; - -// Error codes returned by functions in this API. -typedef enum { - // No error occurred. - success = 0, - // Caller module passed an invalid argument. - invalid_argument, - // Invalid encoding. - invalid_encoding, - // Caller module is missing a memory export. - missing_memory, - // Device or resource busy. - busy, - // Runtime Error. - runtime_error, -} error; - -// An execution graph for performing inference (i.e., a model). -typedef uint32_t graph; - -// Bind a `graph` to the input and output tensors for an inference. -typedef uint32_t graph_execution_context; - -#endif diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/wasi-nn/wasi_nn_native.c b/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/wasi-nn/wasi_nn_native.c deleted file mode 100644 index 333dd475c6e..00000000000 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/wasi-nn/wasi_nn_native.c +++ /dev/null @@ -1,264 +0,0 @@ -/* - * Copyright (C) 2019 Intel Corporation. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - */ - -#include -#include -#include -#include -#include - -#include "wasi_nn_common.h" -#include "wasm_export.h" -#include "bh_platform.h" - -#include "wasi_nn.h" -#include "wasi_nn_tensorflow.hpp" -#include "logger.h" - -/* Definition of 'wasi_nn.h' structs in WASM app format (using offset) */ - -typedef struct { - uint32_t buf_offset; - uint32_t size; -} graph_builder_wasm; - -typedef struct { - uint32_t buf_offset; - uint32_t size; -} graph_builder_array_wasm; - -typedef struct { - uint32_t dimensions_offset; - tensor_type type; - uint32_t data_offset; -} tensor_wasm; - -typedef struct { - uint32_t buf_offset; - uint32_t size; -} tensor_dimensions_wasm; - -/* Global variables */ - -static uint8_t _is_initialized; -static graph_encoding _encoding; - -/* Utils */ - -static error -check_initialized() -{ - if (!_is_initialized) { - NN_ERR_PRINTF("Model not initialized."); - return invalid_argument; - } - if (_encoding != tensorflow) { - NN_ERR_PRINTF("Model encoding is not tensorflow."); - return invalid_argument; - } - return success; -} - -/* WASI-NN implementation */ - -error -wasi_nn_load(wasm_exec_env_t exec_env, graph_builder_array_wasm *builder, - graph_encoding encoding, execution_target target, graph *graph) -{ - NN_DBG_PRINTF("Running wasi_nn_load [encoding=%d, target=%d]...", encoding, - target); - - wasm_module_inst_t instance = wasm_runtime_get_module_inst(exec_env); - bh_assert(instance); - - if (!wasm_runtime_validate_native_addr(instance, builder, - sizeof(graph_builder_array_wasm))) - return invalid_argument; - - if (!wasm_runtime_validate_app_addr(instance, builder->buf_offset, - builder->size * sizeof(uint32_t))) - return invalid_argument; - - NN_DBG_PRINTF("Graph builder array contains %d elements", builder->size); - - graph_builder_wasm *gb_wasm = - (graph_builder_wasm *)wasm_runtime_addr_app_to_native( - instance, builder->buf_offset); - - graph_builder *gb_native = (graph_builder *)wasm_runtime_malloc( - builder->size * sizeof(graph_builder)); - if (gb_native == NULL) - return missing_memory; - - for (int i = 0; i < builder->size; ++i) { - if (!wasm_runtime_validate_app_addr(instance, gb_wasm[i].buf_offset, - gb_wasm[i].size - * sizeof(uint8_t))) { - wasm_runtime_free(gb_native); - return invalid_argument; - } - - gb_native[i].buf = (uint8_t *)wasm_runtime_addr_app_to_native( - instance, gb_wasm[i].buf_offset); - gb_native[i].size = gb_wasm[i].size; - - NN_DBG_PRINTF("Graph builder %d contains %d elements", i, - gb_wasm[i].size); - } - - graph_builder_array gba_native = { .buf = gb_native, - .size = builder->size }; - - if (!wasm_runtime_validate_native_addr(instance, graph, sizeof(graph))) { - wasm_runtime_free(gb_native); - return invalid_argument; - } - - switch (encoding) { - case tensorflow: - break; - default: - NN_ERR_PRINTF("Only tensorflow is supported."); - wasm_runtime_free(gb_native); - return invalid_argument; - } - - _encoding = encoding; - _is_initialized = 1; - - error res = tensorflow_load(gba_native, _encoding, target, graph); - NN_DBG_PRINTF("wasi_nn_load finished with status %d [graph=%d]", res, - *graph); - - wasm_runtime_free(gb_native); - return res; -} - -error -wasi_nn_init_execution_context(wasm_exec_env_t exec_env, graph graph, - graph_execution_context *ctx) -{ - NN_DBG_PRINTF("Running wasi_nn_init_execution_context [graph=%d]...", - graph); - error res; - if (success != (res = check_initialized())) - return res; - res = tensorflow_init_execution_context(graph); - *ctx = graph; - NN_DBG_PRINTF( - "wasi_nn_init_execution_context finished with status %d [ctx=%d]", res, - *ctx); - return res; -} - -error -wasi_nn_set_input(wasm_exec_env_t exec_env, graph_execution_context ctx, - uint32_t index, tensor_wasm *input_tensor) -{ - NN_DBG_PRINTF("Running wasi_nn_set_input [ctx=%d, index=%d]...", ctx, - index); - - error res; - if (success != (res = check_initialized())) - return res; - - wasm_module_inst_t instance = wasm_runtime_get_module_inst(exec_env); - bh_assert(instance); - - if (!wasm_runtime_validate_native_addr(instance, input_tensor, - sizeof(tensor_wasm))) - return invalid_argument; - - if (!wasm_runtime_validate_app_addr( - instance, input_tensor->dimensions_offset, sizeof(uint32_t))) - return invalid_argument; - - tensor_dimensions_wasm *dimensions_w = - (tensor_dimensions_wasm *)wasm_runtime_addr_app_to_native( - instance, input_tensor->dimensions_offset); - - if (!wasm_runtime_validate_app_addr(instance, dimensions_w->buf_offset, - dimensions_w->size * sizeof(uint32_t))) - return invalid_argument; - - tensor_dimensions dimensions = { - .buf = (uint32_t *)wasm_runtime_addr_app_to_native( - instance, dimensions_w->buf_offset), - .size = dimensions_w->size - }; - - NN_DBG_PRINTF("Number of dimensions: %d", dimensions.size); - int total_elements = 1; - for (int i = 0; i < dimensions.size; ++i) { - NN_DBG_PRINTF("Dimension %d: %d", i, dimensions.buf[i]); - total_elements *= dimensions.buf[i]; - } - NN_DBG_PRINTF("Tensor type: %d", input_tensor->type); - - if (!wasm_runtime_validate_app_addr(instance, input_tensor->data_offset, - total_elements)) - return invalid_argument; - - tensor tensor = { .type = input_tensor->type, - .dimensions = &dimensions, - .data = (uint8_t *)wasm_runtime_addr_app_to_native( - instance, input_tensor->data_offset) }; - - res = tensorflow_set_input(ctx, index, &tensor); - NN_DBG_PRINTF("wasi_nn_set_input finished with status %d", res); - return res; -} - -error -wasi_nn_compute(wasm_exec_env_t exec_env, graph_execution_context ctx) -{ - NN_DBG_PRINTF("Running wasi_nn_compute [ctx=%d]...", ctx); - error res; - if (success != (res = check_initialized())) - return res; - - res = tensorflow_compute(ctx); - NN_DBG_PRINTF("wasi_nn_compute finished with status %d", res); - return res; -} - -error -wasi_nn_get_output(wasm_exec_env_t exec_env, graph_execution_context ctx, - uint32_t index, tensor_data output_tensor, - uint32_t *output_tensor_size) -{ - NN_DBG_PRINTF("Running wasi_nn_get_output [ctx=%d, index=%d]...", ctx, - index); - error res; - if (success != (res = check_initialized())) - return res; - - res = tensorflow_get_output(ctx, index, output_tensor, output_tensor_size); - NN_DBG_PRINTF("wasi_nn_get_output finished with status %d [data_size=%d]", - res, *output_tensor_size); - return res; -} - -/* Register WASI-NN in WAMR */ - -/* clang-format off */ -#define REG_NATIVE_FUNC(func_name, signature) \ - { #func_name, wasi_nn_##func_name, signature, NULL } -/* clang-format on */ - -static NativeSymbol native_symbols_wasi_nn[] = { - REG_NATIVE_FUNC(load, "(*ii*)i"), - REG_NATIVE_FUNC(init_execution_context, "(i*)i"), - REG_NATIVE_FUNC(set_input, "(ii*)i"), - REG_NATIVE_FUNC(compute, "(i)i"), - REG_NATIVE_FUNC(get_output, "(ii**)i"), -}; - -uint32_t -get_wasi_nn_export_apis(NativeSymbol **p_libc_wasi_apis) -{ - *p_libc_wasi_apis = native_symbols_wasi_nn; - return sizeof(native_symbols_wasi_nn) / sizeof(NativeSymbol); -} diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/wasi-nn/wasi_nn_tensorflow.cpp b/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/wasi-nn/wasi_nn_tensorflow.cpp deleted file mode 100644 index 597b04dc284..00000000000 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/wasi-nn/wasi_nn_tensorflow.cpp +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Copyright (C) 2019 Intel Corporation. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - */ - -#include "wasi_nn_tensorflow.hpp" -#include "wasi_nn_common.h" -#include "bh_common.h" -#include "bh_platform.h" -#include "platform_common.h" - -#include -#include -#include -#include -#include - -/* Global variables */ - -static std::unique_ptr interpreter; -static std::unique_ptr model; - -static char *model_pointer = NULL; - -/* WASI-NN (tensorflow) implementation */ - -error -tensorflow_load(graph_builder_array builder, graph_encoding encoding, - execution_target target, graph *graph) -{ - if (model_pointer != NULL) { - wasm_runtime_free(model_pointer); - model_pointer = NULL; - } - - if (builder.size != 1) { - NN_ERR_PRINTF("Unexpected builder format."); - return invalid_argument; - } - - if (encoding != tensorflow) { - NN_ERR_PRINTF("Encoding is not tensorflow."); - return invalid_argument; - } - - if (target != cpu) { - NN_ERR_PRINTF("Only CPU target is supported."); - return invalid_argument; - } - - uint32_t size = builder.buf[0].size; - - model_pointer = (char *)wasm_runtime_malloc(size); - if (model_pointer == NULL) { - NN_ERR_PRINTF("Error when allocating memory for model."); - return missing_memory; - } - - bh_memcpy_s(model_pointer, size, builder.buf[0].buf, size); - - model = tflite::FlatBufferModel::BuildFromBuffer(model_pointer, size, NULL); - if (model == NULL) { - NN_ERR_PRINTF("Loading model error."); - wasm_runtime_free(model_pointer); - model_pointer = NULL; - return missing_memory; - } - - // Build the interpreter with the InterpreterBuilder. - tflite::ops::builtin::BuiltinOpResolver resolver; - tflite::InterpreterBuilder tflite_builder(*model, resolver); - tflite_builder(&interpreter); - if (interpreter == NULL) { - NN_ERR_PRINTF("Error when generating the interpreter."); - wasm_runtime_free(model_pointer); - model_pointer = NULL; - return missing_memory; - } - - return success; -} - -error -tensorflow_init_execution_context(graph graph) -{ - if (interpreter == NULL) { - NN_ERR_PRINTF("Non-initialized interpreter."); - return runtime_error; - } - interpreter->AllocateTensors(); - return success; -} - -error -tensorflow_set_input(graph_execution_context ctx, uint32_t index, - tensor *input_tensor) -{ - if (interpreter == NULL) { - NN_ERR_PRINTF("Non-initialized interpreter."); - return runtime_error; - } - - uint32_t num_tensors = interpreter->inputs().size(); - NN_DBG_PRINTF("Number of tensors (%d)", num_tensors); - if (index + 1 > num_tensors) { - return runtime_error; - } - - auto tensor = interpreter->input_tensor(index); - if (tensor == NULL) { - NN_ERR_PRINTF("Missing memory"); - return missing_memory; - } - - uint32_t model_tensor_size = 1; - for (int i = 0; i < (int)tensor->dims->size; ++i) - model_tensor_size *= (uint32_t)tensor->dims->data[i]; - - uint32_t input_tensor_size = 1; - for (int i = 0; i < input_tensor->dimensions->size; i++) - input_tensor_size *= (uint32_t)input_tensor->dimensions->buf[i]; - - if (model_tensor_size != input_tensor_size) { - NN_ERR_PRINTF("Input tensor shape from the model is different than the " - "one provided"); - return invalid_argument; - } - - auto *input = interpreter->typed_input_tensor(index); - if (input == NULL) - return missing_memory; - - bh_memcpy_s(input, model_tensor_size * sizeof(float), input_tensor->data, - model_tensor_size * sizeof(float)); - return success; -} - -error -tensorflow_compute(graph_execution_context ctx) -{ - if (interpreter == NULL) { - NN_ERR_PRINTF("Non-initialized interpreter."); - return runtime_error; - } - interpreter->Invoke(); - return success; -} - -error -tensorflow_get_output(graph_execution_context context, uint32_t index, - tensor_data output_tensor, uint32_t *output_tensor_size) -{ - if (interpreter == NULL) { - NN_ERR_PRINTF("Non-initialized interpreter."); - return runtime_error; - } - - uint32_t num_output_tensors = interpreter->outputs().size(); - NN_DBG_PRINTF("Number of tensors (%d)", num_output_tensors); - - if (index + 1 > num_output_tensors) { - return runtime_error; - } - - auto tensor = interpreter->output_tensor(index); - if (tensor == NULL) { - NN_ERR_PRINTF("Missing memory"); - return missing_memory; - } - - uint32_t model_tensor_size = 1; - for (int i = 0; i < (int)tensor->dims->size; ++i) - model_tensor_size *= (uint32_t)tensor->dims->data[i]; - - if (*output_tensor_size < model_tensor_size) { - NN_ERR_PRINTF("Insufficient memory to copy tensor %d", index); - return missing_memory; - } - - float *tensor_f = interpreter->typed_output_tensor(index); - for (int i = 0; i < model_tensor_size; ++i) - NN_DBG_PRINTF("output: %f", tensor_f[i]); - - *output_tensor_size = model_tensor_size; - bh_memcpy_s(output_tensor, model_tensor_size * sizeof(float), tensor_f, - model_tensor_size * sizeof(float)); - return success; -} diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/wasi-nn/wasi_nn_tensorflow.hpp b/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/wasi-nn/wasi_nn_tensorflow.hpp deleted file mode 100644 index 46264c0b811..00000000000 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/wasi-nn/wasi_nn_tensorflow.hpp +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2019 Intel Corporation. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - */ - -#ifndef WASI_NN_TENSORFLOW_HPP -#define WASI_NN_TENSORFLOW_HPP - -#include - -#include "wasi_nn.h" -#include "logger.h" - -#ifdef __cplusplus -extern "C" { -#endif - -error -tensorflow_load(graph_builder_array builder, graph_encoding encoding, - execution_target target, graph *graph); - -error -tensorflow_init_execution_context(graph graph); - -error -tensorflow_set_input(graph_execution_context ctx, uint32_t index, - tensor *input_tensor); - -error -tensorflow_compute(graph_execution_context ctx); - -error -tensorflow_get_output(graph_execution_context context, uint32_t index, - tensor_data output_tensor, uint32_t *output_tensor_size); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/common/posix/posix_malloc.c b/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/common/posix/posix_malloc.c deleted file mode 100644 index 660d1baae6c..00000000000 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/common/posix/posix_malloc.c +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (C) 2019 Intel Corporation. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - */ - -#include "platform_api_vmcore.h" - -void * -os_malloc(unsigned size) -{ - return malloc(size); -} - -void * -os_realloc(void *ptr, unsigned size) -{ - return realloc(ptr, size); -} - -void -os_free(void *ptr) -{ - free(ptr); -} diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/version.h.in b/lib/wasm-micro-runtime-WAMR-1.1.1/core/version.h.in deleted file mode 100644 index 882305a8ce8..00000000000 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/version.h.in +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright (C) 2019 Intel Corporation. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - */ - -/* Please don't modify this header. It is automatically generated. - Any modification should be in config_common.cmake */ - -#ifndef _WAMR_VERSION_H_ -#define _WAMR_VERSION_H_ -#cmakedefine WAMR_VERSION_MAJOR @WAMR_VERSION_MAJOR@ -#define WAMR_VERSION_MINOR @WAMR_VERSION_MINOR@ -#define WAMR_VERSION_PATCH @WAMR_VERSION_PATCH@ -#endif diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/doc/build_wamr.md b/lib/wasm-micro-runtime-WAMR-1.1.1/doc/build_wamr.md deleted file mode 100644 index 2986640553b..00000000000 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/doc/build_wamr.md +++ /dev/null @@ -1,612 +0,0 @@ - -Build WAMR vmcore (iwasm) -========================= -It is recommended to use the [WAMR SDK](../wamr-sdk) tools to build a project that integrates the WAMR. This document introduces how to build the WAMR minimal product which is vmcore only (no app-framework and app-mgr) for multiple platforms. - -## WAMR vmcore cmake building configurations - -By including the script `runtime_lib.cmake` under folder [build-scripts](../build-scripts) in CMakeList.txt, it is easy to build minimal product with cmake. - -```cmake -# add this into your CMakeList.txt -include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake) -add_library(vmlib ${WAMR_RUNTIME_LIB_SOURCE}) -``` - -The script `runtime_lib.cmake` defines a number of variables for configuring the WAMR runtime features. You can set these variables in your CMakeList.txt or pass the configurations from cmake command line. - -#### **Configure platform and architecture** - -- **WAMR_BUILD_PLATFORM**: set the target platform. It can be set to any platform name (folder name) under folder [core/shared/platform](../core/shared/platform). - -- **WAMR_BUILD_TARGET**: set the target CPU architecture. Current supported targets are: X86_64, X86_32, AARCH64, ARM, THUMB, XTENSA, ARC, RISCV32, RISCV64 and MIPS. - - For ARM and THUMB, the format is \\[\]\[_VFP], where \ is the ARM sub-architecture and the "_VFP" suffix means using VFP coprocessor registers s0-s15 (d0-d7) for passing arguments or returning results in standard procedure-call. Both \ and "_VFP" are optional, e.g. ARMV7, ARMV7_VFP, THUMBV7, THUMBV7_VFP and so on. - - For AARCH64, the format is\[\], VFP is enabled by default. \ is optional, e.g. AARCH64, AARCH64V8, AARCH64V8.1 and so on. - - For RISCV64, the format is \[_abi], where "_abi" is optional, currently the supported formats are RISCV64, RISCV64_LP64D and RISCV64_LP64: RISCV64 and RISCV64_LP64D are identical, using [LP64D](https://github.com/riscv/riscv-elf-psabi-doc/blob/master/riscv-elf.md#-named-abis) as abi (LP64 with hardware floating-point calling convention for FLEN=64). And RISCV64_LP64 uses [LP64](https://github.com/riscv/riscv-elf-psabi-doc/blob/master/riscv-elf.md#-named-abis) as abi (Integer calling-convention only, and hardware floating-point calling convention is not used). - - For RISCV32, the format is \[_abi], where "_abi" is optional, currently the supported formats are RISCV32, RISCV32_ILP32D and RISCV32_ILP32: RISCV32 and RISCV32_ILP32D are identical, using [ILP32D](https://github.com/riscv/riscv-elf-psabi-doc/blob/master/riscv-elf.md#-named-abis) as abi (ILP32 with hardware floating-point calling convention for FLEN=64). And RISCV32_ILP32 uses [ILP32](https://github.com/riscv/riscv-elf-psabi-doc/blob/master/riscv-elf.md#-named-abis) as abi (Integer calling-convention only, and hardware floating-point calling convention is not used). - -```bash -cmake -DWAMR_BUILD_PLATFORM=linux -DWAMR_BUILD_TARGET=ARM -``` - -#### **Configure interpreters** - -- **WAMR_BUILD_INTERP**=1/0: enable or disable WASM interpreter - -- **WAMR_BUILD_FAST_INTERP**=1/0: build fast (default) or classic WASM interpreter. - - NOTE: the fast interpreter runs ~2X faster than classic interpreter, but consumes about 2X memory to hold the pre-compiled code. - -#### **Configure AOT and JITs** - -- **WAMR_BUILD_AOT**=1/0, enable AOT or not, default to enable if not set -- **WAMR_BUILD_JIT**=1/0, enable LLVM JIT or not, default to disable if not set -- **WAMR_BUILD_LAZY_JIT**=1/0, whether to use Lazy JIT mode or not when *WAMR_BUILD_JIT* is set, default to enable if not set -- **WAMR_BUILD_FAST_JIT**=1/0, enable Fast JIT or not, default to disable if not set - -#### **Configure LIBC** - -- **WAMR_BUILD_LIBC_BUILTIN**=1/0, build the built-in libc subset for WASM app, default to enable if not set - -- **WAMR_BUILD_LIBC_WASI**=1/0, build the [WASI](https://github.com/WebAssembly/WASI) libc subset for WASM app, default to enable if not set - -- **WAMR_BUILD_LIBC_UVWASI**=1/0 (Experiment), build the [WASI](https://github.com/WebAssembly/WASI) libc subset for WASM app based on [uvwasi](https://github.com/nodejs/uvwasi) implementation, default to disable if not set - -> Note: for platform which doesn't support **WAMR_BUILD_LIBC_WASI**, e.g. Windows, developer can try using **WAMR_BUILD_LIBC_UVWASI**. - -#### **Enable Multi-Module feature** - -- **WAMR_BUILD_MULTI_MODULE**=1/0, default to disable if not set - -#### **Enable WASM mini loader** - -- **WAMR_BUILD_MINI_LOADER**=1/0, default to disable if not set - -> Note: the mini loader doesn't check the integrity of the WASM binary file, developer must ensure that the WASM file is well-formed. - -#### **Enable shared memory feature** -- **WAMR_BUILD_SHARED_MEMORY**=1/0, default to disable if not set - -#### **Enable bulk memory feature** -- **WAMR_BUILD_BULK_MEMORY**=1/0, default to disable if not set - -#### **Enable thread manager** -- **WAMR_BUILD_THREAD_MGR**=1/0, default to disable if not set - -#### **Enable lib-pthread** -- **WAMR_BUILD_LIB_PTHREAD**=1/0, default to disable if not set -> Note: The dependent feature of lib pthread such as the `shared memory` and `thread manager` will be enabled automatically. - -#### **Enable lib-pthread-semaphore** -- **WAMR_BUILD_LIB_PTHREAD_SEMAPHORE**=1/0, default to disable if not set -> Note: This feature depends on `lib-pthread`, it will be enabled automatically if this feature is enabled. - -#### **Disable boundary check with hardware trap in AOT or JIT mode** -- **WAMR_DISABLE_HW_BOUND_CHECK**=1/0, default to enable if not set and supported by platform -> Note: by default only platform linux/darwin/android/vxworks 64-bit will enable boundary check with hardware trap in AOT or JIT mode, and the wamrc tool will generate AOT code without boundary check instructions in all 64-bit targets except SGX to improve performance. - -#### **Enable tail call feature** -- **WAMR_BUILD_TAIL_CALL**=1/0, default to disable if not set - -#### **Enable 128-bit SIMD feature** -- **WAMR_BUILD_SIMD**=1/0, default to enable if not set -> Note: only supported in AOT mode x86-64 target. - -#### **Configure Debug** - -- **WAMR_BUILD_CUSTOM_NAME_SECTION**=1/0, load the function name from custom name section, default to disable if not set - -#### **Enable dump call stack feature** -- **WAMR_BUILD_DUMP_CALL_STACK**=1/0, default to disable if not set - -> Note: if it is enabled, the call stack will be dumped when exception occurs. - -> - For interpreter mode, the function names are firstly extracted from *custom name section*, if this section doesn't exist or the feature is not enabled, then the name will be extracted from the import/export sections -> - For AOT/JIT mode, the function names are extracted from import/export section, please export as many functions as possible (for `wasi-sdk` you can use `-Wl,--export-all`) when compiling wasm module, and add `--enable-dump-call-stack` option to wamrc during compiling AOT module. - -#### **Enable memory profiling (Experiment)** -- **WAMR_BUILD_MEMORY_PROFILING**=1/0, default to disable if not set -> Note: if it is enabled, developer can use API `void wasm_runtime_dump_mem_consumption(wasm_exec_env_t exec_env)` to dump the memory consumption info. -Currently we only profile the memory consumption of module, module_instance and exec_env, the memory consumed by other components such as `wasi-ctx`, `multi-module` and `thread-manager` are not included. - -#### **Enable performance profiling (Experiment)** -- **WAMR_BUILD_PERF_PROFILING**=1/0, default to disable if not set -> Note: if it is enabled, developer can use API `void wasm_runtime_dump_perf_profiling(wasm_module_inst_t module_inst)` to dump the performance consumption info. Currently we only profile the performance consumption of each WASM function. - -> The function name searching sequence is the same with dump call stack feature. - -#### **Set maximum app thread stack size** -- **WAMR_APP_THREAD_STACK_SIZE_MAX**=n, default to 8 MB (8388608) if not set -> Note: the AOT boundary check with hardware trap mechanism might consume large stack since the OS may lazily grow the stack mapping as a guard page is hit, we may use this configuration to reduce the total stack usage, e.g. -DWAMR_APP_THREAD_STACK_SIZE_MAX=131072 (128 KB). - -#### **WAMR_BH_VPRINTF**=, default to disable if not set -> Note: if the vprintf_callback function is provided by developer, the os_printf() and os_vprintf() in Linux, Darwin, Windows and VxWorks platforms, besides WASI Libc output will call the callback function instead of libc vprintf() function to redirect the stdout output. For example, developer can define the callback function like below outside runtime lib: -> -> ```C -> int my_vprintf(const char *format, va_list ap) -> { -> /* output to pre-opened file stream */ -> FILE *my_file = ...; -> return vfprintf(my_file, format, ap); -> /* or output to pre-opened file descriptor */ -> int my_fd = ...; -> return vdprintf(my_fd, format, ap); -> /* or output to string buffer and print the string */ -> char buf[128]; -> vsnprintf(buf, sizeof(buf), format, ap); -> return my_printf("%s", buf); -> } -> ``` -> -> and then use `cmake -DWAMR_BH_VPRINTF=my_vprintf ..` to pass the callback function, or add `BH_VPRINTF=my_vprintf` macro for the compiler, e.g. add line `add_defintions(-DBH_VPRINTF=my_vprintf)` in CMakeListst.txt. - -#### **Enable reference types feature** -- **WAMR_BUILD_REF_TYPES**=1/0, default to disable if not set - -#### **Exclude WAMR application entry functions** -- **WAMR_DISABLE_APP_ENTRY**=1/0, default to disable if not set - -> Note: The WAMR application entry (`core/iwasm/common/wasm_application.c`) encapsulate some common process to instantiate, execute the wasm functions and print the results. Some platform related APIs are used in these functions, so you can enable this flag to exclude this file if your platform doesn't support those APIs. -> *Don't enable this flag if you are building `product-mini`* - -#### **Enable source debugging features** -- **WAMR_BUILD_DEBUG_INTERP**=1/0, default to 0 if not set -> Note: There are some other setup required by source debugging, please refer to [source_debugging.md](./source_debugging.md) for more details. - -#### **Enable load wasm custom sections** -- **WAMR_BUILD_LOAD_CUSTOM_SECTION**=1/0, default to disable if not set - -> Note: By default, the custom sections are ignored. If the embedder wants to get custom sections from `wasm_module_t`, then `WAMR_BUILD_LOAD_CUSTOM_SECTION` should be enabled, and then `wasm_runtime_get_custom_section` can be used to get a custom section by name. - -> Note: If `WAMR_BUILD_CUSTOM_NAME_SECTION` is enabled, then the `custom name section` will be treated as a special section and consumed by the runtime, not available to the embedder. - -> For AoT file, must use `--emit-custom-sections` to specify which sections need to be emitted into AoT file, otherwise all custom sections (except custom name section) will be ignored. - -### **Stack guard size** -- **WAMR_BUILD_STACK_GUARD_SIZE**=n, default to N/A if not set. -> Note: By default, the stack guard size is 1K (1024) or 24K (if uvwasi enabled). - -**Combination of configurations:** - -We can combine the configurations. For example, if we want to disable interpreter, enable AOT and WASI, we can run command: - -``` Bash -cmake .. -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_AOT=1 -DWAMR_BUILD_LIBC_WASI=0 -DWAMR_BUILD_PLATFORM=linux -``` - -Or if we want to enable interpreter, disable AOT and WASI, and build as X86_32, we can run command: - -``` Bash -cmake .. -DWAMR_BUILD_INTERP=1 -DWAMR_BUILD_AOT=0 -DWAMR_BUILD_LIBC_WASI=0 -DWAMR_BUILD_TARGET=X86_32 -``` - -## Cross compilation - -If you are building for ARM architecture on a X86 development machine, you can use the `CMAKE_TOOLCHAIN_FILE` to set the toolchain file for cross compling. - -``` -cmake .. -DCMAKE_TOOLCHAIN_FILE=$TOOL_CHAIN_FILE \ - -DWAMR_BUILD_PLATFORM=linux \ - -DWAMR_BUILD_TARGET=ARM -``` - -Refer to toolchain sample file [`samples/simple/profiles/arm-interp/toolchain.cmake`](../samples/simple/profiles/arm-interp/toolchain.cmake) for how to build mini product for ARM target architecture. - -If you compile for ESP-IDF, make sure to set the right toolchain file for the chip you're using (e.g. `$IDF_PATH/tools/cmake/toolchain-esp32c3.cmake`). -Note that all ESP-IDF toolchain files live under `$IDF_PATH/tools/cmake/`. - -Linux -------------------------- -First of all please install the dependent packages. -Run command below in Ubuntu-18.04: - -``` Bash -sudo apt install build-essential cmake g++-multilib libgcc-8-dev lib32gcc-8-dev -``` -Or in Ubuntu-16.04: -``` Bash -sudo apt install build-essential cmake g++-multilib libgcc-5-dev lib32gcc-5-dev -``` -Or in Fedora: -``` Bash -sudo dnf install glibc-devel.i686 -``` - -After installing dependencies, build the source code: -``` Bash -cd product-mini/platforms/linux/ -mkdir build && cd build -cmake .. -make -# iwasm is generated under current directory -``` - -By default in Linux, the `fast interpreter`, `AOT` and `Libc WASI` are enabled, and JIT is disabled. -And the build target is set to X86_64 or X86_32 depending on the platform's bitwidth. - -There are total 6 running modes supported: fast interpreter, classi interpreter, AOT, LLVM Lazy JIT, LLVM MC JIT and Fast JIT. - -(1) To run a wasm file with `fast interpreter` mode - build iwasm with default build and then: -```Bash -iwasm -``` -Or -```Bash -mkdir build && cd build -cmake .. -DWAMR_BUILD_INTERP=1 -make -``` - -(2) To disable `fast interpreter` and enable `classic interpreter` instead: -``` Bash -mkdir build && cd build -cmake .. -DWAMR_BUILD_FAST_INTERP=0 -make -``` - -(3) To run an AOT file, firstly please refer to [Build wamrc AOT compiler](../README.md#build-wamrc-aot-compiler) to build wamrc, and then: -```Bash -wamrc -o -iwasm -``` - -(4) To enable the `LLVM Lazy JIT` mode, firstly we should build LLVM library: -``` Bash -cd product-mini/platforms/linux/ -./build_llvm.sh (The llvm source code is cloned under /core/deps/llvm and auto built) -``` - -Then pass argument `-DWAMR_BUILD_JIT=1` to cmake to enable LLVM Lazy JIT: -``` Bash -mkdir build && cd build -cmake .. -DWAMR_BUILD_JIT=1 -make -``` - -(5) Or disable `LLVM Lazy JIT` and enable `LLVM MC JIT` instead: -```Bash -mkdir build && cd build -cmake .. -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=0 -make -``` - -By default, the LLVM Orc Lazy JIT is enabled to speedup the lanuching process and reduce the JIT compilation time -by creating threads to compile the WASM functions parallely, and for the main thread, the functions in the -module will not be compiled until they are firstly called and haven't been compiled by the compilation threads. -To disable it and enable LLVM MC JIT instead, please pass argument `-DWAMR_BUILD_LAZY_JIT=0` to cmake. - -(6) To enable the `Fast JIT` mode: -``` Bash -mkdir build && cd build -cmake .. -DWAMR_BUILD_FAST_JIT=1 -make -``` -The Fast JIT is a lightweight JIT engine with quick startup, small footprint and good portability, and gains ~50% performance of AOT. - -Linux SGX (Intel Software Guard Extension) -------------------------- - -Please see [Build and Port WAMR vmcore for Linux SGX](./linux_sgx.md) for the details. - -MacOS -------------------------- - -Make sure to install Xcode from App Store firstly, and install cmake. - -If you use Homebrew, install cmake from the command line: -``` Bash -brew install cmake -``` - -Then build the source codes: -``` Bash -cd product-mini/platforms/darwin/ -mkdir build -cd build -cmake .. -make -# iwasm is generated under current directory -``` -By default in MacOS, the `fast interpreter`, `AOT` and `Libc WASI` are enabled, and JIT is disabled. -And the build target is set to X86_64 or X86_32 depending on the platform's bitwidth. - -To run a wasm file with interpreter mode: -```Bash -iwasm -``` -To run an AOT file, firstly please refer to [Build wamrc AOT compiler](../README.md#build-wamrc-aot-compiler) to build wamrc, and then: -```Bash -wamrc -o -iwasm -``` -Note: -For how to build the `JIT` mode and `classic interpreter` mode, please refer to [Build iwasm on Linux](./build_wamr.md#linux). - -WAMR provides some features which can be easily configured by passing options to cmake, please see [WAMR vmcore cmake building configurations](./build_wamr.md#wamr-vmcore-cmake-building-configurations) for details. Currently in MacOS, interpreter, AOT, and builtin libc are enabled by default. - -Windows -------------------------- - -Make sure `MSVC` and `cmake` are installed and available in the command line environment - -Then build the source codes: -``` Bash -cd product-mini/platforms/windows/ -mkdir build -cd build -cmake .. -cmake --build . --config Release -# ./Release/iwasm.exe is generated -``` - -By default in Windows, the `fast interpreter`, `AOT` and `Libc WASI` are enabled, and JIT is disabled. - -To run a wasm file with interpreter mode: -```Bash -iwasm.exe -``` -To run an AOT file, firstly please refer to [Build wamrc AOT compiler](../README.md#build-wamrc-aot-compiler) to build wamrc, and then: -```Bash -wamrc.exe -o -iwasm.exe -``` -Note: -For how to build the `JIT` mode and `classic interpreter` mode, please refer to [Build iwasm on Linux](./build_wamr.md#linux). - -WAMR provides some features which can be easily configured by passing options to cmake, please see [WAMR vmcore cmake building configurations](./build_wamr.md#wamr-vmcore-cmake-building-configurations) for details. Currently in Windows, interpreter, AOT, and builtin libc are enabled by default. - -MinGW -------------------------- - -First make sure the correct CMake package is installed; the following commands -are valid for the MSYS2 build environment: - -```Bash -pacman -R cmake -pacman -S mingw-w64-x86_64-cmake -``` - -Then follow the build instructions for Windows above, and add the following -arguments for cmake: - -```Bash -cmake .. -G"Unix Makefiles" \ - -DWAMR_BUILD_LIBC_UVWASI=0 \ - -DWAMR_BUILD_INVOKE_NATIVE_GENERAL=1 \ - -DWAMR_DISABLE_HW_BOUND_CHECK=1 -```` - -Note that WASI will be disabled until further work is done towards full MinGW support. - -- uvwasi not building out of the box, though it reportedly supports MinGW. -- Failing compilation of assembler files, the C version of `invokeNative()` will -be used instead. -- Compiler complaining about missing `UnwindInfoAddress` field in `RUNTIME_FUNCTION` -struct (winnt.h). - - -VxWorks -------------------------- -VxWorks 7 SR0620 release is validated. - -First you need to build a VSB. Make sure *UTILS_UNIX* layer is added in the VSB. -After the VSB is built, export the VxWorks toolchain path by: -```bash -export /host/vx-compiler/bin:$PATH -``` -Now switch to iwasm source tree to build the source code: -```bash -cd product-mini/platforms/vxworks/ -mkdir build -cd build -cmake .. -make -``` -Create a VIP based on the VSB. Make sure the following components are added: -* INCLUDE_POSIX_PTHREADS -* INCLUDE_POSIX_PTHREAD_SCHEDULER -* INCLUDE_SHARED_DATA -* INCLUDE_SHL - -Copy the generated iwasm executable, the test WASM binary as well as the needed -shared libraries (libc.so.1, libllvm.so.1 or libgnu.so.1 depending on the VSB, -libunix.so.1) to a supported file system (eg: romfs). - -Note: -WAMR provides some features which can be easily configured by passing options to cmake, please see [WAMR vmcore cmake building configurations](./build_wamr.md#wamr-vmcore-cmake-building-configurations) for details. Currently in VxWorks, interpreter and builtin libc are enabled by default. - -Zephyr -------------------------- -You need to prepare Zephyr first as described here https://docs.zephyrproject.org/latest/getting_started/index.html#get-zephyr-and-install-python-dependencies. - -After that you need to point the `ZEPHYR_BASE` variable to e.g. `~/zephyrproject/zephyr`. Also, it is important that you have `west` available for subsequent actions. - -``` Bash -cd /product-mini/platforms/zephyr/simple -# Execute the ./build_and_run.sh script with board name as parameter. Here take x86 as example: -./build_and_run.sh x86 -``` - -If you want to use the Espressif toolchain (esp32 or esp32c3), you can most conveniently install it with `west`: - -``` Bash -cd $ZEPHYR_BASE -west espressif install -``` - -After that set `ESPRESSIF_TOOLCHAIN_PATH` according to the output, for example `~/.espressif/tools/zephyr`. - -Note: -WAMR provides some features which can be easily configured by passing options to cmake, please see [WAMR vmcore cmake building configurations](./build_wamr.md#wamr-vmcore-cmake-building-configurations) for details. Currently in Zephyr, interpreter, AOT and builtin libc are enabled by default. - - -AliOS-Things -------------------------- -1. a developerkit board id needed for testing -2. download the AliOS-Things code - ``` Bash - git clone https://github.com/alibaba/AliOS-Things.git - ``` -3. copy /product-mini/platforms/alios-things directory to AliOS-Things/middleware, and rename it as iwasm - ``` Bash - cp -a /product-mini/platforms/alios-things middleware/iwasm - ``` -4. create a link to in middleware/iwasm/ and rename it to wamr - ``` Bash - ln -s middleware/iwasm/wamr - ``` -5. modify file app/example/helloworld/helloworld.c, patch as: - ``` C - #include - #include - extern bool iwasm_init(); - int application_start(int argc, char *argv[]) - { - int count = 0; - iwasm_init(); - ... - } - ``` -6. modify file app/example/helloworld/aos.mk - ``` C - $(NAME)_COMPONENTS := osal_aos iwasm - ``` -7. build source code and run - For linux host: - - ``` Bash - aos make helloworld@linuxhost -c config - aos make - ./out/helloworld@linuxhost/binary/helloworld@linuxhost.elf - ``` - - For developerkit: - Modify file middleware/iwasm/aos.mk, patch as: - - ``` C - WAMR_BUILD_TARGET := THUMBV7M - ``` - - ``` Bash - aos make helloworld@developerkit -c config - aos make - ``` - download the binary to developerkit board, check the output from serial port - -RT-Thread -------------------------- - -1. Get rt-thread [system codes](https://github.com/RT-Thread/rt-thread). - -2. Enable WAMR software package with menuconfig tool which provided by RT-Thread. - - * Environment in Linux, run command below: - - ```bash - scons --menuconfig - ``` - - * Environment in Windows ConEmu, run command below: - - ```bash - menuconfig - ``` - - Select and enable `WAMR` in: - - * RT-Thread online packages - * tools packages - * WebAssembly Micro Runtime (WAMR) - -3. Configure `WAMR` with menuconfig tool. - - you can choice features of iwasm below: - - * Enable testing parameters of iwasm - * Enable interpreter Mode / Fast interpreter Mode - * Use built-libc - * Enable AOT - -4. Exit menuconfig tool and save configure, update and download package. - - ```bash - pkgs --update - ``` - -5. build project and download the binary to boards. - - ```bash - scons - ``` - - or build project with 8-thread by using command below: - - ```bash - scons -j8 - ``` - - after project building, you can got an binary file named `rtthread.bin`, then you can download this file to the MCU board. - -Android -------------------------- -able to generate a shared library support Android platform. -- need an [android SDK](https://developer.android.com/studio). Go and get the "Command line tools only" -- look for a command named *sdkmanager* and download below components. version numbers might need to check and pick others - - "build-tools;29.0.3" - - "cmake;3.10.2.4988404" - - "ndk;latest" - - "patcher;v4" - - "platform-tools" - - "platforms;android-29" -- add bin/ of the downloaded cmake to $PATH -- export ANDROID_HOME=/the/path/of/downloaded/sdk/ -- export ANDROID_NDK_LATEST_HOME=/the/path/of/downloaded/sdk/ndk/2x.xxx/ -- ready to go - -Use such commands, you are able to compile with default configurations. Any compiling requirement should be satisfied by modifying product-mini/platforms/android/CMakeList.txt. For example, chaning ${WAMR_BUILD_TARGET} in CMakeList could get different libraries support different ABIs. - -``` shell -$ cd product-mini/platforms/android/ -$ mkdir build -$ cd build -$ cmake .. -$ make -$ # check output in distribution/wasm -$ # include/ includes all necesary head files -$ # lib includes libiwasm.so -``` - -NuttX -------------------------- -WAMR is intergrated with NuttX, just enable the WAMR in Kconfig option (Application Configuration/Interpreters). - -ESP-IDF -------------------------- -WAMR integrates with ESP-IDF both for the XTENSA and RISC-V chips (esp32x and esp32c3 respectively). - -In order to use this, you need at least version 4.3.1 of ESP-IDF. -If you don't have it installed, follow the instructions [here](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/#get-started-get-prerequisites). -ESP-IDF also installs the toolchains needed for compiling WAMR and ESP-IDF. -A small demonstration of how to use WAMR and ESP-IDF can be found under [product_mini](/product-mini/platforms/esp-idf). -The demo builds WAMR for ESP-IDF and runs a small wasm program. -In order to run it for your specific Espressif chip, edit the [build_and_run.sh](/product-mini/platforms/esp-idf/build_and_run.sh) file and put the correct toolchain file (see #Cross-compilation) and `IDF_TARGET`. -Before compiling it is also necessary to call ESP-IDF's `export.sh` script to bring all compile time relevant information in scope. - -Docker -------------------------- -[Docker](https://www.docker.com/) will download all the dependencies and build WAMR Core on your behalf. - -Make sure you have Docker installed on your machine: [macOS](https://docs.docker.com/docker-for-mac/install/), [Windows](https://docs.docker.com/docker-for-windows/install/) or [Linux](https://docs.docker.com/install/linux/docker-ce/ubuntu/). - -Build *iwasm* with the Docker image: - -``` Bash -$ cd ci -$ ./build_wamr.sh -$ ls ../build_out/ -``` - -*build_wamr.sh* will generate *linux* compatible libraries ( libiwasm.so and -libvmlib.a ) and an executable binary (*iwasm*) and copy *iwasm* to -*build_out*. All original generated files are still under -*product-mini/platforms/linux/build*. diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/python/README.md b/lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/python/README.md deleted file mode 100644 index 2698a059e67..00000000000 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/python/README.md +++ /dev/null @@ -1,31 +0,0 @@ -# wamr-python - -## Installation - -### Installing from the source code - -Installing from local source tree is in _development mode_. The package appears to be installed but still is editable from the source tree. - -```bash -$ python -m pip install -e /path/to/wamr-root/binding/python -``` - -## Usage - -```python -import wamr.ffi as ffi -``` - -### Preparation - -The binding will load the shared library _libiwasm.so_ from the WAMR repo. So before running the binding, you need to build the library yourself. - -The default compile options are good enough. - -Please be aware that `wasm_frame_xxx` and `wasm_trap_xxx` only work well when enabling `WAMR_BUILD_DUMP_CALL_STACK`. - -### Examples - -There is a [simple example](./samples/hello_procedural.py) to show how to use bindings. Actually, the python binding follows C-APIs. There it should be easy if be familiar with _programming with wasm-c-api_. - -Unit test cases under _./tests_ could be another but more complete references. diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/python/setup.py b/lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/python/setup.py deleted file mode 100755 index c7868187b6b..00000000000 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/python/setup.py +++ /dev/null @@ -1,30 +0,0 @@ -# -*- coding: utf-8 -*- -#!/usr/bin/env python3 -# -# Copyright (C) 2019 Intel Corporation. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -# -# pylint: disable=missing-class-docstring -# pylint: disable=missing-function-docstring -# pylint: disable=missing-module-docstring - -from setuptools import setup, find_packages - - -with open("README.md") as f: - readme = f.read() - -with open("LICENSE") as f: - license = f.read() - -setup( - name="wamr-python", - version="0.1.0", - description="A WebAssembly runtime powered by WAMR", - long_description=readme, - author="The WAMR Project Developers", - author_email="hello@bytecodealliance.org", - url="https://github.com/bytecodealliance/wamr-python", - license=license, - packages=["wamr"], -) diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/native-lib/wasm-app/main.c b/lib/wasm-micro-runtime-WAMR-1.1.1/samples/native-lib/wasm-app/main.c deleted file mode 100644 index f00ec060211..00000000000 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/native-lib/wasm-app/main.c +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2019 Intel Corporation. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - */ - -#include -#include - -int -test_add(int x, int y); - -int -test_sqrt(int x, int y); - -int -main(int argc, char **argv) -{ - int x = 10, y = 20, res; - - printf("Hello World!\n"); - - res = test_add(x, y); - printf("%d + %d = %d\n", x, y, res); - - res = test_sqrt(x, y); - printf("sqrt(%d, %d) = %d\n", x, y, res); - - return 0; -} diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/sgx-ra/README.md b/lib/wasm-micro-runtime-WAMR-1.1.1/samples/sgx-ra/README.md deleted file mode 100644 index 92b5138ee2d..00000000000 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/sgx-ra/README.md +++ /dev/null @@ -1,42 +0,0 @@ -"sgx-ra" sample introduction -============== - -This sample demonstrates how to execute Remote Attestation on SGX with [librats](https://github.com/inclavare-containers/librats) and run it with iwasm. It can only build on [SGX supported processors](https://www.intel.com/content/www/us/en/support/articles/000028173/processors.html), please check it. - -## Preparation - -Before staring, we need to download and intall [SGX SDK](https://download.01.org/intel-sgx/latest/linux-latest/distro) and [SGX DCAP Library](https://download.01.org/intel-sgx/latest/dcap-latest) referring to this [guide](https://download.01.org/intel-sgx/sgx-dcap/1.8/linux/docs/Intel_SGX_DCAP_Linux_SW_Installation_Guide.pdf). - -The following command is the example of the SGX environment installation on ubuntu18.04. -``` shell -$ cd $HOME -$ # Set your platform, you can get the platforms list on -$ # https://download.01.org/intel-sgx/latest/linux-latest/distro -$ SGX_PALTFORM=ubuntu18.04-server -$ SGX_SDK_VERSION=2.17.100.3 -$ SGX_DRIVER_VERSION=1.41 -$ # install SGX Driver -$ wget https://download.01.org/intel-sgx/latest/linux-latest/distro/$SGX_PALTFORM/sgx_linux_x64_driver_$SGX_DRIVER_VERSION.bin -$ chmod +x sgx_linux_x64_driver_$SGX_DRIVER_VERSION.bin -$ sudo ./sgx_linux_x64_driver_$SGX_DRIVER_VERSION.bin -$ # install SGX SDK -$ wget https://download.01.org/intel-sgx/latest/linux-latest/distro/$SGX_PALTFORM/sgx_linux_x64_sdk_$SGX_SDK_VERSION.bin -$ chmod +x sgx_linux_x64_sdk_$SGX_SDK_VERSION.bin -$ sudo ./sgx_linux_x64_sdk_$SGX_SDK_VERSION.bin -$ # install SGX DCAP Library -$ echo 'deb [arch=amd64] https://download.01.org/intel-sgx/sgx_repo/ubuntu bionic main' | sudo tee /etc/apt/sources.list.d/intel-sgx.list > /dev/null -$ wget -O - https://download.01.org/intel-sgx/sgx_repo/ubuntu/intel-sgx-deb.key | sudo apt-key add - -$ sudo apt update -$ sudo apt install libsgx-uae-service libsgx-dcap-default-qpl-dev libsgx-dcap-ql-dev libsgx-dcap-quote-verify-dev -``` - -## Build -``` shell -$ mkdir build && cd build -$ cmake .. -$ make -$ # run the sample -$ ./iwasm wasm-app/test.wasm -``` - -The sample will print the evidence in json and "Evidence is trusted." by default. \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/sgx-ra/wasm-app/main.c b/lib/wasm-micro-runtime-WAMR-1.1.1/samples/sgx-ra/wasm-app/main.c deleted file mode 100644 index d6b079c4e29..00000000000 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/sgx-ra/wasm-app/main.c +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2022 Intel Corporation - * Copyright (c) 2020-2021 Alibaba Cloud - * - * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - */ - -#include -#include -#include "lib_rats_wrapper.h" - -int -main(int argc, char **argv) -{ - char *evidence_json = NULL; - const char *hash = "12345678123456781234567812345678"; - evidence_json = librats_collect((const uint8_t *)hash); - if (evidence_json == NULL) { - printf("Librats collect evidence failed.\n"); - return -1; - } - printf("evidence json:\n%s\n", evidence_json); - - if (librats_verify(evidence_json, (const uint8_t *)hash) != 0) { - printf("Evidence is not trusted.\n"); - } - else { - printf("Evidence is trusted.\n"); - } - - if (evidence_json) { - free(evidence_json); - } - - return 0; -} diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/XNNPACK/build_workload.sh b/lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/XNNPACK/build_workload.sh deleted file mode 120000 index a31afa92826..00000000000 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/XNNPACK/build_workload.sh +++ /dev/null @@ -1 +0,0 @@ -../docker/build_workload.sh \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/XNNPACK/xnnpack.patch b/lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/XNNPACK/xnnpack.patch deleted file mode 100644 index 7eed678b65d..00000000000 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/XNNPACK/xnnpack.patch +++ /dev/null @@ -1,112 +0,0 @@ -diff --git a/.bazelrc b/.bazelrc -index ec740f38..29f9d56e 100644 ---- a/.bazelrc -+++ b/.bazelrc -@@ -49,4 +49,9 @@ build:ios_fat --watchos_cpus=armv7k - 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:wasm --cpu=wasm -+build:wasm --copt=-msimd128 -+build:wasm --crosstool_top=@emsdk//emscripten_toolchain:everything -+build:wasm --host_crosstool_top=@bazel_tools//tools/cpp:toolchain -diff --git a/BUILD.bazel b/BUILD.bazel -index 3fc8139f..c893356d 100644 ---- a/BUILD.bazel -+++ b/BUILD.bazel -@@ -11988,7 +11988,6 @@ config_setting( - values = { - "crosstool_top": "@emsdk//emscripten_toolchain:everything", - "cpu": "wasm", -- "copt": "-msimd128", - "copt": "-mrelaxed-simd", - }, - ) -diff --git a/WORKSPACE b/WORKSPACE -index c58e76b6..30934678 100644 ---- a/WORKSPACE -+++ b/WORKSPACE -@@ -21,6 +21,7 @@ http_archive( - name = "com_google_benchmark", - strip_prefix = "benchmark-master", - urls = ["https://github.com/google/benchmark/archive/master.zip"], -+ patches = ["@//third_party:benchmark.patch"], - ) - - # FP16 library, used for half-precision conversions -@@ -84,6 +85,19 @@ http_archive( - ], - ) - -+http_archive( -+ name = "emsdk", -+ strip_prefix = "emsdk-2.0.26/bazel", -+ url = "https://github.com/emscripten-core/emsdk/archive/refs/tags/2.0.26.tar.gz", -+ sha256 = "79e7166aa8eaae6e52cef1363b2d8db795d03684846066bc51f9dcf905dd58ad", -+) -+ -+load("@emsdk//:deps.bzl", emsdk_deps = "deps") -+emsdk_deps() -+ -+load("@emsdk//:emscripten_deps.bzl", emsdk_emscripten_deps = "emscripten_deps") -+emsdk_emscripten_deps() -+ - # Android NDK location and version is auto-detected from $ANDROID_NDK_HOME environment variable - android_ndk_repository(name = "androidndk") - -diff --git a/build_defs.bzl b/build_defs.bzl -index fbadb400..e496b78d 100644 ---- a/build_defs.bzl -+++ b/build_defs.bzl -@@ -430,7 +430,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", -diff --git a/emscripten.bzl b/emscripten.bzl -index 130d5f16..2696ad54 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", -+ "-s ERROR_ON_UNDEFINED_SYMBOLS=0", - "-s ALLOW_MEMORY_GROWTH=1", - "-s TOTAL_MEMORY=445644800", # 425M -- "--pre-js $(location :preamble.js.lds)", -+ "-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/third_party/cpuinfo.BUILD b/third_party/cpuinfo.BUILD -index 128d683e..f6c287c4 100644 ---- a/third_party/cpuinfo.BUILD -+++ b/third_party/cpuinfo.BUILD -@@ -343,5 +343,5 @@ config_setting( - - config_setting( - name = "emscripten", -- values = {"crosstool_top": "//toolchain:emscripten"}, -+ values = {"crosstool_top": "@emsdk//emscripten_toolchain:everything"}, - ) diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/bwa/CMakeLists.txt b/lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/bwa/CMakeLists.txt deleted file mode 100644 index 7f7e3182506..00000000000 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/bwa/CMakeLists.txt +++ /dev/null @@ -1,46 +0,0 @@ -# Copyright (C) 2019 Intel Corporation. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -cmake_minimum_required (VERSION 2.8...3.16) - -project(bwa_wasm) - -include(${CMAKE_CURRENT_SOURCE_DIR}/../cmake/preparation.cmake) - -####################################### -include(ExternalProject) - -################ libz ################ -ExternalProject_Add(libz_src - GIT_REPOSITORY https://github.com/madler/zlib.git - GIT_TAG master - GIT_PROGRESS ON - GIT_SHALLOW ON - SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/libz - UPDATE_COMMAND "" - PATCH_COMMAND "" - CONFIGURE_COMMAND "" - BUILD_COMMAND "" - INSTALL_COMMAND "" -) - -################ bwa ################ -ExternalProject_Add(bwa - GIT_REPOSITORY https://github.com/lh3/bwa.git - GIT_TAG master - GIT_PROGRESS ON - GIT_SHALLOW ON - SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/bwa - DEPENDS libz_src - UPDATE_COMMAND git clean -ffdx && git checkout -- * - && ${CMAKE_COMMAND} -E echo "Copying pre-installed CMakeLists.txt" - && ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.bwa_wasm.txt CMakeLists.txt - && git apply ../bwa.patch - CONFIGURE_COMMAND ${CMAKE_COMMAND} - -DWASI_SDK_PREFIX=${WASI_SDK_HOME} - -DCMAKE_TOOLCHAIN_FILE=${WASI_SDK_HOME}/share/cmake/wasi-sdk.cmake - -DCMAKE_SYSROOT=${WASI_SDK_HOME}/share/wasi-sysroot - ${CMAKE_CURRENT_SOURCE_DIR}/bwa - BUILD_COMMAND make bwa_wasm_opt - INSTALL_COMMAND ${CMAKE_COMMAND} -E copy ./bwa.opt.wasm ${CMAKE_BINARY_DIR}/bwa.wasm -) diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/bwa/build_workload.sh b/lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/bwa/build_workload.sh deleted file mode 120000 index a31afa92826..00000000000 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/bwa/build_workload.sh +++ /dev/null @@ -1 +0,0 @@ -../docker/build_workload.sh \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/cmake/preparation.cmake b/lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/cmake/preparation.cmake deleted file mode 100644 index 326943c838d..00000000000 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/cmake/preparation.cmake +++ /dev/null @@ -1,49 +0,0 @@ -# Copyright (C) 2019 Intel Corporation. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -####################################### -include(ExternalProject) - -file(REAL_PATH ../../.. WAMR_ROOT - BASE_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} -) - -find_path(WASI_SDK_PARENT - name wasi-sdk - PATHS ${WAMR_ROOT}/test-tools/ - NO_DEFAULT_PATH - NO_CMAKE_FIND_ROOT_PATH -) - -if(NOT WASI_SDK_PARENT) - message(FATAL_ERROR - "can not find 'wasi-sdk' under ${WAMR_ROOT}/test-tools, " - "please run ${WAMR_ROOT}/test-tools/build-wasi-sdk/build_wasi_sdk.py " - "to build wasi-sdk and try again" - ) -endif() - -set(WASI_SDK_HOME ${WASI_SDK_PARENT}/wasi-sdk) -message(CHECK_START "Detecting WASI-SDK at ${WASI_SDK_HOME}") -if(EXISTS "${WASI_SDK_HOME}/share/cmake/wasi-sdk.cmake") - message(CHECK_PASS "found") -else() - message(CHECK_FAIL "not found") -endif() - -################ BINARYEN ################ -find_program(WASM_OPT - NAMES wasm-opt - PATHS /opt/binaryen-version_101/bin /opt/binaryen/bin - NO_DEFAULT_PATH - NO_CMAKE_FIND_ROOT_PATH -) - -if(NOT WASM_OPT) - message(FATAL_ERROR - "can not find wasm-opt. " - "please download it from " - "https://github.com/WebAssembly/binaryen/releases/download/version_101/binaryen-version_101-x86_64-linux.tar.gz " - "and install it under /opt" - ) -endif() diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/docker/build_workload.sh b/lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/docker/build_workload.sh deleted file mode 100755 index 640cca97fd3..00000000000 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/docker/build_workload.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/usr/bin/env bash -# -# Copyright (C) 2019 Intel Corporation. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -# - -readonly SCRIPT_PATH=$(dirname "$(realpath "$0")") -readonly ROOT=$(realpath "${SCRIPT_PATH}"/../../../) -readonly CURRENT_PATH=$(pwd) -readonly CURRENT_RELATIVE_ROOT=$(realpath --relative-base ${ROOT} ${CURRENT_PATH}) -readonly VARIANT=$(lsb_release -c | awk '{print $2}') - -docker build \ - --build-arg VARIANT=${VARIANT} \ - --memory 4G --cpu-quota 50000 \ - -t wamr_dev_${VARIANT}:0.1 -f "${ROOT}"/.devcontainer/Dockerfile "${ROOT}"/.devcontainer && - docker run --rm -it \ - --memory 4G \ - --cpus ".5" \ - --name workload_build_env \ - --mount type=bind,source="${ROOT}",target=/workspace \ - wamr_dev_${VARIANT}:0.1 \ - /bin/bash -c "\ - pwd \ - && pushd ${CURRENT_RELATIVE_ROOT} \ - && rm -rf build \ - && mkdir build \ - && pushd build \ - && cmake .. \ - && cmake --build . --config Release \ - && popd \ - && popd \ - && echo 'Go and find out results under ${CURRENT_RELATIVE_ROOT}/build' " diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/meshoptimizer/CMakeLists.txt b/lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/meshoptimizer/CMakeLists.txt deleted file mode 100644 index 172de8d673e..00000000000 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/meshoptimizer/CMakeLists.txt +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright (C) 2019 Intel Corporation. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -cmake_minimum_required (VERSION 3.0) - -project(bench-meshoptimizer) - -include(${CMAKE_CURRENT_SOURCE_DIR}/../cmake/preparation.cmake) - -################ MESHOPTIMIZER ################ -include(ExternalProject) - -ExternalProject_Add(codecbench - PREFIX codecbench - GIT_REPOSITORY https://github.com/zeux/meshoptimizer.git - GIT_TAG master - GIT_SHALLOW ON - GIT_PROGRESS ON - SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/meshoptimizer - UPDATE_COMMAND git clean -fd && git checkout -- * - && ${CMAKE_COMMAND} -E echo "Applying patch" - && git apply ${CMAKE_CURRENT_SOURCE_DIR}/codecbench.patch - CONFIGURE_COMMAND ${CMAKE_COMMAND} - -DWASI_SDK_PREFIX=${WASI_SDK_HOME} - -DCMAKE_TOOLCHAIN_FILE=${WASI_SDK_HOME}/share/cmake/wasi-sdk.cmake - -DCMAKE_SYSROOT=${WASI_SDK_HOME}/share/wasi-sysroot - ${CMAKE_CURRENT_SOURCE_DIR}/meshoptimizer - BUILD_COMMAND make codecbench - INSTALL_COMMAND ${CMAKE_COMMAND} -E copy ./codecbench.wasm ${CMAKE_BINARY_DIR}/codecbench.wasm -) diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/meshoptimizer/build_workload.sh b/lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/meshoptimizer/build_workload.sh deleted file mode 120000 index a31afa92826..00000000000 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/meshoptimizer/build_workload.sh +++ /dev/null @@ -1 +0,0 @@ -../docker/build_workload.sh \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/wasm-av1/CMakeLists.txt b/lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/wasm-av1/CMakeLists.txt deleted file mode 100644 index 8b1f0df0cb4..00000000000 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/wasm-av1/CMakeLists.txt +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright (C) 2019 Intel Corporation. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -cmake_minimum_required (VERSION 2.8...3.16) - -project(av1_wasm) - -include(${CMAKE_CURRENT_SOURCE_DIR}/../cmake/preparation.cmake) - -####################################### -include(ExternalProject) - -################ av1 ################ -ExternalProject_Add(av1 - PREFIX av1 - GIT_REPOSITORY https://github.com/GoogleChromeLabs/wasm-av1.git - GIT_TAG master - GIT_PROGRESS ON - GIT_SHALLOW ON - SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/av1 - UPDATE_COMMAND git clean -fd && git checkout -- * - && ${CMAKE_COMMAND} -E echo "Copying pre-installed CMakeLists.txt" - && ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.avx_wasm.txt CMakeLists.txt - && git apply ../av1-clang.patch - CONFIGURE_COMMAND ${CMAKE_COMMAND} - -DWASI_SDK_PREFIX=${WASI_SDK_HOME} - -DCMAKE_TOOLCHAIN_FILE=${WASI_SDK_HOME}/share/cmake/wasi-sdk.cmake - -DCMAKE_SYSROOT=${WASI_SDK_HOME}/share/wasi-sysroot - ${CMAKE_CURRENT_SOURCE_DIR}/av1 - BUILD_COMMAND make testavx_opt - INSTALL_COMMAND ${CMAKE_COMMAND} -E copy testavx.opt.wasm ${CMAKE_CURRENT_BINARY_DIR}/testavx.wasm -) diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/wasm-av1/build_workload.sh b/lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/wasm-av1/build_workload.sh deleted file mode 120000 index a31afa92826..00000000000 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/wasm-av1/build_workload.sh +++ /dev/null @@ -1 +0,0 @@ -../docker/build_workload.sh \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/connection.wasm b/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/connection.wasm deleted file mode 100644 index 2a2e79dc72c43d82914ca308f7bb1e90243a33be..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6379 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 M@${4$MoB~c2U0XxAOHXW diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/event_publisher.wasm b/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/event_publisher.wasm deleted file mode 100644 index 4cf911099ee9480c82a7469e939b8e524e4a31bf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5074 zcma)AO>ZPe8Lq1C>G`PfZhNzb)$S5i_a?+h5KA0<*cFmXz%C&Og!loIS-W>VJ)Rl6 zr|rcY7>Cd08v+CfN#Fny2aq^KA_pRI$PeI(KpX%egd&9tNJzl)JXPH@V|x{_ox@{4fqpq$q9Y&6YE(eO;!Xlw7tFTy)TmI*<6bCiun zlf!I@YqaMV7w^G`-rcP1O^>F%a4#1KTJoyu7D7LT{@- z-pY2p$qSC((~E3c_KQ-;g`&O5wCokx{sFc?f7{hiw3>~Oe@)S7v>P2Eg_IqkwNhb2 z?n$K@0Z7p!!A#m;zf;eIeZ9+1JU5?{od`ZoiX$cTWDL#Iy~%i*iL~QZ-p;jEENZB` zySMvWLy=qnZEG?fXItd}kK6sSFWzw;Pt$BXofN(7FdLU*tqICtJSfH6sc{>yi^-9A zqSJE{y==T4NZsr0Wc|I~?fx_iRJ$pKm0CXD`RAioKPiKm+EklHtbmxvuGB`v$N0lC zPo&0{v~P$!Rq?Z=rU4j_@8c={6xWxnIIm4$g;DXR9fLCRhKLNl>|aH`Ar!U0e+3M- zl^bDX{23>xjnWrHy(!|)lB)F^E!nOhQAqMbtSON;-11#QtVnI|f8itosA*u!s(o4U2ZBHY(k!D<>!=;4egXb$nBZd z8q9=PfNnZa3M3NfoN1$S%XCR&3!QJ7t^HkDbQkp%(@EjvR0m_u*0mDFw0Yg)J6FLFPsPF zDzU(fY%bYC(jp9yD0k*U6E4in!K+i?O=khb{^E4$)|(tx^|RD3D%qU*OxL3ZGa}$n z5U>ubY3LU07c_YYGW>50O~45e`e4kLMCtl~Q-*5s-^7eyw5UiTKvm-+cqU|>IE5`H zBmO)K!I3ag7!fLd>Ix9UE-L{QEL=^}Fegm7T)~zJ<%9|Ah6=0F4KdY;jUB?e71e|x z9d;7rl?~nW6DIN#M(KCMm{IWLZ>I(-q@-=5$khC-h`&zon)uvd^1>IfTs|XUQvrZ} zj4od)@zE;n@$tW!`vsp5?eTwteQq5V#s9|?FKH@le5lV5UX!wc!-NM&h!YG5k8y%= zc`-#oA3-Lo&T_{>WF<#dM26ONfkr~uWH)}EayNwXJ0kuT*Bc`A>r3^zg>}F<1}=`Z zSQq55<~e5~djahkBcjKg9kdlYMAfV?XbyCzHj(bY!RlOmUE-uhHDQ1u^cOzBD&c|0 z(?z;6S{L2;JI+BA%bGYBf7>k@Iqi8CJh@JDWdms_QB;FzfKkK}QC`J{>T z0;?7ZMG@Ua?$%qEuz-fp6{b6-6-Km*S!l`%JmEXxq|z@-sTN+u5Ak9RUU=Z4jVs(W z#*kK*Fgna;{DIRG-TAn{$$t z2`3FsPH0ApyB9IY)g{a*bBXsA9QhGPfn8@6L)%o#UgZ>~rdlZ!HW>-hpnIOBvq znx9)0^5ma@bc6E_=9#tgI0~T$#}`5~((Aw`wN7O#b#v|1)BX zP_Z!J17rPD#ya(HdhTSRL2NrZqIu*?U(R_GT5W)a!zAs{kBld|j z0oc*=2oGMHAXlI3Jec57Wrx)OZ(QfqO{dQT2Mob!K*V%=59;GI=3o;DB)Mn;I`G_D z1^cn!S%VdPqiy{=h3dcNcB~nu>M{4|D$_^u`xFAIm*7}EJAsQF^!?{9PVR7`ht4&+ z>mlBRyYw!F2CeP0r*#;VEC2#*04_u<#u3THQS~cS4eZ>TqgbjDeRdIuLQkB7;dC>SKV(0Y}VkJWFU|(R?IT&ZFtA(Q3vhtNv4Ft zqF@cX5Y5G+;th&&@rwj^+0_}|r0mr^{w^sj6e|*@6Yhj->T3KI z=aGoN=iNzg3Wak^=){9Xh~r@@D_hdO>Ck?aQk;s?c60l8((J$8&U4(k%wFgw%0AD0 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 diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/sensor.wasm b/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/sensor.wasm deleted file mode 100644 index eb51ec8eea7c70fcbe738584c41635823e5b3ccf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4027 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 diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/simple b/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/simple deleted file mode 100755 index da9c485ed4dd470df65977507b94beb7dea17dba..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 368240 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
rs+wt6cP_ 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 M@${4$MoB~c2U0XxAOHXW diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/sys/event_publisher.wasm b/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/sys/event_publisher.wasm deleted file mode 100644 index 4cf911099ee9480c82a7469e939b8e524e4a31bf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5074 zcma)AO>ZPe8Lq1C>G`PfZhNzb)$S5i_a?+h5KA0<*cFmXz%C&Og!loIS-W>VJ)Rl6 zr|rcY7>Cd08v+CfN#Fny2aq^KA_pRI$PeI(KpX%egd&9tNJzl)JXPH@V|x{_ox@{4fqpq$q9Y&6YE(eO;!Xlw7tFTy)TmI*<6bCiun zlf!I@YqaMV7w^G`-rcP1O^>F%a4#1KTJoyu7D7LT{@- z-pY2p$qSC((~E3c_KQ-;g`&O5wCokx{sFc?f7{hiw3>~Oe@)S7v>P2Eg_IqkwNhb2 z?n$K@0Z7p!!A#m;zf;eIeZ9+1JU5?{od`ZoiX$cTWDL#Iy~%i*iL~QZ-p;jEENZB` zySMvWLy=qnZEG?fXItd}kK6sSFWzw;Pt$BXofN(7FdLU*tqICtJSfH6sc{>yi^-9A zqSJE{y==T4NZsr0Wc|I~?fx_iRJ$pKm0CXD`RAioKPiKm+EklHtbmxvuGB`v$N0lC zPo&0{v~P$!Rq?Z=rU4j_@8c={6xWxnIIm4$g;DXR9fLCRhKLNl>|aH`Ar!U0e+3M- zl^bDX{23>xjnWrHy(!|)lB)F^E!nOhQAqMbtSON;-11#QtVnI|f8itosA*u!s(o4U2ZBHY(k!D<>!=;4egXb$nBZd z8q9=PfNnZa3M3NfoN1$S%XCR&3!QJ7t^HkDbQkp%(@EjvR0m_u*0mDFw0Yg)J6FLFPsPF zDzU(fY%bYC(jp9yD0k*U6E4in!K+i?O=khb{^E4$)|(tx^|RD3D%qU*OxL3ZGa}$n z5U>ubY3LU07c_YYGW>50O~45e`e4kLMCtl~Q-*5s-^7eyw5UiTKvm-+cqU|>IE5`H zBmO)K!I3ag7!fLd>Ix9UE-L{QEL=^}Fegm7T)~zJ<%9|Ah6=0F4KdY;jUB?e71e|x z9d;7rl?~nW6DIN#M(KCMm{IWLZ>I(-q@-=5$khC-h`&zon)uvd^1>IfTs|XUQvrZ} zj4od)@zE;n@$tW!`vsp5?eTwteQq5V#s9|?FKH@le5lV5UX!wc!-NM&h!YG5k8y%= zc`-#oA3-Lo&T_{>WF<#dM26ONfkr~uWH)}EayNwXJ0kuT*Bc`A>r3^zg>}F<1}=`Z zSQq55<~e5~djahkBcjKg9kdlYMAfV?XbyCzHj(bY!RlOmUE-uhHDQ1u^cOzBD&c|0 z(?z;6S{L2;JI+BA%bGYBf7>k@Iqi8CJh@JDWdms_QB;FzfKkK}QC`J{>T z0;?7ZMG@Ua?$%qEuz-fp6{b6-6-Km*S!l`%JmEXxq|z@-sTN+u5Ak9RUU=Z4jVs(W z#*kK*Fgna;{DIRG-TAn{$$t z2`3FsPH0ApyB9IY)g{a*bBXsA9QhGPfn8@6L)%o#UgZ>~rdlZ!HW>-hpnIOBvq znx9)0^5ma@bc6E_=9#tgI0~T$#}`5~((Aw`wN7O#b#v|1)BX zP_Z!J17rPD#ya(HdhTSRL2NrZqIu*?U(R_GT5W)a!zAs{kBld|j z0oc*=2oGMHAXlI3Jec57Wrx)OZ(QfqO{dQT2Mob!K*V%=59;GI=3o;DB)Mn;I`G_D z1^cn!S%VdPqiy{=h3dcNcB~nu>M{4|D$_^u`xFAIm*7}EJAsQF^!?{9PVR7`ht4&+ z>mlBRyYw!F2CeP0r*#;VEC2#*04_u<#u3THQS~cS4eZ>TqgbjDeRdIuLQkB7;dC>SKV(0Y}VkJWFU|(R?IT&ZFtA(Q3vhtNv4Ft zqF@cX5Y5G+;th&&@rwj^+0_}|r0mr^{w^sj6e|*@6Yhj->T3KI z=aGoN=iNzg3Wak^=){9Xh~r@@D_hdO>Ck?aQk;s?c60l8((J$8&U4(k%wFgw%0AD0 z*gqm7m>%EcR{Wy{L;N*9Lq}X^_EBN~g7*^?nJcIGWio)|t5M^ueBZn;e>v}wdFXv# zqJ|m5*vHZRc6Gm8=ONcaIHxvQFuyvZq-t*F0LjN!%l*{AyO9a3V)-+KtL_)D|3S>M zMJJpfE^O(ag;Ln#mi}@0UUzq4`ej-02Y=ZgjI+Yr=?`|Z?d!(fuHbIN_-llU{^W}I zSXMfjIVbK)JORJ?--7LbDjeKCfVtZKV0_r$9c-Jy7+?$MImNfQsVa0?zSv`n*N04Sfx3@)GUmOCfq9}4l>wQHuoH>mGce4zb> zm6P61lEesH4~-|KxidiA%AL%VMSnc)yK5J5Fy6y$4B-2Fo64rZRZDeAblqehACym; z@x%b&;b1E>JN@zYF7Bb`vhJ3r7WMZw_xi_ NG?eRHUH5LB$k=?;jI&||yBS-GCdx`kTPR*Ipae+nz3MIUlYt;2ap}}mF`=t+f`>KXr-LWI#Y9ZZ5?&DFN&H9hZ(`L7!m&LZr3u+Q zEG22&55jyh@caF!l}+q}I0%T0(jXYL219bpWEgkC^ngk{S%Rn5ksmLdv7QmJ=k{or zNuGKYsGD(c*h$hL#vqACaVvMfYJ|yXzZr~!FwJ6~F^h*m+DuN8X4+}>nuCOvIOv)Y zrJVshwfwLZ^fQz7!a5?Pew>o9o>(W_b{vNUIYN}ET$a*y#861-Sb{|932P$s-EDV5 z`sXYB#CYkpsFbklC_a(oMj;~}Mqv`r*@~GRj}U-9v4+VENWZ`Dw|ex{I@VfI7zVAh zgJIiGefrF4jFKQsqB!5=rHDHr6HlA5+*NdWh4i~`K;W6Bb4n=E2Qu zmVWTSI<7ek1Y!%Apr;7lV7>(t+hCI2hJ0V>J2|5F7l@>`x>b_9AOEXt6F^V8s}&N` zvYpaW`BcSarwG)LO23`^REtd_bd{DftxeXtsDGPlT`XwXtaZxxdY0%pYghkqhK~wr zWmYR2wQY9xb^Z5T?Ost$u-eiB*;W1K_cQ+Q7u5{3l2Q8{(eIwOhWb~z-d~G)2ApH` zK2P+#H5K}UTyMHykF$-i_6(gC#|?Q)=#O&MTSZla&@!rEs3GqP{m)$QZb2_gV8)>| z+J?h-gno;YkAixqpbZ()tqoiOZGFGgkZ1A!1>>>khBM%vF#4;Fdj#|KI zFh7b>-uWsv!Mq#h#f#=Fv0;q4 zNkM&YzN7_C6r7EydSq$Rt+E#Mr1z~X8DNK}%7L&};vDEYXRlOsRO#{xm#A{~Rs_Ec zJFM$nXJcbY$}vXY=&r7jc=(54?I61xp4mR_YM{V^;*5yQ%X#-CD70>APF18nJG6V@u>_(szO;%w-f=i>#`lpGisOwg`?g0WNrn|2uj{}*t6@N z<|2|fay^8_!WV>?$lW=Pnm}M{7YGDvaR~UpxV#4SDbZ>8WGsSXyMJ2L61%v?TQT1Y zM%`=B4c#q;T)M_5kAPnc?Vw5C?85RO8!+< zy_%eTR6!1tBE8$J3CjOf_~MzG%m}?<*f5_`PM^sexXtl>f#dT+4_AaQbxjdzDvG=3Y| z0@{vYc>GviGaUlqrp&-|H2{Gyg#a2MfT59rDN|DLjy;JQL*eS-wlS5-6>8LBmRBFT zT6Oay_#a$4kFYzhqP*ENqJNYV{T|w5_K!?Xv|@e%5e%1g$uvtwSvkus*6k_~0E5{a zQ)YWVHZ0&A!DrC`M=32!7dy#~Q5FBslD@LS-OXEuCDM2MVPqf`!sWbY_z0fwdzHZ; ziQZ2bgL?`6r#~!M0|03AOe314=)YuL=>5PLxKEP)J?m?;AMaxZ2b|A`NyI{&A?J?OOJXgeN-{2zF|6~#f_9}c$O0KYpe~720T5=oSBvqgP0&UU0%g+EVGsFxXMaQ52_JYV7w% zm|eWKaji0!;U4sON#og~tlux#?VqGUQCJX-;PX=BF~Wm>-Ldq-K{Yb>MgUL7Q+7iUV`A+EKx^PWp@rBb5a4 zxYG*Mksr4ELA?BDUb!vqRonP*w&^p6Px?le+=dVz0)HgLmz7eV zP|vA@PT1efkCM3A8w!^jy+*e?Xo_4WX^n@r;jYGECEO~C<$Xcj0WSl znF{x@a5P?74mZPoVn?{caWb-Y4zYYKOqNGmqvfRC>@4?2BA@x|hW*reFYGmkTcTiL zp#hAO#wbi|;{cmW+C2biHu}x5Yds#E=?B215hp^DDJwwNaL^xx%cHR0vQsa>VQ;V* zrcQ=&yPvG4BEWC1H)0^G>KuMV!7UWsf{?;3NGWmxjhrY6QBumy$)R+doFj$Izr)#< z=F)<c)~nJgE-}Up@5!tznzHVWU&Qv@nB2T%F8@r8FO}|x4gU_HipY9 zjZx^RQc(&cJ$2$_`H>s+^+F4CIKf9TF*`f|E^Nf~ylHmcayCe`8OPrLrR2|8ijBYN z?dd2(!+&sRXGeIiNa<`FQFYXkmge9G<{&yDgn3(T7CBO(<)kt}4`?7p}EZS8y;did7nrtE)pK%|wUM zfCX1A0bA}28+Gf-uSicTBk+Xps^e+Ldx&NMEiteBKp8&@9RGfcnZ~(BE(&~+++7ra z3QV%-f0yO#%?X^@OR)geeWe?N~vWD`+W- zl3=Q}@DAgNW(R)Lr^6H%>HS_xcN@gZ2yPYSNbT&AsUjN%~@5N!R}z z4d#(T=XlUZqJ0O1-2EdkI)@A;_mnaFJp&Zz(3E-7S~=ov*~K6Y2zcQF3|A>zmFquD zUI<+VQea{Z+8`=$&dh<4Dv|)|jurszdCXx|@f0PIKs>Weii)Hb5++-Q-hRXdjsWEg zN`U0hfTr)SDxqXqbMUF{x+Bz(AIPH7@k9jycJIpinZ=D&jECVfdy0~`JqspmT2{|Y@|HKGKk9Daf~CqO20WK~iDNasoQ zh^wVEZ;B{T>B_=9&9_l=vUKHj;~=ui|2%s}&ALV8sdSk?i>NM8XEdWxSce2D-I*{a z?;sIxp{4=$-Ym)z%1hQy`NLTd@HQ(^dQoo8Gblx~2%w&$s;oAkZ(iFYWrMkSp#qd^ zRAZBmfkyIoYB(`D@uAnz8;oaU+}IxH_XxY~nMD>~VbW)+5EI)#R`&%mXra20^4#bn(h z>kewPJ_ z*?|#0P*I2xGJNg`A52h!UCLm=8BC6;!q8jIY=waeDvUkm!k3$-E;cC+7_AV>TfEqC zg`s}VjKTi*d2=CryqWxL&k$5! zp!R;8m$_{Jx{T!_ugAb09!8|SH8W02PyyC)D7z%hKe3j`?4mp6s_1*8g;x*^ z!dNitrlBI=$lFO15ve-n39P+rVgT;g=+Rb#$T?}`uryIURCF9ea5QAQI1Nhk08aRX z=%pzlt}=pRbhTdugwg{++gBD+Ic_drD3(y?CC8_(w0StSsi%{K>#C?&Ed;Kv7R=MB z*20Vy#j#RiTQ>@Ele1)A&hVjtWQ>7Ns1;ca8B|vvHkVViOS5XI+M-gJBD>f8D^RD+Xq#6OB&(3I5L5DWO z#X^zha=xw(<<#X+U~b>vL5OrZuCbDz77=Q{t&l>I=fHQtBrOyYzbTe#vxxSF6!`n zJ2|QQ13e1k&2}@?>y3V^8^+VIte6coci(;Hu6xeid51o0&VA_2t&95D=(uhq{MBvu zLw&3z7DR1*&sB;Yz@Oj zJz5{c$#K2e=#J4^IDhPXc_PCt?zJWL8)s$R?##HAtt6Zk&WOgad8&R5;c9o#n0h?6 zIz`eNj90o-o3o;o!JvB$d$_u7_tz#uA|RVKLDY>nZfqUbxHn%**1-yxdVd@?NV1E^ zG@^@|FZfArub|WZlXK$kFyS#1Od+AVzJRvqxy z#y$L>U^D|@w?0k7_Dpg@w?|0wMr+XTZq1C_?c!=4Zo`bGREhoai=sA;yQlc`w4jxsk@nM-Ic#hpPg(+*d`fWMo}%Z|_W887z%F>M>x_K>i<#K9wz4-30Gg+60w5;B|vgRXxux~yF350 zJv|%mgBTsLINp5iiJ3YKgkCl$jyfwk+9&vjUXftLJ{VBRoydfJ1eo4 zr|aj{d*A!st5?-c;kYk|NPN<}B=+f&+{cfz&%Xuy@>A@KeKUjyrtwSoUo^AabGgN% zB;OTBooKLI94B!v8jx!`{jk>?HnUFDZ;tk;kcn}p$Q^exjv^wv0z&>+DWNa5N zJ_E3gtte@X_r{H+-Rw5{W18b73udYrM`03SrXR(2wH-GDjb=D#Mm=ldxRJNxaWqcC zI3Y1pG#ZYRMjY)-FlEP!qqsdtHZ9gUU}|oMF<^aQ$;Drh3WZYP2nmuT1eHZuO1B_J z!f^_YAW?k4*%$g&&D$sahhzMU_S`F?TtsIF1~7q$EfSPd->JUwLrpG%3c@zJcEhQP`L3idLjsmHq+#sOoTcvFdj81D$HY|B4wbo}VXG z)MAbBV1d#a32xOy#lOlTA17&N$p0qy>*U)0Qr0h_?`YAfI{MBXXD3@$!LXaj9EFkN z9VPweSch^tY|A%@{AYRSgc7PyNAOh9E5kwmt32x66vElp6gcok=;NOPS~^3d?}!~O z9_L<-D*m@ww(3G19reFuI)x6~vm$6!g>pMpSMPVQ8p|ZB5p`MOR*j@pQI{3&uaIlC z01x*{0WSc$MV`&3me7F)SFQtFfq9h5txLZmJS8=ug=gS+%JF_Igq(TdzmFFy@WKLj zwV&e7FuH6thtXiZAEQX^Gpr2bq5wo@(EZCjCb zoQ!YiIZP6KW$wrjfCr?(l=o*L+~=PV6s}|Sn3*QK`|&Oq%xRC7G0PZ{4gxDtp7F62(uE- zm_?uO99=+lx$BRxx_~TU^BlEfo(2jGD2}YKT26XxIErEEzsOnxA=h;!-Au5d4=_yr z^E`J#(=iXiU~EPeCk9~+xW3L@R|N+L8ael25YuKHZ0_0A7gO1Qb5pwhORQajhl~ya zg%0{F65IUzJh%^pav+X94|+VHz*Ha&nS$x&_!&E#4e*AoPdA-+3^-s2PG4bD-Y1YB z_hNR|fk3bnn}80qOA8P`Aa)x)_{O%qpG#!_DKn$}Zq+$$nv6v+rp&p(^mdLpMg{Yn zYOY}nJ$3=x&3}PSz&~sY>@h1=0u~UhD;@t8p008zewI^+N@NO($vf-Hucq`{M+j^> z>lJ1T%0US8ZiE7XW#9~hrmtL+m@Ed@S?n#=#ZCR>LM}{c$s0u<-fShy~3>+or zsUqQ%gRO8Ka8ix{rYiORxP$-L zE^e29K64WII{s_yDQ~BAng2r`08dkH{+LS<)vd}|iYQJk>3^43fP|kS_p|MFUo7Ds z5}Pxfvme1sv-kpb1Z3 zUj2)YpL7Gx*k#kd&+FkI3_Q*wBad*+IW~jF*|f6eR`g&ak>)W`_0|RKq@9HY2~@g?>CFM2Bm)A z7Tv1I(n@iV^&8)q<&qK#m$44-pj$#8V2^?heM@xwuQUD=;Fl!VR(Pk2of_e~!5t(y z7GX@{c7b$wlE=7%9hG$<960)B&KlEZ?n+fY(RgQbu0l=`v|;%wmZ1I_y>)p*=$BGN zH)e>Wc5qH|=-%%iwkBW3a84dAlaP*ED9)9Rl)1LCp}JK1)l{dNISJDNRjkwsOP$qk zrc!5fQZ7p!F}fZhI){q#c7~5~VkH(U88MvHb@@5{*Hr9QUW||X%G?auCH*W&XZ~;J z#SFBf5&J07Zy$9=`X{N}-}775YCssmW$2k`U#$)8}*RJ)Xef4TwlxY#zSQ*@RPt zi+m>QvJXUN5_UyaD0Xqq&*}u(?E;_QVffnNiVb_;OLv4e7kB+Pli08GAVi&s4GTW+hU2)xil?zpRtwI@8^bv_&!;cbQ8BtYn1C)9ZS7$!> zBwwQWb%HnOIfrk|&N+wlj~D=s6Uz**tC%f~^;(z3A`$n!dhw*ep5{H9vXkN9a ztMN5qFig~D8+MZINabW`GDr>D_xW@U;T3#}D7xHE9#Vs$8b|SNyBVqNaM0@Ev&D3+ zdHc_n>ZhJM|AnV7KKX>Ypf7&*{9|isdAzE^#5{WKL8O*jbe3w{!+un|Jn2jZwXHUP z!Wa!}{Hfzizuk<7XX43#za-R}!#JviqtThoIP6Ey4CAip4Z@_o8=V>B(?-;)g-H_g zM}{PX{`jFLm1((Erl-R#wvP8*)s6PJNvkT^8%1ksygiJQRka)TCg`2LynMMlox|6Y z!)NM`?h_q3im)5rbosHGnOFI?59=A$W5kCwP$OlR&C01h7Bi4K>q{z!Ik#_ diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/sys/timer.wasm b/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/sys/timer.wasm deleted file mode 100644 index bcd4c8fa4cdaeb7e3a758c469818fc368db65d5e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2468 zcmZ`*%ZnpL82_reJCjK#GnH}Bbr+;Mvtm4~a|JrGa#RRrNi7-?N(1Vl0SAJYKsj zW^`H3@Cau7jPT?)w#3Zs;U$&Y#r(zE2YDAT+o!93gU;ALBO zi?ag8dPm)HL2J%jQRX9?c^j3n9rwml0BNc!!Rz()N+pUSA*2i=F~uti1c}Oh!AzK6 z9*t*YZmjbY^xAb%V+E7^Oj10_x_~g9WQC>sYi@OX0!;Kk6N{xAqtTVLcSMaX?DZyD zW_#rTWIruadTsZb`b zi}`}X2>XurycR|cy z8fwo1swH$dY=vevgfzsEolAt=SDD%+=~Z-Oo!4y&y%zY)t7^gmQAcj`>GJ3t7F<0p zeG%7-)L};|&Yk3fQg|mptb_P7bQu>-;Ji@(;YAx>c;F#|>T$!C!x*yF+b}xJ_hLkj zoPCD1#JKIig&rJ1Gdx`3tFQ3=E<`v3XfcGaH`EA;qC^S}w%D$y)`lk6O|fu7kpRp0H{4-+5&23J`evQT~MqJR<& zk$wgqG^j3Pc(M@oIs0EpdbYuZvyepk{=74N2r3Tii!sXGz4H61)eQb=RUa#}eg-3d zEUvr`cPH^EzGW^xLhO8z{d|v-#UN+9yb#<>!G@WBY^~J-6-~;R$VD9h8shY@!RBpALFfUrn?A N2%ktRS;x2({TJv(^uGWA diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/timer.wasm b/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/timer.wasm deleted file mode 100644 index bcd4c8fa4cdaeb7e3a758c469818fc368db65d5e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2468 zcmZ`*%ZnpL82_reJCjK#GnH}Bbr+;Mvtm4~a|JrGa#RRrNi7-?N(1Vl0SAJYKsj zW^`H3@Cau7jPT?)w#3Zs;U$&Y#r(zE2YDAT+o!93gU;ALBO zi?ag8dPm)HL2J%jQRX9?c^j3n9rwml0BNc!!Rz()N+pUSA*2i=F~uti1c}Oh!AzK6 z9*t*YZmjbY^xAb%V+E7^Oj10_x_~g9WQC>sYi@OX0!;Kk6N{xAqtTVLcSMaX?DZyD zW_#rTWIruadTsZb`b zi}`}X2>XurycR|cy z8fwo1swH$dY=vevgfzsEolAt=SDD%+=~Z-Oo!4y&y%zY)t7^gmQAcj`>GJ3t7F<0p zeG%7-)L};|&Yk3fQg|mptb_P7bQu>-;Ji@(;YAx>c;F#|>T$!C!x*yF+b}xJ_hLkj zoPCD1#JKIig&rJ1Gdx`3tFQ3=E<`v3XfcGaH`EA;qC^S}w%D$y)`lk6O|fu7kpRp0H{4-+5&23J`evQT~MqJR<& zk$wgqG^j3Pc(M@oIs0EpdbYuZvyepk{=74N2r3Tii!sXGz4H61)eQb=RUa#}eg-3d zEUvr`cPH^EzGW^xLhO8z{d|v-#UN+9yb#<>!G@WBY^~J-6-~;R$VD9h8shY@!RBpALFfUrn?A N2%ktRS;x2({TJv(^uGWA diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/ui_app.wasm b/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/ui_app.wasm deleted file mode 100644 index ddda9e2d3b2df8c35f2aafec7c0d5557445c1404..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1953 zcmZ`)J#!m35M2PrPmm%=#&Ik+pw5|i#!cL~a7Bz_B}K+5(qz&=NAhGJbvi2KiHc@2 z!?fv=Ka%lJaN)v53KcF~r0`7A`9~xV07XfWb2G#(cCl}F-!6`nERGoAX;&v_c~%_0 z=tmI|`>ejtRubNh^Xpr`p5q{yKfL_LukZc(%CC22?N{FGS$jNNlr}4ndQoN|hCZ&_ zSpiK}Qmg00P@Us(guYQnIpt|Kd6t$oU8Y4zw;GePViyO{z1z(Td705C@^X{Wor-JB zLlIT&cy>~hqS6Y2_0)@MbG=1JMXh0WN1Qa>;~l95@jsbjq%y89L%KM&gl(9=teFO;T zoG+>VW}~_g6`(h0Z!R6l+zCOUbB+}_GQ+28>pqW6Q#IujoPCftu<{T4!PLHthJhG_ zdF2>!Yp8jL`O>s|LI3_LUm;-7s-8oT-=j&UX>c=CZNN=S@g4TWH{tG7iETq5A4Z3X z7Cqt-Uf9(E^45pkA>`t9zO7LD(3(jD(l3uW)Q;psJ`^~QN;SDEAYllew0Vn3iJuGS zl=Uu=eEk0tq(QhZ)V(5ukwBNKngHkPdhCMp0sFx4t+NefIaiRc>OK?AK#9+r4=}Jd z=2r7C5|~#<1zxJ+=d5nr01LoyAUqAh9fH0x`5KeILGXDy1lLgz3U^e}3NK{aC);o+~97QQMY0LBnAIN?0H zvqj@$@H?*SPO9e2st7qot)++%={!%rvlmHVJ+|3MqjZk~+~^@9iWImL0TljH2- UGwlDpbog`B2T7Js27`hA7k$EpLjV8( diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/vgl_wasm_runtime b/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/vgl_wasm_runtime deleted file mode 100755 index fa68f3a2d029cb9a52f48b27da192cd5e9ccf4c4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 512936 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

+Yan-y)=euy)7Vq*iLrvm8>v3DYGB^H{A0!5 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%0DN#iuBm`Gwu-vT0iOq42lzSQLx6d$(e{AN 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

454e2dpC`9@K6jqx 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 diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/wasm_runtime_wgl b/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/wasm_runtime_wgl deleted file mode 100755 index eb7b42b821115c9596080ba822504887903bff18..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 591680 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

bjhXX>*dcHs^jMKCfO=C ziYdrRM5|{|6fDI?9*QaBs^qAY2xR#eYHts%AMCBO@)|Ag$-HyBr-&QW#ez?l6#1je zmGggOGYqh$Qhb<+1u%<6fPBsp+x{>btW5VzJjmh&K4dYX$JL-#3b8Re*#tIrwXnf* z+@Y_~1MAjgdZ$z14DR0Z^dbhcQe!$7=m^Pg7HU|QiqjRJW{cL)T0T{pVZ@SOkA`&Wn9)Qh1mrgqh?B5ze%s3W_IN~r~WO{|E(2DHx$S_8vhd>SzYm% zW4=Spjy{^lV1Yg@t2(rzl&ZbtDwHpELJ=) z|3TyH^}MuBRD`GF)l!y-0DFw}4SXo8Cb+c z4LMzFXOlE<(`TMg`yOx4wZ6KiR9Wf&vH~q4Hd3bpEG@O2qH$H@LaA|VMM3Su-McT| zkQ!VL{bh(xRt9L=u05(at3XTJkFp!ADg~0hH)f=7X2A0rmP!{>v@X*HJ!Znc)}c8ze1{^ zlF%2&d$yFWfrwKsy9D#W P8g+flZAm-A8RRJ$WBF@>>Ze-(Z{SrLgb&Zti( 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⪼X`;6=1hTEDPnyzAJKbJz+R;S#@5u7`?hkqvjVXULt$KK(+i;SRLx^~1l` z7v<=edzJ^6%5|?_YvHG1VFsJb;{}faE>~-qnNilJ{rFDC7=_REM+IB`bsarq$!VMg z%t4S{qpuIOdw957i-bKG7nT%VgB|ruOfHluW@@<6Cs*C|*4KMGK0{LC!0nHPi-L3{ zgXFf$`YQI|pqdf{bB!-KzU_@p<_>YT6op#3+*vEuEPjL|MFO0QIxhP#vlH6Sn&n}B z0t`kl1Dr{;?;yw#nE*x-5wk#etq^utTZi`~&*!oy2irOP?WZ{BJ$nfmXVtiUMFHuv z1wO8b&eK9flb1ciT$lMvsT(;*19RB|IKT&a%&DQEHLmg{m6*eSus*2d%U2kuPrQ2B{G)y;%!Sl$j`W zY={;a#gjCH?J)6w72@WK$3#aZqBmaqp*&t9e!363`+yTGSIxd6h@i>=YlXF=8?E*h$&<_ouDGcdB2t z$fby75ilYO(x$QbFdspAL=L6RWL`#N&hRbzzw{5Aj-OGoZ}`5|E}Axi5$x_L+owHp z7H<{N+@cC`A|A_92j4Dae&xKwN&rANbA+TObxa`yv@6si%S1I|%9^dO8NMZSl;xK} zTfEWhiiKhsU_Dxe)wblnG%r9GUS2LeyI2Y?RPC0AE{^$f)EIMrAady*Nn4@_5}T2S z;dDmPec}Q>*La*s%iP2|5ulcQ7JQUck}|XFW*6m}M*4TU=<;&aKQNPY%uzZG2KtzgF<&f^~uK zO@r?Sz6G{7V7)IF5MI!yZvrpoG(VS~1?fDo!qcXzsm5luHAGbVaetjWL0e%3H$Ypx zviv%2#Yx_)%#&rKvP0jb!gJN=fudRFWh8M4au=+8!{1VJSX|@i~^dA>(<0*Kgr}m%*L&T;r zzs}Vz-&nFac1Htdt}N}rf0IG0|8dcFDRM^}i9NN4E+BKcR^Q>?r`5kyv_n2!))qVr z7`bODc3C^wfb(_9hS+_;Vdeke;|k78MW0EA`+&oO|DiGqPQraytAEwPYLTj9;SXbr z0FnU6@sbW-Y;uD)cqnV(RLS-Q5J+hw1rTrXhUjkexjE_`D7uASxJ9eq+_XJUv3A|t z`c@YI30I=$#$_AHn}9=a;s0p!7N`|lv_aa@^o1w>WbCpHTKxv1)|fM(Uu+t0fbp2e z;eh|tPt`0K{!2eutn_o1P_a8K62IjT_#v?dh0F`7+P%?yUh0ZXR!#S6mmhLku03=H zIED6H2(}6LakHObc%Mz?gAS1&k~k}&uOw54`)l)Q-i#hU6KyI;%kA^fJ+%6PrERs? zXePUf7=r?W0+sr{qKCF(U`?51STPypc4h_{tZ^m!l%~F`G76p(?;%a~K}Y6NrVcIq z9CiAm*A?go#@b|1 z_VuDmwE78yLhYHgKg5qZ+r3`DxrkG#m_j%oF`WQbTpAklJU|Td%*?JwPdJt+^@r@> z5UjVjU$BrHAPcL?+G~FaoYslM$dNkl$61nBW!^+*p5fD0T!JEUCp8edo$JRXxZTT0 zV8p;iZsDD7d?msIJnpEA;L%X>2#}`>NDG7wlgydqu=*i|y4h2T75!AY*xC>3dgi4|uW;y9 z7LGrs8#s7QG`UU|nEDnk*Tk|yp@W{IdDJTF4An(*$VnHewu$#iw?5jc`Y6BbYwe-4 zq-(8y;+z>Tknf&sulsF@-dXR@mVTeLGRt{ZalAppQNZx35UQ>IHG9`H3_-CD zwGrIlVEe4G?Gp$En{7C4T0|Wgv&OG#XRB8M6MiV!AZPF4;Cy0{d6p}ND%4)s6!m+W zj(B1-dgV0jVmhdXW>b6CRb$(knp0QJKFiczb=4kRiF?;oWTB4wiiW78>pki!vei0F z3CNn|jFZ`2#)%N-eWYq?oN#^xQW(vgY*mDjO%=sYRqi7)82lq9Fk)EiqRBD5A+Wi@ zQVD#Nh)!TZ^7bUYmO5XF9+wup2#%3Hgp{Xxm(@h=g3#DG62Nm zsdvFT{*m)8^Ox*Ubdie8RSZB68R^Q7z|Bz%yiI=hq1ZIHwi*|u#b@el6m|{dUkevA zEDP*;(Wk9$OyRACi}(y;X~>V{RUbH18Zch)4+NNNp5Y!qwY@4wUp*xo;*Z$#us%>* zoqsZ|Zw`m%)ju%c;uwzsK0H`IP{s3~*V_C|yd4A`jm zb+`H4jiwh7<+NX0?KxR*CXW<9BE_wPm$7LX`al|ydopud*U!}yk4?)2qk1rUKfP)# zQp!i_?l0AEr+Uv&*Iq7`Th{J!4R+~$y*(R!`ue8!?4g1b$iP|R-J4tw*ih5jsYN~` z1H@ABGAOI}9oopw4MpXEgi-cmb+|JO?v_5|c=OYB8ha@}2+TTju7SQ#iKpNjr zcNMqly|y`7_h)jZionQ3n4#*mZf~O6RW`fGbLW?`$jnKu1#3?c{e=B*XB`L{<>2vI z{C(rHX!>AD&hOuPcR}!Cxe7}$GJ)=5BS$H8jsi^GTR{7)gFk`~=zxbO$W48L*wmiav$^LHy)FI=8y;n(e7jXXTZW8XzWrit#gW{genb`0+sx~!(s)BpZ?WZ1 zpdWfV7`Rxge@8#g5~Jyhf>`cAitWl-w%rA??u|`GLClj;J6M)xIUQ>gwR!TC_Y5l! zS1r2`1#9$leOkgG9zcnft)Ew<^VAkA_uD&OQkR0TKVBWv_KcG=%U=ch$42k045=^W_Ki9&al8a$L zfx$3CqU0mQ%YfV5E)05D@U-|4{CSoXoyW@15c5047=r>)thXr;TKIRA2jXaIlC?M{ zR@p>|W&QjusSYcX#zeiYc9l1DybseEKe$IcMj`QMT+Xj3gUE(mQp1_kIun@E#?CGp zq&*_kFWIoFkRQ1t#l<;Kt$vf2Nh2Ru-x6=xd$nI;H7SO8gY|vd3iR!oNTc2s%RNJ@ z*lM8{5e{c;^rpO^9sfYIPprHq92lTfN&| z*+Jd{<0-T&4sjGhcI2#z@ipOc+2EmFu^D|_?q+&RyL=az=5h|RXwjc_Lw2bKi|^d! zhFM0>sqy>m^;ux`X2T>Nj0HH~?cN1k0Sasdw;}!~1*c@U`MFH4ABVpw@4BuhDLq$3 zWAsT&S`qJ1LCF1{dSFPt$-~q5nbjL=7!s`Ar&X*EUL@3Im8_b*xiheP~V+|ZCGp-OVxPYli2Xv<=$_+ zj*?m9Ez7R)YE!cHPiwq-wwm0k*oyGV?m_KyD7up}rsxNWkY%ZLvFZ3B=3vi?S+-AI!d~h={X{uZ_C{$Soz__UVti9_{=U+yV&Ee7-?ha) zf-cASTkxnfjo`F$y7mve`IOw?Ft(e(TUk?C3MTR<#XN;RBGVVDeq-(H4SmJf5A<>A zTSIX-2CzOZzTfpZSm)@ikc~P28YT=|%kf@ke&>NM_8|J#*&mZjP-PlY_!J60u`ydW zWFQ1NBP*BIdJ_Xd3QPSZu_Z%Yyve4KF?_wZZ0(}6FsH|R+Hzn2IF^43w+VAbYJh7( z9WG>LYZjVd!B)`<}P1*ju`B$yQVxYd&kq9(nLnuTsg)MGUf4GGo-} z1IZ8+)V?u46^MW+W9Rnp={w-NbHv2$ z@#-Jb-`-7MR%kD*y)4GG!*KQ{-itKe-x}zpa@M|w)di{%);8VU4kBCls`ZTchu7$1 z8iO1;{0k0H$nz87iyDYS;j%C5Xh#>}xtLw3BN>4+>3Ieo=P4_R&UF*e0&`0?Th}Tl z2FSa#WpSG1oX_HlT?_%3)E1S6B8i_>8f!}J8b#E^fU|%TuXpe_#{N~#l@o+uX`#Nx zc#}5-$58YBo`~@ltv+kJJVgU7IThj0h_`^KmNU17vNf=Ps6AT!>v%rE;bg5RD*C?1t6#lEA6;a)Ik*-b&6ezntc8@+n|T^=8&4db)(>iz zwdiYVn&O&!&B`F{tJ!q4X4&{__#DJqcv;qT$=I|>71Va=w5Z+N4d9avWG zFC1=4^zgY`fmw0ZYm|pTjb6PCw^~Em?1f<`!?$=h_OM+NC+?`cz7 z-~@@UzDskr=|{vx3z$u07~bq|l^qtQjppIatf=IE&H}l4l(x<&8pKTwM1;a4tw;%2 zEc;j;GL1m92S``sHO`WQkquk$XDdSJ;rHhh2K{TSQOCuz`U6v2(PscZ z$ZJ(IHFYi(ES9w77~|vsK>h1{qfaFo&@}=vES3ZBeZ)Hwe#gm>@zk^<(|G(j$-Ur$ z&=&`L?ysA5!8OW1UP&fQ)l84TH;e0FUm}APCTFEELD;A15<^;*>w9i=k7i!mM6?Z*=VcB(5xz*eD*~~GfQ6zZOvxvaoeahy!U6;(uf5z|Lcu`_I@}x?iI}D@X z1>hUnPH@d6on)bGe(@OCTJlz(TNr;YHUCjAC*IQKJuhD0<-H*Or_{TWuS|@cYGNch zvP_Iu4ipswt5}QD)W&~tFNb&}M2R{V;17*|QxdpTna`_Bp{7WOzlUV3%f$>@_$EH= z*Y3;e_>*X*V=lzNOBTXX4*fHVT)*-h`S>*-N%~NJ`f+P`EbDjY^(DB_1$!k1CMF^) z#1}zxMjHbJcx=q$?5s&$7sxA)%(alm==rRQkfGK4p;j~gNEg6&IE?mOUpMgrt^N{N z=paXit=AP3iUC-RY4d!3&*yivRIp#W{gNE5-=!dS`xOORzvG=2rKk}q%Ge=K1v##zaZDH8q!>iDBm3&EPhzh5z~ve2mzA#_d0}qBt|| z$g@fET%MNa1Icr#%9ETwaI`S$o|YDmH}0mBIlyl6t3~qBR>8rzS3c@lZ;)uZNRtC4 zl0F?WneUL0;w?x2Qam+}a+tR-5K=Ox)8|VjN$x%8)Y**y?J`mNxku<6sW3YJQocb{ z<1Y+bUdQpu{53LsEU|1yCyi>!8cLG8HoK$Zf}FrGj-CzRUH-`=>Q9?Q@0YaD+F6LC zn&rXqyBCwK_H7R37(Dr{+oTI!a4>6`a}@xDJKX6$MB@mD+Q@T-V1WcCE?LF-F!9JI zg^5u^4zfe{ed(ZL&vN{`9gFyl`w30ks3z;~OsQq=f-v1o+!i_#}#%uVFXw?iL% zK3M}nB1`^Q>j7tsa*fvhayA>G+59fVn#IM$1IAGY+9D=`k<#v2Y3*)>eQ5Xmu9}0b zXQ3AvjenAXgx1+&`~V~gUKJF#g{{yacobLhC)5Mp;}59^md@8AN`puHS^h2(DdV@0 zEqFA$Hbg`Zkr0DaolA3gEVLf;cpPp$5@Il%Z#@?BsA7ITeJSk zv;3>^hVBF1a6|@0ENjaF880Ir<*QlS1svRj-Ncr$k)^CW4-<&I?Id_COXlC?&@ zw`9G-kK25YmP#ZKISt(zJOUg16+A;m|ED{($bA41dY{T~xKRt=#;My6XRNO-a&yX8^f=Ad()On}~CjzH- zh5R!ha{%!VsyHEt7bAk|vJM0gV#Ie$lUWvuXM>{oDj$|BAuPC^L=x?%Lfc#uhUM%xV zH-A($|Lpj^`hNbmeP3gJKT&x{e@oYMA0<1o2c^h31&N|JN;L%JTG6V0R0`lMqyv~F6(BOqfVTA!dxk~gw&$E7a+eL|X z*-|bPm=?e_@?H@CN`CUsSpxQXzRT~=FRvGw`#$H~XSvRGu5)eYI_s5Mx$>=-^BzDTp`9oIC z{8OdkiN1u2$o91JwBv7rGB~;Wc|pDXgC$n;WPV8y5MqnrTiR+K;n}}*%9rINmLJ<7 zCRO~_hkJXiT|D{ARN4M?rVq}ZllHIAC_B`V>(QKY5*13lkj6AVJO5qu6=o8fk_Gfi zGxxiC#1XXBjIyckYpc3~i4W*XDcr}ylgn|emFlE((75kN0{d1-3b#sIyB$-e_RiBz zrbueM!o1Ew$C8qiM{8=nEI;%Fi>RVC@}wss73w`!9curflOLo#�E%?%X-(`MIf` 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

Zp=LsZlr+kFO|_LWoOf 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

-O+C&fu~A!) z8hAPHWpLi;hV*QAE5jZb#YIK+M(~<#Fut^$EqmXEQR525w?#zJE&|H?+I-@eiQ~xS zN{%HYh6NOP@)h(9UBom3$Qw>N1SLA~$R^oz#6oZg7?F#s)h)EAYzwG)E!Zz)HAys% z1tttC8O;Yhwhe_fNgn#~pMp^n9)91*jsYgyjF;@9^^t?lCY8c;06+NwZW+GNP?$&} zc)J@Y>6}zowhSuT!bpZ(jHi~!#8BXYHijmg55mZ@w7YCbQ9u!eo58FWE1=7<34zMGUzr?7h)BM2yK8=&4&i;*|4!y2B+D+;eU)Mlx0 zzu#r$NaJ)OH?Q^^eM=I2f~qn#Z0+jG=~Oz@w0HWWA z!`Q|sD{Sm?%UBnrphhCnGMdD>&_RchIAYc~jAy6_-b;t2Oxdt`aYoB24Umt&rNyb0 zlNq11kqHd=Al*94l#}Ob0T5lh>a?0u_(l$rm;i^Bl8;o&T3Q!!j)bYuzm8Jf+%5H~ zu$_31{Skx;x;1Y;)&E}N@_9Gn*|^H&?ZPD(rS`CFia*eBR!^KHj!Jz zWaQBiOUJp~Q`j5Tem~$GIMTsAj$#U&=(US_tL>q?`rMZHMT%$ zKjjmFS#MBG*jnkZ!7Z|Y90?(xx~G3o3kb|HOGJ@|4eQx8f>8eJ3nK#MLEf-CZKd$H zaX}W%{t0tW>ahaIiHlU=3NQS&Bb&;m=bL48ax!)ZZ|Xwz6Y2qsO+(F19@0*309#0B zc(Ljc_s|+qH!1#GT2kOwfXNSGe`=RG_MVRwD?nQM0B+IP*`v}i%r?6s7al#K)kj%L ziF*Q?Y0;RinMk-v3%3vF_yST(dos4R>!6N3`8;VH=_Q>)#|q~gyZb|sFu}%Y!PdzK zDvQV?LrlD3FyerD^9sEZ%k_*wtVIm&IAp9*LBrhak&p#>jS@F)Vmda-6_@^92}>>t z(h7$*ae~AR%}nOBn-JFMQ`B0v71_1)!2KkhQ3YzyZn9LW5FaFjl&jNh?ZjP@SQdNH zgbVFuw%>8w+mk@XA2@`hE4ETgMO17oLgITkQ)5}g+lkkR+z#c^yotX*qi+4ge`bkr z>p(~|B%%-=alr>p0WqrsCsnv}GBT|FzFqUoVDrmxV{0AV<7O-S%JxC2oEVnGolwkP zu8Bp92{rCwj%iiyze9-=$ytdriSmgwl;=?f6QFOPZH4^AdH~nIKtN(e*%Fp&g!7s{_I^X8gnflLP57{DJ%)5soQwbZ8~o=);} zm?4RdD?72PSoMGgpXv&FPuk-bgzZ>=W?WY-CELpA;qBB0A-lFC>QOZ0z~X7+#dWQk z!?nPjSS+FBl5J31L>w7>q1|@ItGIqY(}5iXUVX?KVn5We^GFPb0*5w1bAWuI9+*K3 ziae?&_J@1#{V%rAKssq2xe;vL>>`I%`6NC=c7#6=2<2UgYVe4BVXZb8Bg_=c!SfQ=PL|L?y)jShYf{{MTuqaXT1{QjBI z0IXa7`wMva{rG>h|80MW-@jN^#`BMj-Y@Z9wtx9^Rw4b4>W|yMf$#tGM?c!c_^*2V z_~m#0`*Hi3eBOWK=RG|9A^bnu|2=OXzu)}BR`d7ahii}aKVij_zky#iiT0oWf_;eJ zf5F8S|Hkn9X?*)pG5=rpj^p=bZxHj3apLzm+W$_`{x|=m4HmzeG>SNX!Y<}-wI-8~ zy*&E+%|B&d;`f8M?LEei_Obq-@%FD>+-)1TOxuJ==`i|2)dLM9xqDw)HRR zv;4<3l>dGfFJ=3ey?y+S;s261j^A&O+W+9zD#UNh*PEsJNBJ*|+W*ko$M0Wy5|FbV zV%+HOmqzVB|9z_;zfOKp{fK}5nYR!8O+NAQ{P*IQQ&T;>T)$3!74L*!w13bUCgS(! zzF0RH!~b86+JEv7tbP1`@L%ip0kz Mh>3cG(d*>@0zQoTT>t<8 diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/build-wasi-sdk/build_wasi_sdk.py b/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/build-wasi-sdk/build_wasi_sdk.py deleted file mode 100755 index 4c6789116de..00000000000 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/build-wasi-sdk/build_wasi_sdk.py +++ /dev/null @@ -1,299 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright (C) 2019 Intel Corporation. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -# - -""" -The script operates on such directories and files -|-- core -| `-- deps -| |-- emscripten -| `-- wasi-sdk -| `-- src -| |-- llvm-project -| `-- wasi-libc -`-- test-tools - |-- build-wasi-sdk - | |-- build_wasi_sdk.py - | |-- include - | `-- patches - `-- wasi-sdk - |-- bin - |-- lib - `-- share - `-- wasi-sysroot -""" - -import hashlib -import logging -import os -import pathlib -import shlex -import shutil -import subprocess -import sys -import tarfile -import tempfile -import urllib -import urllib.request - -logger = logging.getLogger("build_wasi_sdk") - -external_repos = { - "config": { - "sha256": "302e5e7f3c4996976c58efde8b2f28f71d51357e784330eeed738e129300dc33", - "store_dir": "core/deps/wasi-sdk/src/config", - "strip_prefix": "config-191bcb948f7191c36eefe634336f5fc5c0c4c2be", - "url": "https://git.savannah.gnu.org/cgit/config.git/snapshot/config-191bcb948f7191c36eefe634336f5fc5c0c4c2be.tar.gz", - }, - "emscripten": { - "sha256": "0904a65379aea3ea94087b8c12985b2fee48599b473e3bef914fec2e3941532d", - "store_dir": "core/deps/emscripten", - "strip_prefix": "emscripten-2.0.28", - "url": "https://github.com/emscripten-core/emscripten/archive/refs/tags/2.0.28.tar.gz", - }, - "llvm-project": { - "sha256": "dc5169e51919f2817d06615285e9da6a804f0f881dc55d6247baa25aed3cc143", - "store_dir": "core/deps/wasi-sdk/src/llvm-project", - "strip_prefix": "llvm-project-34ff6a75f58377f32a5046a29f55c4c0e58bee9e", - "url": "https://github.com/llvm/llvm-project/archive/34ff6a75f58377f32a5046a29f55c4c0e58bee9e.tar.gz", - }, - "wasi-sdk": { - "sha256": "fc4fdb0e97b915241f32209492a7d0fab42c24216f87c1d5d75f46f7c70a553d", - "store_dir": "core/deps/wasi-sdk", - "strip_prefix": "wasi-sdk-1a953299860bbcc198ad8c12a21d1b2e2f738355", - "url": "https://github.com/WebAssembly/wasi-sdk/archive/1a953299860bbcc198ad8c12a21d1b2e2f738355.tar.gz", - }, - "wasi-libc": { - "sha256": "f6316ca9479d3463eb1c4f6a1d1f659bf15f67cb3c1e2e83d9d11f188dccd864", - "store_dir": "core/deps/wasi-sdk/src/wasi-libc", - "strip_prefix": "wasi-libc-a78cd329aec717f149934d7362f57050c9401f60", - "url": "https://github.com/WebAssembly/wasi-libc/archive/a78cd329aec717f149934d7362f57050c9401f60.tar.gz", - }, -} - -# TOOD: can we use headers from wasi-libc and clang directly ? -emscripten_headers_src_dst = [ - ("include/compat/emmintrin.h", "sse/emmintrin.h"), - ("include/compat/immintrin.h", "sse/immintrin.h"), - ("include/compat/smmintrin.h", "sse/smmintrin.h"), - ("include/compat/xmmintrin.h", "sse/xmmintrin.h"), - ("lib/libc/musl/include/pthread.h", "libc/musl/pthread.h"), - ("lib/libc/musl/include/signal.h", "libc/musl/signal.h"), - ("lib/libc/musl/include/netdb.h", "libc/musl/netdb.h"), - ("lib/libc/musl/include/sys/wait.h", "libc/musl/sys/wait.h"), - ("lib/libc/musl/include/sys/socket.h", "libc/musl/sys/socket.h"), - ("lib/libc/musl/include/setjmp.h", "libc/musl/setjmp.h"), - ("lib/libc/musl/arch/emscripten/bits/setjmp.h", "libc/musl/bits/setjmp.h"), -] - - -def checksum(name, local_file): - sha256 = hashlib.sha256() - with open(local_file, "rb") as f: - bytes = f.read(4096) - while bytes: - sha256.update(bytes) - bytes = f.read(4096) - - return sha256.hexdigest() == external_repos[name]["sha256"] - - -def download(url, local_file): - logger.debug(f"download from {url}") - urllib.request.urlretrieve(url, local_file) - return local_file.exists() - - -def unpack(tar_file, strip_prefix, dest_dir): - # extract .tar.gz to /tmp, then move back without strippred prefix directories - with tempfile.TemporaryDirectory() as tmp: - with tarfile.open(tar_file) as tar: - logger.debug(f"extract to {tmp}") - tar.extractall(tmp) - - strip_prefix_dir = ( - pathlib.Path(tmp).joinpath(strip_prefix + os.path.sep).resolve() - ) - if not strip_prefix_dir.exists(): - logger.error(f"extract {tar_file.name} failed") - return False - - # mv /tmp/${strip_prefix} dest_dir/* - logger.debug(f"move {strip_prefix_dir} to {dest_dir}") - shutil.copytree( - str(strip_prefix_dir), - str(dest_dir), - copy_function=shutil.move, - dirs_exist_ok=True, - ) - - return True - - -def download_repo(name, root): - if not name in external_repos: - logger.error(f"{name} is not a known repository") - return False - - store_dir = root.joinpath(f'{external_repos[name]["store_dir"]}').resolve() - download_flag = store_dir.joinpath("DOWNLOADED") - if store_dir.exists() and download_flag.exists(): - logger.info( - f"keep using '{store_dir.relative_to(root)}'. Or to remove it and try again" - ) - return True - - # download only when the target is neither existed nor broken - download_dir = pathlib.Path("/tmp/build_wasi_sdk/") - download_dir.mkdir(exist_ok=True) - - tar_name = pathlib.Path(external_repos[name]["url"]).name - tar_file = download_dir.joinpath(tar_name) - if tar_file.exists(): - if checksum(name, tar_file): - logger.debug(f"use pre-downloaded {tar_file}") - else: - logger.debug(f"{tar_file} is broken, remove it") - tar_file.unlink() - - if not tar_file.exists(): - if not download(external_repos[name]["url"], tar_file) or not checksum( - name, tar_file - ): - logger.error(f"download {name} failed") - return False - - # unpack and removing *strip_prefix* - if not unpack(tar_file, external_repos[name]["strip_prefix"], store_dir): - return False - - # leave a FLAG - download_flag.touch() - - # leave download files in /tmp - return True - - -def run_patch(patch_file, cwd): - if not patch_file.exists(): - logger.error(f"{patch_file} not found") - return False - - with open(patch_file, "r") as f: - try: - PATCH_DRY_RUN_CMD = "patch -f -p1 --dry-run" - if subprocess.check_call(shlex.split(PATCH_DRY_RUN_CMD), stdin=f, cwd=cwd): - logger.error(f"patch dry-run {cwd} failed") - return False - - PATCH_CMD = "patch -f -p1" - f.seek(0) - if subprocess.check_call(shlex.split(PATCH_CMD), stdin=f, cwd=cwd): - logger.error(f"patch {cwd} failed") - return False - except subprocess.CalledProcessError: - logger.error(f"patch {cwd} failed") - return False - return True - - -def build_and_install_wasi_sdk(root): - store_dir = root.joinpath(f'{external_repos["wasi-sdk"]["store_dir"]}').resolve() - if not store_dir.exists(): - logger.error(f"{store_dir} does not found") - return False - - # patch wasi-libc and wasi-sdk - patch_flag = store_dir.joinpath("PATCHED") - if not patch_flag.exists(): - if not run_patch( - root.joinpath("test-tools/build-wasi-sdk/patches/wasi_libc.patch"), - store_dir.joinpath("src/wasi-libc"), - ): - return False - - if not run_patch( - root.joinpath("test-tools/build-wasi-sdk/patches/wasi_sdk.patch"), store_dir - ): - return False - - patch_flag.touch() - else: - logger.info("bypass the patch phase") - - # build - build_flag = store_dir.joinpath("BUILDED") - if not build_flag.exists(): - BUILD_CMD = "make build" - if subprocess.check_call(shlex.split(BUILD_CMD), cwd=store_dir): - logger.error(f"build wasi-sdk failed") - return False - - build_flag.touch() - else: - logger.info("bypass the build phase") - - # install - install_flag = store_dir.joinpath("INSTALLED") - binary_path = root.joinpath("test-tools").resolve() - if not install_flag.exists(): - shutil.copytree( - str(store_dir.joinpath("build/install/opt").resolve()), - str(binary_path), - dirs_exist_ok=True, - ) - - # install headers - emscripten_headers = ( - root.joinpath(external_repos["emscripten"]["store_dir"]) - .joinpath("system") - .resolve() - ) - wasi_sysroot_headers = binary_path.joinpath( - "wasi-sdk/share/wasi-sysroot/include" - ).resolve() - for (src, dst) in emscripten_headers_src_dst: - src = emscripten_headers.joinpath(src) - dst = wasi_sysroot_headers.joinpath(dst) - dst.parent.mkdir(parents=True, exist_ok=True) - shutil.copy(src, dst) - - install_flag.touch() - else: - logger.info("bypass the install phase") - - return True - - -def main(): - console = logging.StreamHandler() - console.setFormatter(logging.Formatter("%(asctime)s - %(message)s")) - logger.setLevel(logging.INFO) - logger.addHandler(console) - logger.propagate = False - - # locate the root of WAMR - current_file = pathlib.Path(__file__) - if current_file.is_symlink(): - current_file = pathlib.Path(os.readlink(current_file)) - root = current_file.parent.joinpath("../..").resolve() - logger.info(f"The root of WAMR is {root}") - - # download repos - for repo in external_repos.keys(): - if not download_repo(repo, root): - return False - - # build wasi_sdk and install - if not build_and_install_wasi_sdk(root): - return False - - # TODO install headers from emscripten - - return True - - -if __name__ == "__main__": - sys.exit(0 if main() else 1) diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/build-wasi-sdk/patches/wasi_libc.patch b/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/build-wasi-sdk/patches/wasi_libc.patch deleted file mode 100644 index e236735b40a..00000000000 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/build-wasi-sdk/patches/wasi_libc.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/expected/wasm32-wasi/predefined-macros.txt b/expected/wasm32-wasi/predefined-macros.txt -index c1bb19e..954f3b5 100644 ---- a/expected/wasm32-wasi/predefined-macros.txt -+++ b/expected/wasm32-wasi/predefined-macros.txt -@@ -3002,6 +3002,8 @@ - #define __alignof_is_defined 1 - #define __bitop(x,i,o) ((x)[(i)/8] o (1<<(i)%8)) - #define __bool_true_false_are_defined 1 -+#define __clang_literal_encoding__ "UTF-8" -+#define __clang_wide_literal_encoding__ "UTF-32" - #define __inline inline - #define __restrict restrict - #define __tg_complex(fun,x) (__RETCAST_CX(x)( __FLTCX((x)+I) && __IS_FP(x) ? fun ## f (x) : __LDBLCX((x)+I) ? fun ## l (x) : fun(x) )) diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/build-wasi-sdk/patches/wasi_sdk.patch b/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/build-wasi-sdk/patches/wasi_sdk.patch deleted file mode 100644 index 0fc4caee761..00000000000 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/build-wasi-sdk/patches/wasi_sdk.patch +++ /dev/null @@ -1,15 +0,0 @@ -diff --git a/version.sh b/version.sh -index 8e7c44c..ff0d3ba 100755 ---- a/version.sh -+++ b/version.sh -@@ -1,5 +1,6 @@ - #!/usr/bin/env bash --set -e --GIT_DESCR=$(git describe --long --candidates=999 --match='wasi-sdk-*' --dirty='+m' --abbrev=12) --GIT_PACKAGE_VERSION=$(echo $GIT_DESCR | perl -ne 'if(/^wasi-sdk-(\d+)-(\d+)-g([0-9a-f]{7,12})([+]m)?$/) { if($2 == 0) { print "$1.$2$4" } else { print "$1.$2g$3$4" } exit } else { print "could not parse git description"; exit 1 }';) --echo $GIT_PACKAGE_VERSION -+#set -e -+#GIT_DESCR=$(git describe --long --candidates=999 --match='wasi-sdk-*' --dirty='+m' --abbrev=12) -+#GIT_PACKAGE_VERSION=$(echo $GIT_DESCR | perl -ne 'if(/^wasi-sdk-(\d+)-(\d+)-g([0-9a-f]{7,12})([+]m)?$/) { if($2 == 0) { print "$1.$2$4" } else { print "$1.$2g$3$4" } exit } else { print "could not parse git description"; exit 1 }';) -+#echo $GIT_PACKAGE_VERSION -+echo wasi-sdk-13-eng diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/debug/README.md b/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/debug/README.md deleted file mode 100644 index 36fbc5d6ec6..00000000000 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/debug/README.md +++ /dev/null @@ -1,13 +0,0 @@ -### If you want to enable `source debugging` for this extension, please build `lldb` firstly following this [instruction](../../../../../doc/source_debugging.md#debugging-with-interpreter). - -### After building(`linux` for example), create `bin` folder and `lib` folder respectively in `linux` directory, add following necessary target files into the folders. - - ```shell - /llvm/build-lldb/bin/lldb # move this file to resource/debug/linux/bin/ - /llvm/build-lldb/bin/lldb-vscode # move this file to resource/debug/linux/bin/ - /llvm/build-lldb/lib/liblldb.so.13 # move this file to resource/debug/linux/lib/ - ``` - -Note: For macOS, the library is named like `liblldb.13.0.1.dylib`. - -### Then you can start the extension and run the execute source debugging by clicking the `debug` button in the extension panel. diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/src/debugConfigurationProvider.ts b/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/src/debugConfigurationProvider.ts deleted file mode 100644 index 8fd539c85e2..00000000000 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/src/debugConfigurationProvider.ts +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2019 Intel Corporation. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - */ - -import * as vscode from 'vscode'; -import * as os from 'os'; - -export class WasmDebugConfigurationProvider - implements vscode.DebugConfigurationProvider -{ - constructor() {} - - /* default port set as 1234 */ - private port = 1234; - private hostPath!: string; - private providerPromise: Thenable | undefined = - undefined; - - private wasmDebugConfig!: vscode.DebugConfiguration; - - public resolveDebugConfiguration(): - | Thenable - | undefined { - if (!this.providerPromise) { - this.providerPromise = Promise.resolve(this.wasmDebugConfig); - return this.providerPromise; - } - return this.providerPromise; - } - - public setDebugConfig(hostPath: string, port: number) { - this.port = port; - this.hostPath = hostPath; - /* linux and windows has different debug configuration */ - if (os.platform() === 'win32' || os.platform() === 'darwin') { - this.wasmDebugConfig = { - type: 'wamr-debug', - name: 'Attach', - request: 'attach', - ['stopOnEntry']: true, - ['initCommands']: ['platform select remote-linux'], - ['attachCommands']: [ - 'process connect -p wasm connect://127.0.0.1:' + port + '', - ], - }; - } else if (os.platform() === 'linux') { - this.wasmDebugConfig = { - type: 'wamr-debug', - name: 'Attach', - request: 'attach', - ['stopOnEntry']: true, - ['attachCommands']: [ - 'process connect -p wasm connect://127.0.0.1:' + port + '', - ], - }; - } - } - - public getDebugConfig() { - return this.wasmDebugConfig; - } -} diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/src/utilities/directoryUtilities.ts b/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/src/utilities/directoryUtilities.ts deleted file mode 100644 index cff54c7f022..00000000000 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/src/utilities/directoryUtilities.ts +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (C) 2019 Intel Corporation. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - */ - -import fileSystem = require('fs'); -import vscode = require('vscode'); -import path = require('path'); -import os = require('os'); - -/** - * - * @param path destination path - */ -export function CreateDirectory( - dest: string, - mode: string | number | null | undefined = undefined -): boolean { - try { - if (fileSystem.existsSync(dest)) { - if (fileSystem.lstatSync(dest).isDirectory()) { - return true; - } else { - return false; - } - } - - if (!path) { - return false; - } - - let parent = path.dirname(dest); - if (!CreateDirectory(parent, mode)) { - return false; - } - - fileSystem.mkdirSync(dest, mode); - return true; - } catch (error) { - vscode.window.showErrorMessage(error as string); - return false; - } -} - -export function CopyFiles(src: string, dest: string, flags?: number): boolean { - try { - fileSystem.copyFileSync(src, dest); - return true; - } catch (error) { - vscode.window.showErrorMessage(error as string); - return false; - } -} - -export function WriteIntoFile(path: string, data: string): void { - try { - fileSystem.writeFileSync(path, data, null); - } catch (err) { - vscode.window.showErrorMessage(err as string); - } -} - -export function ReadFromFile(path: string): string { - try { - let data = fileSystem.readFileSync(path, { encoding: 'utf-8' }); - return data as string; - } catch (err) { - vscode.window.showErrorMessage(err as string); - return ''; - } -} - -export function WriteIntoFileAsync( - path: string, - data: string, - callback: fileSystem.NoParamCallback -): void { - try { - fileSystem.writeFile(path, data, callback); - } catch (err) { - vscode.window.showErrorMessage(err as string); - return; - } -} - -export function CheckIfDirectoryExist(path: string): boolean { - try { - if (fileSystem.existsSync(path)) { - return true; - } else { - return false; - } - } catch (err) { - vscode.window.showErrorMessage(err as string); - return false; - } -} - -export function checkFolderName(folderName: string) { - let invalidCharacterArr: string[] = []; - var valid = true; - - if (folderName.length > 255) { - valid = false; - } - - if (os.platform() === 'win32') { - invalidCharacterArr = ['\\', '/', ':', '?', '*', '"', '|', '<', '>']; - } else if (os.platform() === 'linux' || os.platform() === 'darwin') { - invalidCharacterArr = ['/']; - } - - invalidCharacterArr.forEach(function (c) { - if (folderName.indexOf(c) !== -1) { - valid = false; - } - }); - - return valid; -} diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/tsconfig.json b/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/tsconfig.json deleted file mode 100644 index b65c745109c..00000000000 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "compilerOptions": { - "module": "commonjs", - "target": "es6", - "outDir": "out", - "lib": [ - "es6" - ], - "sourceMap": true, - "rootDir": "src", - "strict": true /* enable all strict type-checking options */ - /* Additional Checks */ - // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ - // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ - // "noUnusedParameters": true, /* Report errors on unused parameters. */ - }, - "exclude": [ - "node_modules", - ".vscode-test" - ] -} diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/.clang-tidy b/lib/wasm-micro-runtime-WAMR-1.2.2/.clang-tidy similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/.clang-tidy rename to lib/wasm-micro-runtime-WAMR-1.2.2/.clang-tidy diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/.devcontainer/Dockerfile b/lib/wasm-micro-runtime-WAMR-1.2.2/.devcontainer/Dockerfile similarity index 69% rename from lib/wasm-micro-runtime-WAMR-1.1.1/.devcontainer/Dockerfile rename to lib/wasm-micro-runtime-WAMR-1.2.2/.devcontainer/Dockerfile index 5ddba8f3ef9..7ccfa2467f6 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/.devcontainer/Dockerfile +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/.devcontainer/Dockerfile @@ -12,7 +12,7 @@ ENV TZ=Asian/Shanghai # hadolint ignore=DL3008 RUN apt-get update \ && apt-get install -y apt-transport-https apt-utils build-essential \ - ca-certificates curl g++-multilib git gnupg \ + ca-certificates ccache curl g++-multilib git gnupg \ libgcc-9-dev lib32gcc-9-dev lsb-release \ ninja-build ocaml ocamlbuild python2.7 \ software-properties-common tree tzdata \ @@ -20,6 +20,15 @@ RUN apt-get update \ && apt-get clean -y \ && rm -rf /var/lib/apt/lists/* +# +# binaryen +ARG BINARYEN_VER=111 +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 \ + && rm binaryen-version_${BINARYEN_VER}-x86_64-linux.tar.gz + # # CMAKE (https://apt.kitware.com/) SHELL ["/bin/bash", "-o", "pipefail", "-c"] @@ -31,25 +40,26 @@ RUN wget --progress=dot:giga -O - https://apt.kitware.com/keys/kitware-archive-l && 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/* + && rm -rf /var/lib/apt/lists/* # # install emsdk WORKDIR /opt RUN git clone https://github.com/emscripten-core/emsdk.git +ARG EMSDK_VER=3.0.0 WORKDIR /opt/emsdk RUN git pull \ - && ./emsdk install 2.0.26 \ - && ./emsdk activate 2.0.26 \ + && ./emsdk install ${EMSDK_VER} \ + && ./emsdk activate ${EMSDK_VER} \ && echo "source /opt/emsdk/emsdk_env.sh" >> /root/.bashrc # # install wasi-sdk -ARG WASI_SDK_VER=16 +ARG WASI_SDK_VER=19 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 -fs /opt/wasi-sdk-${WASI_SDK_VER}.0 /opt/wasi-sdk \ + && ln -sf /opt/wasi-sdk-${WASI_SDK_VER}.0 /opt/wasi-sdk \ && rm /opt/wasi-sdk-${WASI_SDK_VER}.0-linux.tar.gz # @@ -57,29 +67,29 @@ RUN wget -c --progress=dot:giga https://github.com/WebAssembly/wasi-sdk/releases ARG WABT_VER=1.0.29 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 -fs /opt/wabt-${WABT_VER} /opt/wabt \ + && ln -sf /opt/wabt-${WABT_VER} /opt/wabt \ && rm /opt/wabt-${WABT_VER}-ubuntu.tar.gz # # install bazelisk ARG BAZELISK_VER=1.12.0 -RUN mkdir /opt/bazelisk \ +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 \ && ln -fs /opt/bazelisk/bazelisk-linux-amd64 /opt/bazelisk/bazel # # install clang+llvm +ARG LLVM_VER=14 +RUN apt-get purge -y clang-10 llvm-10 && apt autoremove -y WORKDIR /etc/apt/apt.conf.d RUN touch 99verfiy-peer.conf \ && echo "Acquire { https::Verify-Peer false }" > 99verfiy-peer.conf -WORKDIR /tmp +WORKDIR /tmp RUN wget --progress=dot:giga https://apt.llvm.org/llvm.sh \ && chmod a+x ./llvm.sh \ - && /tmp/llvm.sh 12 all \ - && ln -sf /usr/bin/clang-format-12 /usr/bin/clang-format \ - && rm -rf /tmp/* + && ./llvm.sh ${LLVM_VER} all # # [Optional] @@ -96,17 +106,28 @@ 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 --user black nose pycparser pylint + && pip3 install --no-cache-dir black nose pycparser pylint + +# +# Install github-cli. It doens't work as a feature of devcontainer.json +RUN cd /tmp \ + && wget 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 -# set path, PS and clean up -ENV PATH "/opt/bazelisk:/opt/clang-llvm/bin:${PATH}" -RUN echo "export PATH=/opt/bazelisk:/opt/clang-llvm/bin:${PATH}" >> /root/.bashrc \ - && printf "%s\n" "PS1='\n[ \u@wamr-dev-docker \W ]\n$ '" >> /root/.bashrc \ +# +# Install NodeJS +RUN curl -fsSL https://deb.nodesource.com/setup_19.x | bash - +RUN apt-get install -y nodejs + +# set path +ENV PATH="/opt/bazelisk:/usr/lib/llvm-${LLVM_VER}/bin:${PATH}" +ENV CC=/usr/lib/llvm-${LLVM_VER}/bin/clang CXX=/usr/lib/llvm-${LLVM_VER}/bin/clang++ +RUN printf "%s\n" "PS1='\n[ \u@wamr-dev-docker \W ]\n$ '" >> /root/.bashrc \ && apt-get autoremove -y \ && apt-get clean -y \ && rm -rf /var/lib/apt/lists/* \ && rm -rf /tmp/* # set workdir when container run -VOLUME /workspace -WORKDIR /workspace \ No newline at end of file +VOLUME /workspaces +WORKDIR /workspaces diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/.devcontainer/devcontainer.json b/lib/wasm-micro-runtime-WAMR-1.2.2/.devcontainer/devcontainer.json similarity index 87% rename from lib/wasm-micro-runtime-WAMR-1.1.1/.devcontainer/devcontainer.json rename to lib/wasm-micro-runtime-WAMR-1.2.2/.devcontainer/devcontainer.json index 976f5beb753..24e1bdfd61f 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/.devcontainer/devcontainer.json +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/.devcontainer/devcontainer.json @@ -1,6 +1,5 @@ // 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 { @@ -10,7 +9,12 @@ // 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 "args": { - "VARIANT": "ubuntu-20.04" + "BINARYEN_VER": "111", + "EMSDK_VER": "3.0.0", + "LLVM_VER": "15", + "VARIANT": "ubuntu-20.04", + "WASI_SDK_VER": "19", + "WABT_VER": "1.0.31" } }, "runArgs": [ @@ -27,12 +31,10 @@ // Add the IDs of extensions you want installed when the container is created. "extensions": [ "dtsvet.vscode-wasm", - "esbenp.prettier-vscode", + "llvm-vs-code-extensions.vscode-clangd", "ms-python.python", "ms-python.vscode-pylance", "ms-vscode.cmake-tools", - "ms-vscode.cpptools", - "twxs.cmake" ] } }, diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/.github/scripts/extract_from_release_notes.py b/lib/wasm-micro-runtime-WAMR-1.2.2/.github/scripts/extract_from_release_notes.py new file mode 100644 index 00000000000..3802d92113c --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/.github/scripts/extract_from_release_notes.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# + +""" +Extract the latest release notes content from RELEASE_NOTES.md +""" + +import argparse +import os +import sys +import traceback + + +def latest_content(release_notes_path): + """ + can't change the format of the original content + """ + content = "" + start_extract = False + with open(release_notes_path, encoding="utf-8") as f: + for line in f: + if line.startswith("## "): + if start_extract: + break + + start_extract = True + continue + + # hit a separated line + if line.startswith("---"): + break + + content += line + + content += os.linesep + return content + + +def main(): + """ + GO!GO!!GO!!! + """ + parser = argparse.ArgumentParser(description="run the sample and examine outputs") + parser.add_argument("release_notes_path", type=str) + args = parser.parse_args() + + ret = 1 + try: + print(latest_content(args.release_notes_path)) + ret = 0 + except AssertionError: + traceback.print_exc() + return ret + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/.github/scripts/fetch_and_compare_version.py b/lib/wasm-micro-runtime-WAMR-1.2.2/.github/scripts/fetch_and_compare_version.py new file mode 100644 index 00000000000..ac206cadec3 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/.github/scripts/fetch_and_compare_version.py @@ -0,0 +1,123 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# + +import re +import shlex +import subprocess +import sys + + +def fetch_version_from_code(): + """ + search the semantic version definition in core/version.h + """ + major, minor, patch = "", "", "" + with open("core/version.h", encoding="utf-8") as f: + for line in f: + if "WAMR_VERSION" not in line: + continue + + major_match = re.search(r"WAMR_VERSION_MAJOR (\d+)", line) + if major_match is not None: + major = major_match.groups()[0] + continue + + minor_match = re.search(r"WAMR_VERSION_MINOR (\d+)", line) + if minor_match is not None: + minor = minor_match.groups()[0] + continue + + patch_match = re.search(r"WAMR_VERSION_PATCH (\d+)", line) + if patch_match is not None: + patch = patch_match.groups()[0] + + if len(major) == 0 or len(minor) == 0 or len(patch) == 0: + raise Exception( + "can't find the semantic version definition likes WAMR_VERSION_*" + ) + return f"WAMR-{major}.{minor}.{patch}" + + +def fetch_latest_git_tag(): + list_tag_cmd = ( + 'git tag --list WAMR-*.*.* --sort=committerdate --format="%(refname:short)"' + ) + p = subprocess.run(shlex.split(list_tag_cmd), capture_output=True, check=True) + + all_tags = p.stdout.decode().strip() + latest_tag = all_tags.split("\n")[-1] + return latest_tag + + +def match_version_pattern(v): + pattern = r"WAMR-\d+\.\d+\.\d+" + m = re.match(pattern, v) + return m is not None + + +def split_version_string(v): + """ + return the semantic version as an integer list + """ + pattern = r"WAMR-(\d+)\.(\d+)\.(\d+)" + m = re.match(pattern, v) + return [int(x) for x in m.groups()] + + +def compare_version_string(v1, v2): + """ + return value: + - 1. if v1 > v2 + - -1. if v1 < v2 + - 0. if v1 == v2 + """ + if not match_version_pattern(v1): + raise Exception(f"{v1} doesn't match the version pattern") + + if not match_version_pattern(v2): + raise Exception(f"{v2} doesn't match the version pattern") + + v1_sem_ver = split_version_string(v1) + v2_sem_ver = split_version_string(v2) + + return 0 if v1_sem_ver == v2_sem_ver else (1 if v1_sem_ver > v2_sem_ver else -1) + + +def is_major_or_minor_changed(v1, v2): + """ + return true if change either major of v2 or minor of v2 + return false or else + """ + if not match_version_pattern(v1): + raise Exception(f"{v1} doesn't match the version pattern") + + if not match_version_pattern(v2): + raise Exception(f"{v2} doesn't match the version pattern") + + v1_major, v1_minor, _ = split_version_string(v1) + v2_major, v2_minor, _ = split_version_string(v2) + + return v2_major != v1_major or v2_minor != v1_minor + + +def next_version(): + definition = fetch_version_from_code() + tag = fetch_latest_git_tag() + + new_version = "" + minor_changed = False + if compare_version_string(definition, tag) == 1: + new_version = definition.split("-")[-1] + + if is_major_or_minor_changed(tag, definition): + minor_changed = True + + return new_version, "major_minor_change" if minor_changed else "patch_change" + + +if __name__ == "__main__": + print(f"{next_version()[0]},{next_version()[1]}") + sys.exit(0) diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/.github/scripts/reuse_latest_release_binaries.py b/lib/wasm-micro-runtime-WAMR-1.2.2/.github/scripts/reuse_latest_release_binaries.py new file mode 100644 index 00000000000..0fe2d9766c3 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/.github/scripts/reuse_latest_release_binaries.py @@ -0,0 +1,102 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# + +import argparse +import json +import os +import shlex +import subprocess +import sys +from urllib.error import HTTPError, URLError +import urllib.request + + +def get_last_commit(target_path, cwd): + last_commit_cmd = f"git log -n 1 --pretty=format:%H -- {target_path}" + p = subprocess.run( + shlex.split(last_commit_cmd), capture_output=True, check=True, cwd=cwd + ) + return p.stdout.decode().strip() + + +def fetch_git_tags(): + list_tag_cmd = ( + 'git tag --list WAMR-*.*.* --sort=committerdate --format="%(refname:short)"' + ) + p = subprocess.run(shlex.split(list_tag_cmd), capture_output=True, check=True) + + all_tags = p.stdout.decode().strip() + return all_tags.split("\n") + + +def download_binaries(binary_name_stem, cwd): + """ + 1. find the latest release name + 2. form assets download url: + """ + try: + all_tags = fetch_git_tags() + # *release_process.yml* will create a tag and release at first + second_last_tag = all_tags[-2] + latest_tag = all_tags[-1] + + latest_url = "https://api.github.com/repos/bytecodealliance/wasm-micro-runtime/releases/latest" + print(f"::notice::query the latest release with {latest_url}...") + with urllib.request.urlopen(latest_url) as response: + body = response.read() + + release_name = json.loads(body)["name"] + + # WAMR-X.Y.Z -> X.Y.Z + second_last_sem_ver = second_last_tag[5:] + latest_sem_ver = latest_tag[5:] + assert latest_sem_ver in binary_name_stem + name_stem_in_release = binary_name_stem.replace( + latest_sem_ver, second_last_sem_ver + ) + + # download and rename + for file_ext in (".zip", ".tar.gz"): + assets_url = f"https://github.com/bytecodealliance/wasm-micro-runtime/releases/download/{release_name}/{name_stem_in_release}{file_ext}" + local_path = f"{binary_name_stem}{file_ext}" + print(f"::notice::download from {assets_url} and save as {local_path}...") + urllib.request.urlretrieve(assets_url, local_path) + return True + except HTTPError as error: + print(error.status, error.reason) + except URLError as error: + print(error.reason) + except TimeoutError: + print("Request timeout") + + return False + + +def main(): + parser = argparse.ArgumentParser( + description="Reuse binaries of the latest release if no more modification on the_path since last_commit" + ) + parser.add_argument("working_directory", type=str) + parser.add_argument("--binary_name_stem", type=str) + parser.add_argument("--last_commit", type=str) + parser.add_argument("--the_path", type=str) + args = parser.parse_args() + + last_commit = get_last_commit(args.the_path, args.working_directory) + if last_commit == args.last_commit: + return download_binaries(args.binary_name_stem, args.working_directory) + else: + return False + + +if __name__ == "__main__": + # use output to indicate results + # echo "result=${result}" >> "$GITHUB_OUTPUT" + with open(os.environ.get("GITHUB_OUTPUT"), 'a') as output_file: + output_file.write("result=hit\n" if main() else "result=not-hit\n") + + # always return 0 + sys.exit(0) diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/.github/workflows/build_docker_images.yml b/lib/wasm-micro-runtime-WAMR-1.2.2/.github/workflows/build_docker_images.yml new file mode 100644 index 00000000000..819bf94c311 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/.github/workflows/build_docker_images.yml @@ -0,0 +1,89 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +name: Create and publish Docker images + +on: + workflow_call: + inputs: + upload_url: + description: upload binary assets to the URL of release + type: string + required: true + ver_num: + description: a semantic version number. + type: string + required: true + +jobs: + build-and-push-images: + runs-on: ubuntu-22.04 + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Build and save Docker image(wasm-debug-server:${{ inputs.ver_num }}) to tar file + run: | + docker build -t wasm-debug-server:${{ inputs.ver_num }} . + docker save -o wasm-debug-server.tar wasm-debug-server:${{ inputs.ver_num }} + working-directory: test-tools/wamr-ide/WASM-Debug-Server/Docker + + - name: compress the tar file + run: | + tar czf wasm-debug-server-${{ inputs.ver_num }}.tar.gz wasm-debug-server.tar + zip wasm-debug-server-${{ inputs.ver_num }}.zip wasm-debug-server.tar + working-directory: test-tools/wamr-ide/WASM-Debug-Server/Docker + + - name: upload release tar.gz + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ inputs.upload_url }} + asset_path: test-tools/wamr-ide/WASM-Debug-Server/Docker/wasm-debug-server-${{ inputs.ver_num }}.tar.gz + asset_name: wasm-debug-server-${{ inputs.ver_num }}.tar.gz + asset_content_type: application/x-gzip + + - name: upload release zip + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ inputs.upload_url }} + asset_path: test-tools/wamr-ide/WASM-Debug-Server/Docker/wasm-debug-server-${{ inputs.ver_num }}.zip + asset_name: wasm-debug-server-${{ inputs.ver_num }}.zip + asset_content_type: application/zip + + - name: Build and save Docker image(wasm-toolchain:${{ inputs.ver_num }}) to tar file + run: | + docker build -t wasm-toolchain:${{ inputs.ver_num }} . + docker save -o wasm-toolchain.tar wasm-toolchain:${{ inputs.ver_num }} + working-directory: test-tools/wamr-ide/WASM-Toolchain/Docker + + - name: compress the tar file + run: | + tar czf wasm-toolchain-${{ inputs.ver_num }}.tar.gz wasm-toolchain.tar + zip wasm-toolchain-${{ inputs.ver_num }}.zip wasm-toolchain.tar + working-directory: test-tools/wamr-ide/WASM-Toolchain/Docker + + - name: upload release tar.gz + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ inputs.upload_url }} + asset_path: test-tools/wamr-ide/WASM-Toolchain/Docker/wasm-toolchain-${{ inputs.ver_num }}.tar.gz + asset_name: wasm-toolchain-${{ inputs.ver_num }}.tar.gz + asset_content_type: application/x-gzip + + - name: upload release zip + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ inputs.upload_url }} + asset_path: test-tools/wamr-ide/WASM-Toolchain/Docker/wasm-toolchain-${{ inputs.ver_num }}.zip + asset_name: wasm-toolchain-${{ inputs.ver_num }}.zip + asset_content_type: application/zip + diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/.github/workflows/build_iwasm_release.yml b/lib/wasm-micro-runtime-WAMR-1.2.2/.github/workflows/build_iwasm_release.yml new file mode 100644 index 00000000000..64aa9a92c17 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/.github/workflows/build_iwasm_release.yml @@ -0,0 +1,108 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +name: build iwasm release + +on: + workflow_call: + inputs: + arch: + description: arch of the release + type: string + required: false + default: x86_64 + cwd: + description: workfing directory + type: string + required: true + llvm_cache_key: + description: the cache key of llvm libraries + type: string + required: true + runner: + description: OS of compilation + type: string + required: true + upload_url: + description: a semantic version number. it is required when `release` is true. + type: string + required: false + ver_num: + description: a semantic version number. it is required when `release` is true. + type: string + required: false + +jobs: + build: + runs-on: ${{ inputs.runner }} + steps: + - uses: actions/checkout@v3 + + - name: get cached LLVM libraries + id: retrieve_llvm_libs + uses: actions/cache@v3 + with: + path: | + ./core/deps/llvm/build/bin + ./core/deps/llvm/build/include + ./core/deps/llvm/build/lib + ./core/deps/llvm/build/libexec + ./core/deps/llvm/build/share + key: ${{ inputs.llvm_cache_key }} + fail-on-cache-miss: true + + - name: generate iwasm binary release + run: | + cmake -S . -B build \ + -DWAMR_BUILD_AOT=1 -DWAMR_BUILD_INTERP=1 -DWAMR_BUILD_FAST_JIT=1 -DWAMR_BUILD_JIT=1 \ + -DWAMR_BUILD_CUSTOM_NAME_SECTION=0 \ + -DWAMR_BUILD_DEBUG_INTERP=0 \ + -DWAMR_BUILD_DEBUG_AOT=0 \ + -DWAMR_BUILD_DUMP_CALL_STACK=0 \ + -DWAMR_BUILD_LIBC_UVWASI=0 \ + -DWAMR_BUILD_LIBC_EMCC=0 \ + -DWAMR_BUILD_LIB_RATS=0 \ + -DWAMR_BUILD_LOAD_CUSTOM_SECTION=0 \ + -DWAMR_BUILD_MEMORY_PROFILING=0 \ + -DWAMR_BUILD_MINI_LOADER=0 \ + -DWAMR_BUILD_MULTI_MODULE=0 \ + -DWAMR_BUILD_PERF_PROFILING=0 \ + -DWAMR_BUILD_SPEC_TEST=0 \ + -DWAMR_BUILD_BULK_MEMORY=1 \ + -DWAMR_BUILD_LIB_PTHREAD=1 \ + -DWAMR_BUILD_LIB_PTHREAD_SEMAPHORE=1 \ + -DWAMR_BUILD_LIB_WASI_THREADS=1 \ + -DWAMR_BUILD_LIBC_BUILTIN=1 \ + -DWAMR_BUILD_LIBC_WASI=1 \ + -DWAMR_BUILD_REF_TYPES=1 \ + -DWAMR_BUILD_SIMD=1 \ + -DWAMR_BUILD_SHARED_MEMORY=1 \ + -DWAMR_BUILD_TAIL_CALL=1 \ + -DWAMR_BUILD_THREAD_MGR=1 + cmake --build build --config Release --parallel 4 + working-directory: ${{ inputs.cwd }} + + - name: compress the binary + run: | + tar czf iwasm-${{ inputs.ver_num }}-${{ inputs.runner }}.tar.gz iwasm + zip iwasm-${{ inputs.ver_num }}-${{ inputs.runner }}.zip iwasm + working-directory: ${{ inputs.cwd }}/build + + - name: upload release tar.gz + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ inputs.upload_url }} + asset_path: ${{ inputs.cwd }}/build/iwasm-${{ inputs.ver_num }}-${{ inputs.runner }}.tar.gz + asset_name: iwasm-${{ inputs.ver_num }}-${{ inputs.arch }}-${{ inputs.runner }}.tar.gz + asset_content_type: application/x-gzip + + - name: upload release zip + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ inputs.upload_url }} + asset_path: ${{ inputs.cwd }}/build/iwasm-${{ inputs.ver_num }}-${{ inputs.runner }}.zip + asset_name: iwasm-${{ inputs.ver_num }}-${{ inputs.arch }}-${{ inputs.runner }}.zip + asset_content_type: application/zip diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/.github/workflows/build_llvm_libraries.yml b/lib/wasm-micro-runtime-WAMR-1.2.2/.github/workflows/build_llvm_libraries.yml new file mode 100644 index 00000000000..7ef1dd63f86 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/.github/workflows/build_llvm_libraries.yml @@ -0,0 +1,91 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +name: Reusable workflow-build_llvm_libraries + +on: + workflow_call: + inputs: + os: + required: true + type: string + arch: + required: true + type: string + outputs: + cache_key: + description: "A cached key of LLVM libraries" + value: ${{ jobs.build_llvm_libraries.outputs.key}} + +jobs: + build_llvm_libraries: + runs-on: ${{ inputs.os }} + outputs: + key: ${{ steps.create_lib_cache_key.outputs.key}} + + steps: + - name: checkout + uses: actions/checkout@v3 + + - name: install dependencies + run: /usr/bin/env python3 -m pip install -r requirements.txt + working-directory: build-scripts + + - name: retrive the last commit ID + id: get_last_commit + run: echo "last_commit=$(GH_TOKEN=${{ secrets.GITHUB_TOKEN }} /usr/bin/env python3 ./build_llvm.py --llvm-ver)" >> $GITHUB_OUTPUT + working-directory: build-scripts + + # Bump the prefix number to evict all previous caches and + # enforce a clean build, in the unlikely case that some + # weird build error occur and llvm/build becomes a potential + # suspect. + - name: form the cache key of libraries + id: create_lib_cache_key + run: echo "key=0-llvm-libraries-${{ inputs.os }}-${{ inputs.arch }}-${{ steps.get_last_commit.outputs.last_commit }}" >> $GITHUB_OUTPUT + + - name: Cache LLVM libraries + id: retrieve_llvm_libs + uses: actions/cache@v3 + with: + path: | + ./core/deps/llvm/build/bin + ./core/deps/llvm/build/include + ./core/deps/llvm/build/lib + ./core/deps/llvm/build/libexec + ./core/deps/llvm/build/share + key: ${{ steps.create_lib_cache_key.outputs.key}} + + - uses: actions/cache@v3 + with: + path: ~/.ccache + key: 0-ccache-${{ inputs.os }}-${{ steps.get_last_commit.outputs.last_commit }} + restore-keys: | + 0-ccache-${{ inputs.os }} + if: steps.retrieve_llvm_libs.outputs.cache-hit != 'true' && inputs.os == 'ubuntu-20.04' + + - uses: actions/cache@v3 + with: + path: ~/.cache/ccache + key: 0-ccache-${{ inputs.os }}-${{ steps.get_last_commit.outputs.last_commit }} + restore-keys: | + 0-ccache-${{ inputs.os }} + if: steps.retrieve_llvm_libs.outputs.cache-hit != 'true' && inputs.os == 'ubuntu-22.04' + + - run: sudo apt install -y ccache ninja-build + if: steps.retrieve_llvm_libs.outputs.cache-hit != 'true' && startsWith(inputs.os, 'ubuntu') + + - uses: actions/cache@v3 + with: + path: ~/Library/Caches/ccache + key: 0-ccache-${{ inputs.os }}-${{ steps.get_last_commit.outputs.last_commit }} + restore-keys: | + 0-ccache-${{ inputs.os }} + if: steps.retrieve_llvm_libs.outputs.cache-hit != 'true' && startsWith(inputs.os, 'macos') + + - run: brew install ccache ninja + if: steps.retrieve_llvm_libs.outputs.cache-hit != 'true' && startsWith(inputs.os, 'macos') + + - name: Build LLVM libraries + if: steps.retrieve_llvm_libs.outputs.cache-hit != 'true' + run: /usr/bin/env python3 ./build_llvm.py --arch ${{ inputs.arch }} + working-directory: build-scripts diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/.github/workflows/build_wamr_lldb.yml b/lib/wasm-micro-runtime-WAMR-1.2.2/.github/workflows/build_wamr_lldb.yml new file mode 100644 index 00000000000..ba491ad3ad1 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/.github/workflows/build_wamr_lldb.yml @@ -0,0 +1,197 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +name: build wamr lldb + +on: + workflow_call: + inputs: + arch: + description: arch of the release + type: string + required: false + default: x86_64 + runner: + description: OS of compilation + type: string + required: true + upload_url: + description: upload binary assets to the URL of release + type: string + required: true + ver_num: + description: a semantic version number + type: string + required: true + +jobs: + try_reuse: + uses: ./.github/workflows/reuse_latest_release_binaries.yml + with: + binary_name_stem: "wamr-lldb-${{ inputs.ver_num }}-${{ inputs.arch }}-${{ inputs.runner }}" + last_commit: "ea63ba4bd010c2285623ad4acc0262a4d63bcfea" + the_path: "./build-scripts/lldb-wasm.patch" + upload_url: ${{ inputs.upload_url }} + + build: + needs: try_reuse + if: needs.try_reuse.outputs.result != 'hit' + runs-on: ${{ inputs.runner }} + steps: + - uses: actions/checkout@v3 + + - name: Cache build + id: lldb_build_cache + uses: actions/cache@v3 + with: + path: | + ./core/deps/llvm-project/build/bin + ./core/deps/llvm-project/build/include + ./core/deps/llvm-project/build/lib + ./core/deps/llvm-project/build/libexec + ./core/deps/llvm-project/build/share + ./core/deps/llvm-project/lldb/tools/ + ./core/deps/llvm-project/wamr-lldb/ + key: ${{inputs.arch}}-${{ inputs.runner }}-lldb_build + + - name: setup xcode macos + if: steps.lldb_build_cache.outputs.cache-hit != 'true' && contains(inputs.runner, 'macos') + uses: maxim-lobanov/setup-xcode@v1 + with: + xcode-version: latest-stable + + # Remove xCode command line tools, to prevent duplicate symbol compilation failures + - name: install utils macos + if: steps.lldb_build_cache.outputs.cache-hit != 'true' && contains(inputs.runner, 'macos') + run: | + brew install swig cmake ninja libedit + sudo rm -rf /Library/Developer/CommandLineTools + + - name: intsall utils ubuntu + if: steps.lldb_build_cache.outputs.cache-hit != 'true' && contains(inputs.runner, 'ubuntu') + run: sudo apt update && sudo apt-get install -y lld ninja-build + + # `git clone` takes ~7m + - name: download llvm + if: steps.lldb_build_cache.outputs.cache-hit != 'true' + run: | + wget https://github.com/llvm/llvm-project/archive/1f27fe6128769f00197925c3b8f6abb9d0e5cd2e.zip + unzip -q 1f27fe6128769f00197925c3b8f6abb9d0e5cd2e.zip + mv llvm-project-1f27fe6128769f00197925c3b8f6abb9d0e5cd2e llvm-project + working-directory: core/deps/ + + - name: apply wamr patch + if: steps.lldb_build_cache.outputs.cache-hit != 'true' + run: | + git init + git config user.email "action@github.com" + git config user.name "github action" + git apply ../../../build-scripts/lldb-wasm.patch + working-directory: core/deps/llvm-project + + - name: build lldb ubuntu + if: steps.lldb_build_cache.outputs.cache-hit != 'true' && contains(inputs.runner, 'ubuntu') + run: | + echo "start to build lldb..." + mkdir -p wamr-lldb + cmake -S ./llvm -B build \ + -G Ninja \ + -DCMAKE_INSTALL_PREFIX=../wamr-lldb \ + -DCMAKE_BUILD_TYPE:STRING="Release" \ + -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \ + -DLLVM_ENABLE_PROJECTS="clang;lldb" \ + -DLLVM_TARGETS_TO_BUILD:STRING="X86;WebAssembly" \ + -DLLVM_BUILD_BENCHMARKS:BOOL=OFF \ + -DLLVM_BUILD_DOCS:BOOL=OFF \ + -DLLVM_BUILD_EXAMPLES:BOOL=OFF \ + -DLLVM_BUILD_LLVM_DYLIB:BOOL=OFF \ + -DLLVM_BUILD_TESTS:BOOL=OFF \ + -DLLVM_INCLUDE_BENCHMARKS:BOOL=OFF \ + -DLLVM_INCLUDE_DOCS:BOOL=OFF \ + -DLLVM_INCLUDE_EXAMPLES:BOOL=OFF \ + -DLLVM_INCLUDE_TESTS:BOOL=OFF \ + -DLLVM_ENABLE_BINDINGS:BOOL=OFF \ + -DLLVM_ENABLE_LIBXML2:BOOL=ON \ + -DLLDB_ENABLE_PYTHON:BOOL=OFF \ + -DLLVM_ENABLE_LLD:BOOL=ON + cmake --build build --target lldb install --parallel $(nproc) + working-directory: core/deps/llvm-project + + - name: build lldb macos + if: steps.lldb_build_cache.outputs.cache-hit != 'true' && contains(inputs.runner, 'macos') + run: | + echo "start to build lldb..." + mkdir -p wamr-lldb + cmake -S ./llvm -B build \ + -G Ninja \ + -DCMAKE_INSTALL_PREFIX=../wamr-lldb \ + -DCMAKE_BUILD_TYPE:STRING="Release" \ + -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \ + -DLLVM_ENABLE_PROJECTS="clang;lldb" \ + -DLLVM_TARGETS_TO_BUILD:STRING="X86;WebAssembly" \ + -DLLVM_BUILD_BENCHMARKS:BOOL=OFF \ + -DLLVM_BUILD_DOCS:BOOL=OFF \ + -DLLVM_BUILD_EXAMPLES:BOOL=OFF \ + -DLLVM_BUILD_LLVM_DYLIB:BOOL=OFF \ + -DLLVM_BUILD_TESTS:BOOL=OFF \ + -DLLVM_INCLUDE_BENCHMARKS:BOOL=OFF \ + -DLLVM_INCLUDE_DOCS:BOOL=OFF \ + -DLLVM_INCLUDE_EXAMPLES:BOOL=OFF \ + -DLLVM_INCLUDE_TESTS:BOOL=OFF \ + -DLLVM_BUILD_BENCHMARKS:BOOL=OFF \ + -DLLVM_BUILD_DOCS:BOOL=OFF \ + -DLLVM_BUILD_LLVM_DYLIB:BOOL=OFF \ + -DLLVM_ENABLE_BINDINGS:BOOL=OFF \ + -DLLVM_ENABLE_LIBXML2:BOOL=ON \ + -DLLDB_ENABLE_PYTHON:BOOL=OFF \ + -DLLDB_BUILD_FRAMEWORK:BOOL=OFF + cmake --build build --target lldb install --parallel $(nproc) + working-directory: core/deps/llvm-project + + - name: pack a distribution + if: steps.lldb_build_cache.outputs.cache-hit != 'true' + run: | + mkdir -p wamr-lldb/bin + mkdir -p wamr-lldb/lib + cp build/bin/lldb* wamr-lldb/bin + cp lldb/tools/lldb-vscode/package.json wamr-lldb + cp -r lldb/tools/lldb-vscode/syntaxes/ wamr-lldb + working-directory: core/deps/llvm-project + + - name: pack ubuntu specific libraries + if: steps.lldb_build_cache.outputs.cache-hit != 'true' && contains(inputs.runner, 'ubuntu') + run: | + cp build/lib/liblldb*.so wamr-lldb/lib + cp build/lib/liblldb*.so.* wamr-lldb/lib + working-directory: core/deps/llvm-project + + - name: pack macos specific libraries + if: steps.lldb_build_cache.outputs.cache-hit != 'true' && contains(inputs.runner, 'macos') + run: | + cp build/lib/liblldb*.dylib wamr-lldb/lib + working-directory: core/deps/llvm-project + + - name: compress the binary + run: | + tar czf wamr-lldb-${{ inputs.ver_num }}-${{ inputs.runner }}.tar.gz wamr-lldb + zip -r wamr-lldb-${{ inputs.ver_num }}-${{ inputs.runner }}.zip wamr-lldb + working-directory: core/deps/llvm-project + + - name: upload release tar.gz + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ inputs.upload_url }} + asset_path: core/deps/llvm-project/wamr-lldb-${{ inputs.ver_num }}-${{ inputs.runner }}.tar.gz + asset_name: wamr-lldb-${{ inputs.ver_num }}-${{ inputs.arch }}-${{ inputs.runner }}.tar.gz + asset_content_type: application/x-gzip + + - name: upload release zip + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ inputs.upload_url }} + asset_path: core/deps/llvm-project/wamr-lldb-${{ inputs.ver_num }}-${{ inputs.runner }}.zip + asset_name: wamr-lldb-${{ inputs.ver_num }}-${{ inputs.arch }}-${{ inputs.runner }}.zip + asset_content_type: application/zip diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/.github/workflows/build_wamr_sdk.yml b/lib/wasm-micro-runtime-WAMR-1.2.2/.github/workflows/build_wamr_sdk.yml new file mode 100644 index 00000000000..fff6d85df74 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/.github/workflows/build_wamr_sdk.yml @@ -0,0 +1,78 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +name: build wamr-sdk + +on: + workflow_call: + inputs: + arch: + description: arch of the release + type: string + required: false + default: x86_64 + config_file: + description: warm-sdk config file path + type: string + required: true + runner: + description: OS of compilation + type: string + required: true + upload_url: + description: upload binary assets to the URL of release + type: string + required: true + ver_num: + description: a semantic version number + type: string + required: true + wasi_sdk_url: + description: download WASI_SDK from this URL + type: string + required: true + +jobs: + build: + runs-on: ${{ inputs.runner }} + steps: + - uses: actions/checkout@v3 + + - name: download and install wasi-sdk + run: | + cd /opt + basename=$(basename ${{ inputs.wasi_sdk_url }}) + sudo wget --progress=dot:giga ${{ inputs.wasi_sdk_url }} + sudo tar -xzf ${basename} + sudo rm ${basename} + sudo mv wasi-sdk-* wasi-sdk + + - name: generate wamr-sdk release + run: | + ./build_sdk.sh -n wamr-sdk -x $(pwd)/${{ inputs.config_file }} + working-directory: wamr-sdk + + - name: compress the binary + run: | + tar czf wamr-sdk-${{ inputs.ver_num }}-${{ inputs.runner }}.tar.gz wamr-sdk + zip -r wamr-sdk-${{ inputs.ver_num }}-${{ inputs.runner }}.zip wamr-sdk + working-directory: wamr-sdk/out + + - name: upload release tar.gz + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ inputs.upload_url }} + asset_path: wamr-sdk/out/wamr-sdk-${{ inputs.ver_num }}-${{ inputs.runner }}.tar.gz + asset_name: wamr-sdk-${{ inputs.ver_num }}-${{ inputs.arch }}-${{ inputs.runner }}.tar.gz + asset_content_type: application/x-gzip + + - name: upload release zip + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ inputs.upload_url }} + asset_path: wamr-sdk/out/wamr-sdk-${{ inputs.ver_num }}-${{ inputs.runner }}.zip + asset_name: wamr-sdk-${{ inputs.ver_num }}-${{ inputs.arch }}-${{ inputs.runner }}.zip + asset_content_type: application/zip diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/.github/workflows/build_wamr_vscode_ext.yml b/lib/wasm-micro-runtime-WAMR-1.2.2/.github/workflows/build_wamr_vscode_ext.yml new file mode 100644 index 00000000000..297dc9b9e72 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/.github/workflows/build_wamr_vscode_ext.yml @@ -0,0 +1,73 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +name: build wamr-ide vscode extension + +on: + workflow_call: + inputs: + upload_url: + description: upload binary assets to the URL of release + type: string + required: true + ver_num: + description: a semantic version number. + type: string + required: true + +jobs: + build: + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v3 + + - name: Use Node.js 14.x + uses: actions/setup-node@v3 + with: + node-version: 14.x + + - name: set vscode extension to correct version + run: | + npm install -g json + json -I -f package.json -e "this.version=\"${{ inputs.ver_num }}\"" + working-directory: test-tools/wamr-ide/VSCode-Extension + + - name: generate wamr ide vscode extension + run: | + npm install -g vsce + rm -rf node_modules + npm install + vsce package + working-directory: test-tools/wamr-ide/VSCode-Extension + + - name: publish wamr ide vscode extension to the vsce marketplace + if: ${{ github.repository == 'bytecodealliance/wasm-micro-runtime' }} + run: | + vsce publish -p ${{ secrets.TOKEN }} + working-directory: test-tools/wamr-ide/VSCode-Extension + + - name: compress the vscode extension + run: | + mv wamride-*.vsix wamr-ide.vsix + tar czf wamr-ide-${{ inputs.ver_num }}.tar.gz wamr-ide.vsix + zip wamr-ide-${{ inputs.ver_num }}.zip wamr-ide.vsix + working-directory: test-tools/wamr-ide/VSCode-Extension + + - name: upload release tar.gz + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ inputs.upload_url }} + asset_path: test-tools/wamr-ide/VSCode-Extension/wamr-ide-${{ inputs.ver_num }}.tar.gz + asset_name: wamr-ide-${{ inputs.ver_num }}.tar.gz + asset_content_type: application/x-gzip + + - name: upload release zip + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ inputs.upload_url }} + asset_path: test-tools/wamr-ide/VSCode-Extension/wamr-ide-${{ inputs.ver_num }}.zip + asset_name: wamr-ide-${{ inputs.ver_num }}.zip + asset_content_type: application/zip diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/.github/workflows/build_wamrc.yml b/lib/wasm-micro-runtime-WAMR-1.2.2/.github/workflows/build_wamrc.yml new file mode 100644 index 00000000000..11c5de9bafe --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/.github/workflows/build_wamrc.yml @@ -0,0 +1,86 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +name: build wamrc + +on: + workflow_call: + inputs: + arch: + description: arch of the release + type: string + required: false + default: x86_64 + llvm_cache_key: + description: the cache key of llvm libraries + type: string + required: true + release: + description: it is a part of the release process + type: boolean + required: true + runner: + description: OS of compilation + type: string + required: true + upload_url: + description: a semantic version number. it is required when `release` is true. + type: string + required: false + ver_num: + description: a semantic version number. it is required when `release` is true. + type: string + required: false + +jobs: + build: + runs-on: ${{ inputs.runner }} + steps: + - uses: actions/checkout@v3 + + - name: get cached LLVM libraries + id: retrieve_llvm_libs + uses: actions/cache@v3 + with: + path: | + ./core/deps/llvm/build/bin + ./core/deps/llvm/build/include + ./core/deps/llvm/build/lib + ./core/deps/llvm/build/libexec + ./core/deps/llvm/build/share + key: ${{ inputs.llvm_cache_key }} + fail-on-cache-miss: true + + - name: generate wamrc binary release + run: | + cmake -S . -B build + cmake --build build --config Release --parallel 4 + working-directory: wamr-compiler + + - name: compress the binary + if: inputs.release + run: | + tar czf wamrc-${{ inputs.ver_num }}-${{ inputs.runner }}.tar.gz wamrc + zip wamrc-${{ inputs.ver_num }}-${{ inputs.runner }}.zip wamrc + working-directory: wamr-compiler/build + + - name: upload release tar.gz + if: inputs.release + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ inputs.upload_url }} + asset_path: wamr-compiler/build/wamrc-${{ inputs.ver_num }}-${{ inputs.runner }}.tar.gz + asset_name: wamrc-${{ inputs.ver_num }}-${{ inputs.arch }}-${{ inputs.runner }}.tar.gz + asset_content_type: application/x-gzip + + - name: upload release zip + if: inputs.release + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ inputs.upload_url }} + asset_path: wamr-compiler/build/wamrc-${{ inputs.ver_num }}-${{ inputs.runner }}.zip + asset_name: wamrc-${{ inputs.ver_num }}-${{ inputs.arch }}-${{ inputs.runner }}.zip + asset_content_type: application/zip diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/.github/workflows/codeing_guildelines.yml b/lib/wasm-micro-runtime-WAMR-1.2.2/.github/workflows/coding_guidelines.yml similarity index 70% rename from lib/wasm-micro-runtime-WAMR-1.1.1/.github/workflows/codeing_guildelines.yml rename to lib/wasm-micro-runtime-WAMR-1.2.2/.github/workflows/coding_guidelines.yml index f068926312c..259e84fe51b 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/.github/workflows/codeing_guildelines.yml +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/.github/workflows/coding_guidelines.yml @@ -15,18 +15,7 @@ concurrency: cancel-in-progress: true jobs: - # Cancel any in-flight jobs for the same PR/branch so there's only one active - # at a time - cancel_previous: - runs-on: ubuntu-latest - steps: - - name: Cancel Workflow Action - uses: styfle/cancel-workflow-action@0.9.1 - with: - access_token: ${{ github.token }} - - complinace_job: - needs: cancel_previous + compliance_job: runs-on: ubuntu-latest steps: - name: checkout diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/.github/workflows/compilation_on_android_ubuntu.yml b/lib/wasm-micro-runtime-WAMR-1.2.2/.github/workflows/compilation_on_android_ubuntu.yml new file mode 100644 index 00000000000..2a57f621955 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/.github/workflows/compilation_on_android_ubuntu.yml @@ -0,0 +1,645 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +name: compilation on android, ubuntu-20.04, ubuntu-22.04 + +on: + # will be triggered on PR events + pull_request: + types: + - opened + - synchronize + paths: + - ".github/workflows/build_llvm_libraries.yml" + - ".github/workflows/compilation_on_android_ubuntu.yml" + - "build-scripts/**" + - "core/**" + - "!core/deps/**" + - "product-mini/**" + - "samples/**" + - "!samples/workload/**" + - "tests/wamr-test-suites/**" + - "wamr-compiler/**" + - "wamr-sdk/**" + # will be triggered on push events + push: + branches: + - main + - "dev/**" + paths: + - ".github/workflows/build_llvm_libraries.yml" + - ".github/workflows/compilation_on_android_ubuntu.yml" + - "build-scripts/**" + - "core/**" + - "!core/deps/**" + - "product-mini/**" + - "samples/**" + - "!samples/workload/**" + - "tests/wamr-test-suites/**" + - "wamr-compiler/**" + - "wamr-sdk/**" + # allow to be triggered manually + workflow_dispatch: + +# Cancel any in-flight jobs for the same PR/branch so there's only one active +# at a time +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +env: + # For BUILD + AOT_BUILD_OPTIONS: " -DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_FAST_JIT=0 -DWAMR_BUILD_JIT=0 -DWAMR_BUILD_LAZY_JIT=0" + CLASSIC_INTERP_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=0 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=1 -DWAMR_BUILD_FAST_JIT=0 -DWAMR_BUILD_JIT=0 -DWAMR_BUILD_LAZY_JIT=0" + FAST_INTERP_BUILD_OPTIONS: " -DWAMR_BUILD_AOT=0 -DWAMR_BUILD_FAST_INTERP=1 -DWAMR_BUILD_INTERP=1 -DWAMR_BUILD_FAST_JIT=0 -DWAMR_BUILD_JIT=0 -DWAMR_BUILD_LAZY_JIT=0" + FAST_JIT_BUILD_OPTIONS: " -DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_FAST_JIT=1 -DWAMR_BUILD_JIT=0 -DWAMR_BUILD_LAZY_JIT=0" + LLVM_LAZY_JIT_BUILD_OPTIONS: " -DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_FAST_JIT=0 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=1" + LLVM_EAGER_JIT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_FAST_JIT=0 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=0" + MULTI_TIER_JIT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=1 -DWAMR_BUILD_FAST_JIT=1 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=1" + # For Spec Test + DEFAULT_TEST_OPTIONS: "-s spec -b -P" + MULTI_MODULES_TEST_OPTIONS: "-s spec -b -M -P" + SIMD_TEST_OPTIONS: "-s spec -b -S -P" + THREADS_TEST_OPTIONS: "-s spec -b -p -P" + X86_32_TARGET_TEST_OPTIONS: "-m x86_32 -P" + WASI_TEST_OPTIONS: "-s wasi_certification -w" + +jobs: + build_llvm_libraries_on_ubuntu_2004: + uses: ./.github/workflows/build_llvm_libraries.yml + with: + os: "ubuntu-20.04" + arch: "X86" + + build_llvm_libraries_on_ubuntu_2204: + uses: ./.github/workflows/build_llvm_libraries.yml + with: + os: "ubuntu-22.04" + arch: "X86" + + build_wamrc: + needs: + [build_llvm_libraries_on_ubuntu_2004, build_llvm_libraries_on_ubuntu_2204] + runs-on: ${{ matrix.os }} + strategy: + matrix: + include: + - os: ubuntu-20.04 + llvm_cache_key: ${{ needs.build_llvm_libraries_on_ubuntu_2004.outputs.cache_key }} + - os: ubuntu-22.04 + llvm_cache_key: ${{ needs.build_llvm_libraries_on_ubuntu_2204.outputs.cache_key }} + steps: + - name: checkout + uses: actions/checkout@v3 + + # since jobs.id can't contain the dot character + # it is hard to use `format` to assemble the cache key + - name: Get LLVM libraries + id: retrieve_llvm_libs + uses: actions/cache@v3 + with: + path: | + ./core/deps/llvm/build/bin + ./core/deps/llvm/build/include + ./core/deps/llvm/build/lib + ./core/deps/llvm/build/libexec + ./core/deps/llvm/build/share + key: ${{ matrix.llvm_cache_key }} + + - name: Quit if cache miss + if: steps.retrieve_llvm_libs.outputs.cache-hit != 'true' + run: echo "::error::can not get prebuilt llvm libraries" && exit 1 + + - name: Build wamrc + run: | + mkdir build && cd build + cmake .. + cmake --build . --config Release --parallel 4 + working-directory: wamr-compiler + + build_iwasm_linux_gcc4_8: + runs-on: ubuntu-latest + container: + image: ubuntu:14.04 + strategy: + matrix: + make_options_run_mode: [ + # Running mode + $CLASSIC_INTERP_BUILD_OPTIONS, + $FAST_INTERP_BUILD_OPTIONS, + $FAST_JIT_BUILD_OPTIONS, + ] + make_options_feature: [ + # Features + "-DWAMR_BUILD_CUSTOM_NAME_SECTION=1", + "-DWAMR_BUILD_DEBUG_AOT=1", + "-DWAMR_BUILD_DEBUG_INTERP=1", + "-DWAMR_BUILD_DUMP_CALL_STACK=1", + "-DWAMR_BUILD_LIB_PTHREAD=1", + "-DWAMR_BUILD_LIB_WASI_THREADS=1", + "-DWAMR_BUILD_LOAD_CUSTOM_SECTION=1", + "-DWAMR_BUILD_MINI_LOADER=1", + "-DWAMR_BUILD_MEMORY_PROFILING=1", + "-DWAMR_BUILD_MULTI_MODULE=1", + "-DWAMR_BUILD_PERF_PROFILING=1", + "-DWAMR_BUILD_REF_TYPES=1", + "-DWAMR_BUILD_SIMD=1", + "-DWAMR_BUILD_TAIL_CALL=1", + "-DWAMR_DISABLE_HW_BOUND_CHECK=1", + ] + exclude: + # uncompatiable feature and platform + # uncompatiable mode and feature + # MULTI_MODULE only on INTERP mode + - make_options_run_mode: $FAST_JIT_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_MULTI_MODULE=1" + # SIMD only on JIT/AOT mode + - make_options_run_mode: $CLASSIC_INTERP_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_SIMD=1" + - make_options_run_mode: $FAST_INTERP_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_SIMD=1" + # DEBUG_INTERP only on CLASSIC INTERP mode + - make_options_run_mode: $FAST_INTERP_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_DEBUG_INTERP=1" + - make_options_run_mode: $FAST_JIT_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_DEBUG_INTERP=1" + # DEBUG_AOT only on JIT/AOT mode + - make_options_run_mode: $CLASSIC_INTERP_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_DEBUG_AOT=1" + - make_options_run_mode: $FAST_INTERP_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_DEBUG_AOT=1" + # TODO: DEBUG_AOT on JIT + - make_options_run_mode: $FAST_JIT_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_DEBUG_AOT=1" + # MINI_LOADER only on INTERP mode + - make_options_run_mode: $FAST_JIT_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1" + steps: + - name: checkout + uses: actions/checkout@v3 + + - name: Install dependencies + run: apt update && apt install -y make g++-4.8 gcc-4.8 wget git + + - name: Install cmake + run: | + wget https://github.com/Kitware/CMake/releases/download/v3.26.1/cmake-3.26.1-linux-x86_64.tar.gz -O cmake.tar.gz + tar xzf cmake.tar.gz + cp cmake-3.26.1-linux-x86_64/bin/cmake /usr/local/bin + cp -r cmake-3.26.1-linux-x86_64/share/cmake-3.26/ /usr/local/share/ + + - name: Build iwasm + run: | + mkdir build && cd build + cmake .. ${{ matrix.make_options_run_mode }} ${{ matrix.make_options_feature }} -DCMAKE_C_COMPILER=gcc-4.8 -DCMAKE_CXX_COMPILER=g++-4.8 + cmake --build . --config Release --parallel 4 + working-directory: product-mini/platforms/linux + + build_iwasm: + needs: + [build_llvm_libraries_on_ubuntu_2004, build_llvm_libraries_on_ubuntu_2204] + runs-on: ${{ matrix.os }} + strategy: + matrix: + make_options_run_mode: [ + # Running mode + $AOT_BUILD_OPTIONS, + $CLASSIC_INTERP_BUILD_OPTIONS, + $FAST_INTERP_BUILD_OPTIONS, + $FAST_JIT_BUILD_OPTIONS, + $LLVM_LAZY_JIT_BUILD_OPTIONS, + $LLVM_EAGER_JIT_BUILD_OPTIONS, + $MULTI_TIER_JIT_BUILD_OPTIONS, + ] + make_options_feature: [ + # Features + "-DWAMR_BUILD_CUSTOM_NAME_SECTION=1", + "-DWAMR_BUILD_DEBUG_AOT=1", + "-DWAMR_BUILD_DEBUG_INTERP=1", + "-DWAMR_BUILD_DUMP_CALL_STACK=1", + "-DWAMR_BUILD_LIB_PTHREAD=1", + "-DWAMR_BUILD_LIB_WASI_THREADS=1", + "-DWAMR_BUILD_LOAD_CUSTOM_SECTION=1", + "-DWAMR_BUILD_MINI_LOADER=1", + "-DWAMR_BUILD_MEMORY_PROFILING=1", + "-DWAMR_BUILD_MULTI_MODULE=1", + "-DWAMR_BUILD_PERF_PROFILING=1", + "-DWAMR_BUILD_REF_TYPES=1", + "-DWAMR_BUILD_SIMD=1", + "-DWAMR_BUILD_TAIL_CALL=1", + "-DWAMR_DISABLE_HW_BOUND_CHECK=1", + ] + os: [ubuntu-20.04, ubuntu-22.04] + platform: [android, linux] + exclude: + # uncompatiable feature and platform + # uncompatiable mode and feature + # MULTI_MODULE only on INTERP mode + - make_options_run_mode: $AOT_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_MULTI_MODULE=1" + - make_options_run_mode: $FAST_JIT_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_MULTI_MODULE=1" + - make_options_run_mode: $LLVM_LAZY_JIT_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_MULTI_MODULE=1" + - make_options_run_mode: $LLVM_EAGER_JIT_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_MULTI_MODULE=1" + - make_options_run_mode: $MULTI_TIER_JIT_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_MULTI_MODULE=1" + # SIMD only on JIT/AOT mode + - make_options_run_mode: $CLASSIC_INTERP_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_SIMD=1" + - make_options_run_mode: $FAST_INTERP_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_SIMD=1" + # DEBUG_INTERP only on CLASSIC INTERP mode + - make_options_run_mode: $AOT_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_DEBUG_INTERP=1" + - make_options_run_mode: $FAST_INTERP_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_DEBUG_INTERP=1" + - make_options_run_mode: $FAST_JIT_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_DEBUG_INTERP=1" + - make_options_run_mode: $LLVM_LAZY_JIT_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_DEBUG_INTERP=1" + - make_options_run_mode: $LLVM_EAGER_JIT_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_DEBUG_INTERP=1" + - make_options_run_mode: $MULTI_TIER_JIT_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_DEBUG_INTERP=1" + # DEBUG_AOT only on JIT/AOT mode + - make_options_run_mode: $CLASSIC_INTERP_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_DEBUG_AOT=1" + - make_options_run_mode: $FAST_INTERP_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_DEBUG_AOT=1" + # TODO: DEBUG_AOT on JIT + - make_options_run_mode: $FAST_JIT_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_DEBUG_AOT=1" + - make_options_run_mode: $LLVM_LAZY_JIT_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_DEBUG_AOT=1" + - make_options_run_mode: $LLVM_EAGER_JIT_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_DEBUG_AOT=1" + - make_options_run_mode: $MULTI_TIER_JIT_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_DEBUG_AOT=1" + # MINI_LOADER only on INTERP mode + - make_options_run_mode: $AOT_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1" + - make_options_run_mode: $FAST_JIT_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1" + - make_options_run_mode: $LLVM_LAZY_JIT_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1" + - make_options_run_mode: $LLVM_EAGER_JIT_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1" + - make_options_run_mode: $MULTI_TIER_JIT_BUILD_OPTIONS + make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1" + # Fast-JIT and Multi-Tier-JIT mode don't support android(X86-32) + - make_options_run_mode: $FAST_JIT_BUILD_OPTIONS + platform: android + - make_options_run_mode: $MULTI_TIER_JIT_BUILD_OPTIONS + platform: android + # only test andorid on ubuntu latest + - os: ubuntu-20.04 + platform: android + include: + - os: ubuntu-20.04 + llvm_cache_key: ${{ needs.build_llvm_libraries_on_ubuntu_2004.outputs.cache_key }} + - os: ubuntu-22.04 + llvm_cache_key: ${{ needs.build_llvm_libraries_on_ubuntu_2204.outputs.cache_key }} + steps: + - name: checkout + uses: actions/checkout@v3 + + # only download llvm cache when needed + - name: Get LLVM libraries + id: retrieve_llvm_libs + if: endsWith(matrix.make_options_run_mode, '_JIT_BUILD_OPTIONS') + uses: actions/cache@v3 + with: + path: | + ./core/deps/llvm/build/bin + ./core/deps/llvm/build/include + ./core/deps/llvm/build/lib + ./core/deps/llvm/build/libexec + ./core/deps/llvm/build/share + key: ${{ matrix.llvm_cache_key }} + + - name: Quit if cache miss + if: endsWith(matrix.make_options_run_mode, '_JIT_BUILD_OPTIONS') && (steps.retrieve_llvm_libs.outputs.cache-hit != 'true') + run: echo "::error::can not get prebuilt llvm libraries" && exit 1 + + - name: Build iwasm + run: | + mkdir build && cd build + cmake .. ${{ matrix.make_options_run_mode }} ${{ matrix.make_options_feature }} + cmake --build . --config Release --parallel 4 + working-directory: product-mini/platforms/${{ matrix.platform }} + + build_samples_wasm_c_api: + needs: + [ + build_iwasm, + build_llvm_libraries_on_ubuntu_2004, + build_llvm_libraries_on_ubuntu_2204, + build_wamrc, + ] + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + sanitizer: ["", "ubsan"] + make_options: [ + # Running mode + $AOT_BUILD_OPTIONS, + $CLASSIC_INTERP_BUILD_OPTIONS, + $FAST_INTERP_BUILD_OPTIONS, + $FAST_JIT_BUILD_OPTIONS, + $LLVM_LAZY_JIT_BUILD_OPTIONS, + $LLVM_EAGER_JIT_BUILD_OPTIONS, + $MULTI_TIER_JIT_BUILD_OPTIONS, + ] + os: [ubuntu-20.04, ubuntu-22.04] + wasi_sdk_release: + [ + "https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-20/wasi-sdk-20.0-linux.tar.gz", + ] + wabt_release: + [ + "https://github.com/WebAssembly/wabt/releases/download/1.0.31/wabt-1.0.31-ubuntu.tar.gz", + ] + include: + - os: ubuntu-20.04 + llvm_cache_key: ${{ needs.build_llvm_libraries_on_ubuntu_2004.outputs.cache_key }} + - os: ubuntu-22.04 + llvm_cache_key: ${{ needs.build_llvm_libraries_on_ubuntu_2204.outputs.cache_key }} + + steps: + - name: checkout + uses: actions/checkout@v3 + + - name: Get LLVM libraries + id: retrieve_llvm_libs + if: (!endsWith(matrix.make_options, '_INTERP_BUILD_OPTIONS')) + uses: actions/cache@v3 + with: + path: | + ./core/deps/llvm/build/bin + ./core/deps/llvm/build/include + ./core/deps/llvm/build/lib + ./core/deps/llvm/build/libexec + ./core/deps/llvm/build/share + key: ${{ matrix.llvm_cache_key }} + + - name: Quit if cache miss + if: (!endsWith(matrix.make_options, '_INTERP_BUILD_OPTIONS')) && (steps.retrieve_llvm_libs.outputs.cache-hit != 'true') + run: echo "::error::can not get prebuilt llvm libraries" && exit 1 + + - name: download and install wabt + run: | + cd /opt + sudo wget ${{ matrix.wabt_release }} + sudo tar -xzf wabt-1.0.31-*.tar.gz + sudo mv wabt-1.0.31 wabt + + - name: Build wamrc + if: (!endsWith(matrix.make_options, '_INTERP_BUILD_OPTIONS')) + run: | + mkdir build && cd build + cmake -DSANITIZER="${{matrix.sanitizer}}" .. + cmake --build . --config Release --parallel 4 + working-directory: wamr-compiler + + - name: Build Sample [wasm-c-api] + run: | + VERBOSE=1 + cmake -S . -B build ${{ matrix.make_options }} -DSANITIZER="${{matrix.sanitizer}}" + cmake --build build --config Release --parallel 4 + ctest --test-dir build --output-on-failure + working-directory: samples/wasm-c-api + + build_samples_others: + needs: [build_iwasm] + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-20.04, ubuntu-22.04] + wasi_sdk_release: + [ + "https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-20/wasi-sdk-20.0-linux.tar.gz", + ] + wabt_release: + [ + "https://github.com/WebAssembly/wabt/releases/download/1.0.31/wabt-1.0.31-ubuntu.tar.gz", + ] + steps: + - name: checkout + uses: actions/checkout@v3 + + - name: download and install wasi-sdk + run: | + cd /opt + sudo wget ${{ matrix.wasi_sdk_release }} + sudo tar -xzf wasi-sdk-*.tar.gz + sudo mv wasi-sdk-20.0 wasi-sdk + + - name: download and install wabt + run: | + cd /opt + sudo wget ${{ matrix.wabt_release }} + sudo tar -xzf wabt-1.0.31-*.tar.gz + sudo mv wabt-1.0.31 wabt + + - name: Build Sample [basic] + run: | + cd samples/basic + ./build.sh + ./run.sh + + - name: Build Sample [file] + run: | + cd samples/file + mkdir build && cd build + cmake .. + cmake --build . --config Release --parallel 4 + ./src/iwasm -f wasm-app/file.wasm -d . + + - name: Build Sample [multi-thread] + run: | + cd samples/multi-thread + mkdir build && cd build + cmake .. + cmake --build . --config Release --parallel 4 + ./iwasm wasm-apps/test.wasm + + - name: Build Sample [multi-module] + run: | + cd samples/multi-module + mkdir build && cd build + cmake .. + cmake --build . --config Release --parallel 4 + ./multi_module + + - name: Build Sample [spawn-thread] + run: | + cd samples/spawn-thread + mkdir build && cd build + cmake .. + cmake --build . --config Release --parallel 4 + ./spawn_thread + + - name: Build Sample [ref-types] + run: | + cd samples/ref-types + mkdir build && cd build + cmake .. + cmake --build . --config Release --parallel 4 + ./hello + + - name: Build Sample [simple] + run: | + ./build.sh -p host-interp + python3 ./sample_test_run.py $(pwd)/out + exit $? + working-directory: ./samples/simple + + - name: Build Sample [wasi-threads] + run: | + cd samples/wasi-threads + mkdir build && cd build + cmake .. + cmake --build . --config Release --parallel 4 + ./iwasm wasm-apps/no_pthread.wasm + + test: + needs: + [ + build_iwasm, + build_llvm_libraries_on_ubuntu_2004, + build_llvm_libraries_on_ubuntu_2204, + build_wamrc, + ] + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-20.04, ubuntu-22.04] + running_mode: + [ + "classic-interp", + "fast-interp", + "jit", + "aot", + "fast-jit", + "multi-tier-jit", + ] + test_option: + [ + $DEFAULT_TEST_OPTIONS, + $MULTI_MODULES_TEST_OPTIONS, + $SIMD_TEST_OPTIONS, + $THREADS_TEST_OPTIONS, + $WASI_TEST_OPTIONS, + ] + wasi_sdk_release: + [ + "https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-20/wasi-sdk-20.0-linux.tar.gz", + ] + include: + - os: ubuntu-20.04 + llvm_cache_key: ${{ needs.build_llvm_libraries_on_ubuntu_2004.outputs.cache_key }} + ubuntu_version: "20.04" + - os: ubuntu-22.04 + llvm_cache_key: ${{ needs.build_llvm_libraries_on_ubuntu_2204.outputs.cache_key }} + ubuntu_version: "22.04" + exclude: + # uncompatiable modes and features + # classic-interp and fast-interp don't support simd + - running_mode: "classic-interp" + test_option: $SIMD_TEST_OPTIONS + - running_mode: "fast-interp" + test_option: $SIMD_TEST_OPTIONS + # aot and jit don't support multi module + - running_mode: "aot" + test_option: $MULTI_MODULES_TEST_OPTIONS + - running_mode: "jit" + test_option: $MULTI_MODULES_TEST_OPTIONS + # fast-jit doesn't support multi module, simd + - running_mode: "fast-jit" + test_option: $MULTI_MODULES_TEST_OPTIONS + - running_mode: "fast-jit" + test_option: $SIMD_TEST_OPTIONS + # multi-tier-jit doesn't support multi module, simd + - running_mode: "multi-tier-jit" + test_option: $MULTI_MODULES_TEST_OPTIONS + - running_mode: "multi-tier-jit" + test_option: $SIMD_TEST_OPTIONS + steps: + - name: checkout + uses: actions/checkout@v3 + + - name: download and install wasi-sdk + if: matrix.test_option == '$WASI_TEST_OPTIONS' + run: | + cd /opt + sudo wget ${{ matrix.wasi_sdk_release }} + sudo tar -xzf wasi-sdk-*.tar.gz + sudo mv wasi-sdk-20.0 wasi-sdk + + - name: set env variable(if llvm are used) + if: matrix.running_mode == 'aot' || matrix.running_mode == 'jit' || matrix.running_mode == 'multi-tier-jit' + run: echo "USE_LLVM=true" >> $GITHUB_ENV + + - name: set env variable(if x86_32 test needed) + if: > + (matrix.test_option == '$DEFAULT_TEST_OPTIONS' || matrix.test_option == '$THREADS_TEST_OPTIONS' + || matrix.test_option == '$WASI_TEST_OPTIONS') + && matrix.running_mode != 'fast-jit' && matrix.running_mode != 'jit' && matrix.running_mode != 'multi-tier-jit' + run: echo "TEST_ON_X86_32=true" >> $GITHUB_ENV + + #only download llvm libraries in jit and aot mode + - name: Get LLVM libraries + if: env.USE_LLVM == 'true' + id: retrieve_llvm_libs + uses: actions/cache@v3 + with: + path: | + ./core/deps/llvm/build/bin + ./core/deps/llvm/build/include + ./core/deps/llvm/build/lib + ./core/deps/llvm/build/libexec + ./core/deps/llvm/build/share + key: ${{ matrix.llvm_cache_key }} + + - name: Quit if cache miss + if: env.USE_LLVM == 'true' && steps.retrieve_llvm_libs.outputs.cache-hit != 'true' + run: echo "::error::can not get prebuilt llvm libraries" && exit 1 + + - name: install jq JSON processor + if: matrix.running_mode == 'aot' && matrix.test_option == '$WASI_TEST_OPTIONS' + run: sudo apt-get update && sudo apt install -y jq + + - name: Build WASI thread tests + if: matrix.test_option == '$WASI_TEST_OPTIONS' + run: bash build.sh + working-directory: ./core/iwasm/libraries/lib-wasi-threads/test/ + + - name: build socket api tests + if: matrix.test_option == '$WASI_TEST_OPTIONS' + run: bash build.sh + working-directory: ./core/iwasm/libraries/lib-socket/test/ + + - name: run tests + timeout-minutes: 10 + run: ./test_wamr.sh ${{ matrix.test_option }} -t ${{ matrix.running_mode }} + working-directory: ./tests/wamr-test-suites + + #only install x32 support libraries when to run x86_32 cases + - name: install x32 support libraries + if: env.TEST_ON_X86_32 == 'true' + run: + # Add another apt repository as some packages cannot + # be downloaded with the github default repository + sudo curl -sSL https://packages.microsoft.com/keys/microsoft.asc | sudo tee /etc/apt/trusted.gpg.d/microsoft.asc && + sudo apt-add-repository https://packages.microsoft.com/ubuntu/${{ matrix.ubuntu_version }}/prod && + sudo apt-get update && + sudo apt install -y g++-multilib lib32gcc-9-dev + + - name: run tests x86_32 + timeout-minutes: 10 + 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 diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/.github/workflows/compilation_on_macos.yml b/lib/wasm-micro-runtime-WAMR-1.2.2/.github/workflows/compilation_on_macos.yml similarity index 55% rename from lib/wasm-micro-runtime-WAMR-1.1.1/.github/workflows/compilation_on_macos.yml rename to lib/wasm-micro-runtime-WAMR-1.2.2/.github/workflows/compilation_on_macos.yml index ceacacd81b9..aaa97d038cd 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/.github/workflows/compilation_on_macos.yml +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/.github/workflows/compilation_on_macos.yml @@ -6,20 +6,38 @@ name: compilation on macos-latest on: # will be triggered on PR events pull_request: - paths-ignore: - - "assembly-script/**" - - "ci/**" - - "doc/**" - - "test-tools/**" + types: + - opened + - synchronize + paths: + - ".github/workflows/build_llvm_libraries.yml" - ".github/workflows/compilation_on_macos.yml" + - "build-scripts/**" + - "core/**" + - "!core/deps/**" + - "product-mini/**" + - "samples/**" + - "!samples/workload/**" + - "tests/wamr-test-suites/**" + - "wamr-compiler/**" + - "wamr-sdk/**" # will be triggered on push events push: - paths-ignore: - - "assembly-script/**" - - "ci/**" - - "doc/**" - - "test-tools/**" + branches: + - main + - "dev/**" + paths: + - ".github/workflows/build_llvm_libraries.yml" - ".github/workflows/compilation_on_macos.yml" + - "build-scripts/**" + - "core/**" + - "!core/deps/**" + - "product-mini/**" + - "samples/**" + - "!samples/workload/**" + - "tests/wamr-test-suites/**" + - "wamr-compiler/**" + - "wamr-sdk/**" # allow to be triggered manually workflow_dispatch: @@ -33,101 +51,30 @@ env: AOT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=0 -DWAMR_BUILD_LAZY_JIT=0" CLASSIC_INTERP_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=0 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=1 -DWAMR_BUILD_JIT=0 -DWAMR_BUILD_LAZY_JIT=0" FAST_INTERP_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=0 -DWAMR_BUILD_FAST_INTERP=1 -DWAMR_BUILD_INTERP=1 -DWAMR_BUILD_JIT=0 -DWAMR_BUILD_LAZY_JIT=0" - LAZY_JIT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=1" - MC_JIT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=0" - LLVM_CACHE_SUFFIX: "build-llvm_libraries_ex" + LLVM_LAZY_JIT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=1" + LLVM_EAGER_JIT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=0" jobs: - # Cancel any in-flight jobs for the same PR/branch so there's only one active - # at a time - cancel_previous: - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [macos-latest] - steps: - - name: Cancel Workflow Action - uses: styfle/cancel-workflow-action@0.9.1 - with: - access_token: ${{ github.token }} - - # set different traffic lights based on the current repo and the running OS. - # according to light colors, the workflow will run different jobs - check_repo: - needs: cancel_previous - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [macos-latest] - outputs: - traffic_light: ${{ steps.do_check.outputs.light }} - steps: - - name: do_check - id: do_check - if: ${{ matrix.os == 'macos-latest' }} - run: | - if [[ ${{ github.repository }} == */wasm-micro-runtime ]]; then - echo "::set-output name=light::green" - else - echo "::set-output name=light::red" - fi - build_llvm_libraries: - needs: check_repo - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [macos-latest] - include: - - os: macos-latest - light: ${{ needs.check_repo.outputs.traffic_light }} - steps: - - name: light status - run: echo "matrix.os=${{ matrix.os }}, light=${{ matrix.light }}" - - - name: checkout - if: ${{ matrix.light == 'green' }} - uses: actions/checkout@v3 - - - name: Cache LLVM libraries - id: cache_llvm - if: ${{ matrix.light == 'green' }} - uses: actions/cache@v3 - with: - path: | - ./core/deps/llvm/build/bin - ./core/deps/llvm/build/include - ./core/deps/llvm/build/lib - ./core/deps/llvm/build/libexec - ./core/deps/llvm/build/share - key: ${{ matrix.os }}-${{ env.LLVM_CACHE_SUFFIX }} - - - name: Build llvm and clang from source - id: build_llvm - if: ${{ matrix.light == 'green' && steps.cache_llvm.outputs.cache-hit != 'true' }} - run: /usr/bin/env python3 ./build_llvm.py --arch X86 WebAssembly - working-directory: build-scripts + uses: ./.github/workflows/build_llvm_libraries.yml + with: + os: "macos-latest" + arch: "X86" build_wamrc: - needs: [build_llvm_libraries, check_repo] + needs: [build_llvm_libraries] runs-on: ${{ matrix.os }} strategy: matrix: - os: [macos-latest] include: - os: macos-latest - light: ${{ needs.check_repo.outputs.traffic_light }} + llvm_cache_key: ${{ needs.build_llvm_libraries.outputs.cache_key }} steps: - - name: light status - run: echo "matrix.os=${{ matrix.os }}, light=${{ matrix.light }}" - - name: checkout - if: ${{ matrix.light == 'green' }} uses: actions/checkout@v3 - name: Get LLVM libraries - id: cache_llvm - if: ${{ matrix.light == 'green' }} + id: retrieve_llvm_libs uses: actions/cache@v3 with: path: | @@ -136,14 +83,13 @@ jobs: ./core/deps/llvm/build/lib ./core/deps/llvm/build/libexec ./core/deps/llvm/build/share - key: ${{ matrix.os }}-${{ env.LLVM_CACHE_SUFFIX }} + key: ${{ matrix.llvm_cache_key }} - name: Quit if cache miss - if: ${{ matrix.light == 'green' && steps.cache_llvm.outputs.cache-hit != 'true' }} + if: steps.retrieve_llvm_libs.outputs.cache-hit != 'true' run: echo "::error::can not get prebuilt llvm libraries" && exit 1 - name: Build wamrc - if: ${{ matrix.light == 'green' }} run: | mkdir build && cd build cmake .. @@ -151,7 +97,7 @@ jobs: working-directory: wamr-compiler build_iwasm: - needs: [build_llvm_libraries, check_repo] + needs: [build_llvm_libraries] runs-on: ${{ matrix.os }} strategy: matrix: @@ -160,8 +106,8 @@ jobs: $AOT_BUILD_OPTIONS, $CLASSIC_INTERP_BUILD_OPTIONS, $FAST_INTERP_BUILD_OPTIONS, - $LAZY_JIT_BUILD_OPTIONS, - $MC_JIT_BUILD_OPTIONS, + $LLVM_LAZY_JIT_BUILD_OPTIONS, + $LLVM_EAGER_JIT_BUILD_OPTIONS, ] make_options_feature: [ # Features @@ -171,6 +117,7 @@ jobs: "-DWAMR_BUILD_DEBUG_INTERP=1", "-DWAMR_BUILD_DUMP_CALL_STACK=1", "-DWAMR_BUILD_LIB_PTHREAD=1", + "-DWAMR_BUILD_LIB_WASI_THREADS=1", "-DWAMR_BUILD_LOAD_CUSTOM_SECTION=1", "-DWAMR_BUILD_MINI_LOADER=1", "-DWAMR_BUILD_MEMORY_PROFILING=1", @@ -187,11 +134,11 @@ jobs: # uncompatiable feature and platform # uncompatiable mode and feature # MULTI_MODULE only on INTERP mode - - make_options_run_mode: $LAZY_JIT_BUILD_OPTIONS + - make_options_run_mode: $LLVM_LAZY_JIT_BUILD_OPTIONS make_options_feature: "-DWAMR_BUILD_MULTI_MODULE=1" - - make_options_run_mode: $AOT_BUILD_OPTIONS + - make_options_run_mode: $LLVM_EAGER_JIT_BUILD_OPTIONS make_options_feature: "-DWAMR_BUILD_MULTI_MODULE=1" - - make_options_run_mode: $MC_JIT_BUILD_OPTIONS + - make_options_run_mode: $AOT_BUILD_OPTIONS make_options_feature: "-DWAMR_BUILD_MULTI_MODULE=1" # SIMD only on JIT/AOT mode - make_options_run_mode: $CLASSIC_INTERP_BUILD_OPTIONS @@ -201,9 +148,9 @@ jobs: # DEBUG_INTERP only on CLASSIC INTERP mode - make_options_run_mode: $AOT_BUILD_OPTIONS make_options_feature: "-DWAMR_BUILD_DEBUG_INTERP=1" - - make_options_run_mode: $LAZY_JIT_BUILD_OPTIONS + - make_options_run_mode: $LLVM_LAZY_JIT_BUILD_OPTIONS make_options_feature: "-DWAMR_BUILD_DEBUG_INTERP=1" - - make_options_run_mode: $MC_JIT_BUILD_OPTIONS + - make_options_run_mode: $LLVM_EAGER_JIT_BUILD_OPTIONS make_options_feature: "-DWAMR_BUILD_DEBUG_INTERP=1" - make_options_run_mode: $FAST_INTERP_BUILD_OPTIONS make_options_feature: "-DWAMR_BUILD_DEBUG_INTERP=1" @@ -213,32 +160,28 @@ jobs: - make_options_run_mode: $FAST_INTERP_BUILD_OPTIONS make_options_feature: "-DWAMR_BUILD_DEBUG_AOT=1" # TODO: DEBUG_AOT on JIT - - make_options_run_mode: $LAZY_JIT_BUILD_OPTIONS + - make_options_run_mode: $LLVM_LAZY_JIT_BUILD_OPTIONS make_options_feature: "-DWAMR_BUILD_DEBUG_AOT=1" - - make_options_run_mode: $MC_JIT_BUILD_OPTIONS + - make_options_run_mode: $LLVM_EAGER_JIT_BUILD_OPTIONS make_options_feature: "-DWAMR_BUILD_DEBUG_AOT=1" # MINI_LOADER only on INTERP mode - make_options_run_mode: $AOT_BUILD_OPTIONS make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1" - - make_options_run_mode: $LAZY_JIT_BUILD_OPTIONS + - make_options_run_mode: $LLVM_LAZY_JIT_BUILD_OPTIONS make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1" - - make_options_run_mode: $MC_JIT_BUILD_OPTIONS + - make_options_run_mode: $LLVM_EAGER_JIT_BUILD_OPTIONS make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1" include: - os: macos-latest - light: ${{ needs.check_repo.outputs.traffic_light }} + llvm_cache_key: ${{ needs.build_llvm_libraries.outputs.cache_key }} steps: - - name: light status - run: echo "matrix.os=${{ matrix.os }}, light=${{ matrix.light }}" - - name: checkout - if: ${{ matrix.light == 'green' }} uses: actions/checkout@v3 # only download llvm cache when needed - name: Get LLVM libraries - id: cache_llvm - if: (matrix.light == 'green') && (endsWith(matrix.make_options_run_mode, '_JIT_BUILD_OPTIONS')) + id: retrieve_llvm_libs + if: endsWith(matrix.make_options_run_mode, '_JIT_BUILD_OPTIONS') uses: actions/cache@v3 with: path: | @@ -247,14 +190,13 @@ jobs: ./core/deps/llvm/build/lib ./core/deps/llvm/build/libexec ./core/deps/llvm/build/share - key: ${{ matrix.os }}-${{ env.LLVM_CACHE_SUFFIX }} + key: ${{ matrix.llvm_cache_key }} - name: Quit if cache miss - if: (matrix.light == 'green') && (endsWith(matrix.make_options_run_mode, '_JIT_BUILD_OPTIONS')) && (steps.cache_llvm.outputs.cache-hit != 'true') + if: endsWith(matrix.make_options_run_mode, '_JIT_BUILD_OPTIONS') && (steps.retrieve_llvm_libs.outputs.cache-hit != 'true') run: echo "::error::can not get prebuilt llvm libraries" && exit 1 - name: Build iwasm - if: ${{ matrix.light == 'green' }} run: | mkdir build && cd build cmake .. ${{ matrix.make_options_run_mode }} ${{ matrix.make_options_feature }} @@ -262,102 +204,85 @@ jobs: working-directory: product-mini/platforms/${{ matrix.platform }} build_samples_wasm_c_api: - needs: [build_iwasm, check_repo] + needs: [build_iwasm] runs-on: ${{ matrix.os }} strategy: matrix: make_options: [ - # Running mode + # Running modes supported $CLASSIC_INTERP_BUILD_OPTIONS, $FAST_INTERP_BUILD_OPTIONS, - # doesn't support - #$LAZY_JIT_BUILD_OPTIONS, - #$MC_JIT_BUILD_OPTIONS, + # Running modes unsupported + #$LLVM_LAZY_JIT_BUILD_OPTIONS, + #$LLVM_EAGER_JIT_BUILD_OPTIONS, #$AOT_BUILD_OPTIONS, ] os: [macos-latest] - include: - - os: macos-latest - light: ${{ needs.check_repo.outputs.traffic_light }} - wasi_sdk_release: https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-12/wasi-sdk-12.0-macos.tar.gz - wabt_release: https://github.com/WebAssembly/wabt/releases/download/1.0.24/wabt-1.0.24-macos.tar.gz + wasi_sdk_release: + [ + "https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-20/wasi-sdk-20.0-macos.tar.gz", + ] + wabt_release: + [ + "https://github.com/WebAssembly/wabt/releases/download/1.0.31/wabt-1.0.31-macos-12.tar.gz", + ] steps: - - name: light status - run: echo "matrix.os=${{ matrix.os }}, light=${{ matrix.light }}" - - name: checkout - if: ${{ matrix.light == 'green' }} uses: actions/checkout@v3 - name: download and install wabt - if: ${{ matrix.light == 'green' }} run: | cd /opt sudo wget ${{ matrix.wabt_release }} - sudo tar -xzf wabt-1.0.24-*.tar.gz - sudo mv wabt-1.0.24 wabt + sudo tar -xzf wabt-1.0.31-*.tar.gz + sudo mv wabt-1.0.31 wabt - name: Build Sample [wasm-c-api] - if: ${{ matrix.light == 'green' }} run: | - mkdir build && cd build - cmake .. ${{ matrix.make_options }} - cmake --build . --config Release --parallel 4 - ./callback - ./callback_chain - ./empty_imports - ./global - ./hello - ./hostref - ./memory - ./reflect - ./table - ./trap + cmake -S . -B build ${{ matrix.make_options }} + cmake --build build --config Release --parallel 4 + ctest --test-dir build working-directory: samples/wasm-c-api build_samples_others: - needs: [build_iwasm, check_repo] + needs: [build_iwasm] runs-on: ${{ matrix.os }} strategy: matrix: - include: - - os: macos-latest - light: ${{ needs.check_repo.outputs.traffic_light }} - wasi_sdk_release: https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-12/wasi-sdk-12.0-macos.tar.gz - wabt_release: https://github.com/WebAssembly/wabt/releases/download/1.0.24/wabt-1.0.24-macos.tar.gz + os: [macos-latest] + wasi_sdk_release: + [ + "https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-20/wasi-sdk-20.0-macos.tar.gz", + ] + wabt_release: + [ + "https://github.com/WebAssembly/wabt/releases/download/1.0.31/wabt-1.0.31-macos-12.tar.gz", + ] steps: - - name: light status - run: echo "matrix.os=${{ matrix.os }}, light=${{ matrix.light }}" - - name: checkout - if: ${{ matrix.light == 'green' }} uses: actions/checkout@v3 - name: download and install wasi-sdk - if: ${{ matrix.light == 'green' }} run: | cd /opt sudo wget ${{ matrix.wasi_sdk_release }} - sudo tar -xzf wasi-sdk-12.0-*.tar.gz - sudo mv wasi-sdk-12.0 wasi-sdk + sudo tar -xzf wasi-sdk-*.tar.gz + sudo mv wasi-sdk-20.0 wasi-sdk - name: download and install wabt - if: ${{ matrix.light == 'green' }} run: | cd /opt sudo wget ${{ matrix.wabt_release }} - sudo tar -xzf wabt-1.0.24-*.tar.gz - sudo mv wabt-1.0.24 wabt + sudo tar -xzf wabt-1.0.31-*.tar.gz + sudo mv wabt-1.0.31 wabt - name: Build Sample [basic] - if: ${{ matrix.light == 'green' }} run: | cd samples/basic ./build.sh ./run.sh - name: Build Sample [file] - if: ${{ matrix.light == 'green' }} run: | cd samples/file mkdir build && cd build @@ -366,7 +291,6 @@ jobs: ./src/iwasm -f wasm-app/file.wasm -d . - name: Build Sample [multi-thread] - if: ${{ matrix.light == 'green' }} run: | cd samples/multi-thread mkdir build && cd build @@ -375,7 +299,6 @@ jobs: ./iwasm wasm-apps/test.wasm - name: Build Sample [multi-module] - if: ${{ matrix.light == 'green' }} run: | cd samples/multi-module mkdir build && cd build @@ -384,7 +307,6 @@ jobs: ./multi_module - name: Build Sample [spawn-thread] - if: ${{ matrix.light == 'green' }} run: | cd samples/spawn-thread mkdir build && cd build @@ -393,10 +315,17 @@ jobs: ./spawn_thread - name: Build Sample [ref-types] - if: ${{ matrix.light == 'green' }} run: | cd samples/ref-types mkdir build && cd build cmake .. cmake --build . --config Release --parallel 4 ./hello + + - name: Build Sample [wasi-threads] + run: | + cd samples/wasi-threads + mkdir build && cd build + cmake .. + cmake --build . --config Release --parallel 4 + ./iwasm wasm-apps/no_pthread.wasm diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/.github/workflows/compilation_on_nuttx.yml b/lib/wasm-micro-runtime-WAMR-1.2.2/.github/workflows/compilation_on_nuttx.yml similarity index 58% rename from lib/wasm-micro-runtime-WAMR-1.1.1/.github/workflows/compilation_on_nuttx.yml rename to lib/wasm-micro-runtime-WAMR-1.2.2/.github/workflows/compilation_on_nuttx.yml index 41b075fa4c5..f338c8dea7b 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/.github/workflows/compilation_on_nuttx.yml +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/.github/workflows/compilation_on_nuttx.yml @@ -6,18 +6,36 @@ name: compilation on nuttx on: # will be triggered on PR events pull_request: - paths-ignore: - - "assembly-script/**" - - "ci/**" - - "doc/**" - - "test-tools/**" + types: + - opened + - synchronize + paths: + - ".github/workflows/compilation_on_nuttx.yml" + - "build-scripts/**" + - "core/**" + - "!core/deps/**" + - "product-mini/**" + - "samples/**" + - "!samples/workload/**" + - "tests/wamr-test-suites/**" + - "wamr-compiler/**" + - "wamr-sdk/**" # will be triggered on push events push: - paths-ignore: - - "assembly-script/**" - - "ci/**" - - "doc/**" - - "test-tools/**" + branches: + - main + - "dev/**" + paths: + - ".github/workflows/compilation_on_nuttx.yml" + - "build-scripts/**" + - "core/**" + - "!core/deps/**" + - "product-mini/**" + - "samples/**" + - "!samples/workload/**" + - "tests/wamr-test-suites/**" + - "wamr-compiler/**" + - "wamr-sdk/**" # allow to be triggered manually workflow_dispatch: @@ -27,32 +45,21 @@ concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true -jobs: - # Cancel any in-flight jobs for the same PR/branch so there's only one active - # at a time - cancel_previous: - runs-on: ubuntu-22.04 - steps: - - name: Cancel Workflow Action - uses: styfle/cancel-workflow-action@0.9.1 - with: - access_token: ${{ github.token }} +env: + WASI_SDK_PATH: "/opt/wasi-sdk" +jobs: build_iwasm_on_nuttx: runs-on: ubuntu-22.04 strategy: matrix: - nuttx_board_config : [ + nuttx_board_config: [ # x64 "boards/sim/sim/sim/configs/nsh", # cortex-m0 "boards/arm/rp2040/raspberrypi-pico/configs/nsh", - # cortex-m4 - "boards/arm/stm32/stm32f4discovery/configs/nsh", # cortex-m7 "boards/arm/stm32h7/nucleo-h743zi/configs/nsh", - # cortex-a9 - "boards/arm/imx6/sabre-6quad/configs/nsh", # riscv32imac "boards/risc-v/qemu-rv/rv-virt/configs/nsh", # riscv64imac @@ -61,9 +68,12 @@ jobs: "boards/risc-v/k210/maix-bit/configs/nsh", ] wamr_config_option: [ - "CONFIG_INTERPRETERS_WAMR=y\\nCONFIG_INTERPRETERS_WAMR_AOT=y\\nCONFIG_INTERPRETERS_WAMR_FAST=y\\nCONFIG_INTERPRETERS_WAMR_LIBC_BUILTIN=y\\n", "CONFIG_INTERPRETERS_WAMR=y\\nCONFIG_INTERPRETERS_WAMR_AOT=y\\nCONFIG_INTERPRETERS_WAMR_FAST=y\\n", + "CONFIG_INTERPRETERS_WAMR=y\\nCONFIG_INTERPRETERS_WAMR_AOT=y\\nCONFIG_INTERPRETERS_WAMR_FAST=y\\nCONFIG_INTERPRETERS_WAMR_LIBC_WASI=y\\n", + "CONFIG_INTERPRETERS_WAMR=y\\nCONFIG_INTERPRETERS_WAMR_AOT=y\\nCONFIG_INTERPRETERS_WAMR_FAST=y\\nCONFIG_INTERPRETERS_WAMR_LIBC_BUILTIN=y\\n", "CONFIG_INTERPRETERS_WAMR=y\\nCONFIG_INTERPRETERS_WAMR_AOT=y\\nCONFIG_INTERPRETERS_WAMR_CLASSIC=y\\n", + "CONFIG_INTERPRETERS_WAMR=y\\nCONFIG_INTERPRETERS_WAMR_AOT=y\\nCONFIG_INTERPRETERS_WAMR_CLASSIC=y\\nCONFIG_INTERPRETERS_WAMR_LIBC_WASI=y\\n", + "CONFIG_INTERPRETERS_WAMR=y\\nCONFIG_INTERPRETERS_WAMR_AOT=y\\nCONFIG_INTERPRETERS_WAMR_CLASSIC=y\\nCONFIG_INTERPRETERS_WAMR_LIBC_BUILTIN=y\\n", "CONFIG_INTERPRETERS_WAMR=y\\nCONFIG_INTERPRETERS_WAMR_AOT=y\\nCONFIG_INTERPRETERS_WAMR_LIBC_BUILTIN=y\\n", "CONFIG_INTERPRETERS_WAMR=y\\nCONFIG_INTERPRETERS_WAMR_AOT=y\\n", "CONFIG_INTERPRETERS_WAMR=y\\nCONFIG_INTERPRETERS_WAMR_FAST=y\\n", @@ -72,18 +82,27 @@ jobs: steps: - name: Install Utilities - run: | + run: | sudo apt install -y kconfig-frontends-nox genromfs pip3 install pyelftools pip3 install cxxfilt - name: Install ARM Compilers - if: ${{ contains(matrix.nuttx_board_config, 'arm') }} + if: contains(matrix.nuttx_board_config, 'arm') run: sudo apt install -y gcc-arm-none-eabi - name: Install RISC-V Compilers - if: ${{ contains(matrix.nuttx_board_config, 'risc-v') }} - run: sudo apt install -y gcc-riscv64-unknown-elf + if: contains(matrix.nuttx_board_config, 'risc-v') + run: | + curl -L https://static.dev.sifive.com/dev-tools/freedom-tools/v2020.12/riscv64-unknown-elf-toolchain-10.2.0-2020.12.8-x86_64-linux-ubuntu14.tar.gz > riscv.tar.gz + tar xvf riscv.tar.gz + echo "$PWD/riscv64-unknown-elf-toolchain-10.2.0-2020.12.8-x86_64-linux-ubuntu14/bin" >> $GITHUB_PATH + + - name: Install WASI-SDK + run: | + curl -L https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-19/wasi-sdk-19.0-linux.tar.gz > wasi-sdk.tar.gz + tar xvf wasi-sdk.tar.gz + sudo mv wasi-sdk-* /opt/wasi-sdk - name: Checkout NuttX uses: actions/checkout@v3 @@ -104,13 +123,12 @@ jobs: path: apps/interpreters/wamr/wamr - name: Enable WAMR for NuttX - run: | - find nuttx/boards -name defconfig | xargs sed -i '$a\CONFIG_EOL_IS_CR=y\n${{ matrix.wamr_config_option }}' + run: | + find nuttx/boards -name defconfig | xargs sed -i '$a\CONFIG_EOL_IS_LF=y\nCONFIG_PSEUDOFS_SOFTLINKS=y\n${{ matrix.wamr_config_option }}' find nuttx/boards/sim -name defconfig | xargs sed -i '$a\CONFIG_LIBM=y\n' - find nuttx/boards/risc-v -name defconfig | xargs sed -i '$a\CONFIG_LIBM=y\n' - name: Build run: | cd nuttx tools/configure.sh ${{ matrix.nuttx_board_config }} - make -j$(nproc) + make -j$(nproc) EXTRAFLAGS=-Werror diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/.github/workflows/compilation_on_sgx.yml b/lib/wasm-micro-runtime-WAMR-1.2.2/.github/workflows/compilation_on_sgx.yml similarity index 60% rename from lib/wasm-micro-runtime-WAMR-1.1.1/.github/workflows/compilation_on_sgx.yml rename to lib/wasm-micro-runtime-WAMR-1.2.2/.github/workflows/compilation_on_sgx.yml index 98ebb457a2a..f17261118fe 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/.github/workflows/compilation_on_sgx.yml +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/.github/workflows/compilation_on_sgx.yml @@ -6,20 +6,38 @@ name: compilation on SGX on: # will be triggered on PR events pull_request: - paths-ignore: - - "assembly-script/**" - - "ci/**" - - "doc/**" - - "test-tools/**" + types: + - opened + - synchronize + paths: + - ".github/workflows/build_llvm_libraries.yml" - ".github/workflows/compilation_on_sgx.yml" + - "build-scripts/**" + - "core/**" + - "!core/deps/**" + - "product-mini/**" + - "samples/**" + - "!samples/workload/**" + - "tests/wamr-test-suites/**" + - "wamr-compiler/**" + - "wamr-sdk/**" # will be triggered on push events push: - paths-ignore: - - "assembly-script/**" - - "ci/**" - - "doc/**" - - "test-tools/**" + branches: + - main + - "dev/**" + paths: + - ".github/workflows/build_llvm_libraries.yml" - ".github/workflows/compilation_on_sgx.yml" + - "build-scripts/**" + - "core/**" + - "!core/deps/**" + - "product-mini/**" + - "samples/**" + - "!samples/workload/**" + - "tests/wamr-test-suites/**" + - "wamr-compiler/**" + - "wamr-sdk/**" # allow to be triggered manually workflow_dispatch: @@ -33,94 +51,28 @@ env: AOT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=0 -DWAMR_BUILD_LAZY_JIT=0" CLASSIC_INTERP_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=0 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=1 -DWAMR_BUILD_JIT=0 -DWAMR_BUILD_LAZY_JIT=0" FAST_INTERP_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=0 -DWAMR_BUILD_FAST_INTERP=1 -DWAMR_BUILD_INTERP=1 -DWAMR_BUILD_JIT=0 -DWAMR_BUILD_LAZY_JIT=0" - LAZY_JIT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=1" - MC_JIT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=0" - LLVM_CACHE_SUFFIX: "build-llvm_libraries_ex" + LLVM_LAZY_JIT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=1" + LLVM_EAGER_JIT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=0" jobs: - # Cancel any in-flight jobs for the same PR/branch so there's only one active - # at a time - cancel_previous: - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-20.04] - steps: - - name: Cancel Workflow Action - uses: styfle/cancel-workflow-action@0.9.1 - with: - access_token: ${{ github.token }} - - # set different traffic lights based on the current repo and the running OS. - # according to light colors, the workflow will run different jobs - check_repo: - needs: cancel_previous - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-20.04] - outputs: - traffic_light_on_ubuntu_2004: ${{ steps.do_check_on_ubuntu_2004.outputs.light }} - steps: - - name: do_check_on_ubuntu_2004 - id: do_check_on_ubuntu_2004 - if: ${{ matrix.os == 'ubuntu-20.04' }} - run: | - if [[ ${{ github.repository }} == */wasm-micro-runtime ]]; then - echo "::set-output name=light::green" - else - echo "::set-output name=light::green" - fi - build_llvm_libraries: - needs: check_repo - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-20.04] - include: - - os: ubuntu-20.04 - light: ${{ needs.check_repo.outputs.traffic_light_on_ubuntu_2004 }} - steps: - - name: light status - run: echo "matrix.os=${{ matrix.os }}, light=${{ matrix.light }}" - - - name: checkout - if: ${{ matrix.light == 'green' }} - uses: actions/checkout@v3 - - - name: Cache LLVM libraries - id: cache_llvm - if: ${{ matrix.light == 'green' }} - uses: actions/cache@v3 - with: - path: | - ./core/deps/llvm/build/bin - ./core/deps/llvm/build/include - ./core/deps/llvm/build/lib - ./core/deps/llvm/build/libexec - ./core/deps/llvm/build/share - key: ${{ matrix.os }}-${{ env.LLVM_CACHE_SUFFIX }} - - - name: Build llvm and clang from source - id: build_llvm - if: ${{ matrix.light == 'green' && steps.cache_llvm.outputs.cache-hit != 'true' }} - run: /usr/bin/env python3 ./build_llvm.py --arch X86 WebAssembly --project clang lldb - working-directory: build-scripts + uses: ./.github/workflows/build_llvm_libraries.yml + with: + os: "ubuntu-20.04" + arch: "X86" build_iwasm: - needs: [check_repo] runs-on: ${{ matrix.os }} strategy: matrix: make_options_run_mode: [ - # Running mode + # Running modes supported $AOT_BUILD_OPTIONS, $CLASSIC_INTERP_BUILD_OPTIONS, $FAST_INTERP_BUILD_OPTIONS, - # doesn't support - # $LAZY_JIT_BUILD_OPTIONS, - # $MC_JIT_BUILD_OPTIONS, + # Running modes unsupported + #$LLVM_LAZY_JIT_BUILD_OPTIONS, + #$LLVM_EAGER_JIT_BUILD_OPTIONS, ] make_options_feature: [ # Features @@ -130,6 +82,7 @@ jobs: # "-DWAMR_BUILD_DEBUG_INTERP=1", "-DWAMR_BUILD_DUMP_CALL_STACK=1", "-DWAMR_BUILD_LIB_PTHREAD=1", + "-DWAMR_BUILD_LIB_WASI_THREADS=1", "-DWAMR_BUILD_LOAD_CUSTOM_SECTION=1", "-DWAMR_BUILD_MINI_LOADER=1", "-DWAMR_BUILD_MEMORY_PROFILING=1", @@ -152,15 +105,8 @@ jobs: # MINI_LOADER only on INTERP mode - make_options_run_mode: $AOT_BUILD_OPTIONS make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1" - include: - - os: ubuntu-20.04 - light: ${{ needs.check_repo.outputs.traffic_light_on_ubuntu_2004 }} steps: - - name: light status - run: echo "matrix.os=${{ matrix.os }}, light=${{ matrix.light }}" - - name: install SGX SDK and necessary libraries - if: ${{ matrix.light == 'green' }} run: | mkdir -p /opt/intel cd /opt/intel @@ -174,11 +120,9 @@ jobs: source /opt/intel/sgxsdk/environment - name: checkout - if: ${{ matrix.light == 'green' }} uses: actions/checkout@v3 - name: Build iwasm - if: ${{ matrix.light == 'green' }} run: | mkdir build && cd build cmake .. ${{ matrix.make_options_run_mode }} ${{ matrix.make_options_feature }} @@ -186,20 +130,15 @@ jobs: working-directory: product-mini/platforms/${{ matrix.platform }} build_wamrc: - needs: [build_llvm_libraries, check_repo] + needs: [build_llvm_libraries] runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-20.04] include: - os: ubuntu-20.04 - light: ${{ needs.check_repo.outputs.traffic_light_on_ubuntu_2004 }} + llvm_cache_key: ${{ needs.build_llvm_libraries.outputs.cache_key }} steps: - - name: light status - run: echo "matrix.os=${{ matrix.os }}, light=${{ matrix.light }}" - - name: install SGX SDK and necessary libraries - if: ${{ matrix.light == 'green' }} run: | mkdir -p /opt/intel cd /opt/intel @@ -213,12 +152,10 @@ jobs: source /opt/intel/sgxsdk/environment - name: checkout - if: ${{ matrix.light == 'green' }} uses: actions/checkout@v3 - name: Get LLVM libraries - id: cache_llvm - if: ${{ matrix.light == 'green' }} + id: retrieve_llvm_libs uses: actions/cache@v3 with: path: | @@ -227,14 +164,13 @@ jobs: ./core/deps/llvm/build/lib ./core/deps/llvm/build/libexec ./core/deps/llvm/build/share - key: ${{ matrix.os }}-${{ env.LLVM_CACHE_SUFFIX }} + key: ${{ matrix.llvm_cache_key }} - name: Quit if cache miss - if: ${{ matrix.light == 'green' && steps.cache_llvm.outputs.cache-hit != 'true' }} + if: steps.retrieve_llvm_libs.outputs.cache-hit != 'true' run: echo "::error::can not get prebuilt llvm libraries" && exit 1 - name: Build wamrc - if: ${{ matrix.light == 'green' }} run: | mkdir build && cd build cmake .. @@ -242,43 +178,40 @@ jobs: working-directory: wamr-compiler build_samples_wasm_c_api: - needs: [build_iwasm, check_repo] + needs: [build_iwasm] runs-on: ${{ matrix.os }} strategy: matrix: make_options: [ - # Running mode + # Running modes supported $CLASSIC_INTERP_BUILD_OPTIONS, $FAST_INTERP_BUILD_OPTIONS, - # doesn't support - #$LAZY_JIT_BUILD_OPTIONS, - #$MC_JIT_BUILD_OPTIONS, + # Running modes unsupported + #$LLVM_EAGER_JIT_BUILD_OPTIONS, + #$LLVM_LAZY_JIT_BUILD_OPTIONS, #$AOT_BUILD_OPTIONS, ] os: [ubuntu-20.04] - include: - - os: ubuntu-20.04 - light: ${{ needs.check_repo.outputs.traffic_light_on_ubuntu_2004 }} - wasi_sdk_release: https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-12/wasi-sdk-12.0-linux.tar.gz - wabt_release: https://github.com/WebAssembly/wabt/releases/download/1.0.24/wabt-1.0.24-ubuntu.tar.gz + wasi_sdk_release: + [ + "https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-19/wasi-sdk-19.0-linux.tar.gz", + ] + wabt_release: + [ + "https://github.com/WebAssembly/wabt/releases/download/1.0.31/wabt-1.0.31-ubuntu.tar.gz", + ] steps: - - name: light status - run: echo "matrix.os=${{ matrix.os }}, light=${{ matrix.light }}" - - name: checkout - if: ${{ matrix.light == 'green' }} uses: actions/checkout@v3 - name: download and install wabt - if: ${{ matrix.light == 'green' }} run: | cd /opt sudo wget ${{ matrix.wabt_release }} - sudo tar -xzf wabt-1.0.24-*.tar.gz - sudo mv wabt-1.0.24 wabt + sudo tar -xzf wabt-1.0.31-*.tar.gz + sudo mv wabt-1.0.31 wabt - name: install SGX SDK and necessary libraries - if: ${{ matrix.light == 'green' }} run: | mkdir -p /opt/intel cd /opt/intel @@ -292,59 +225,61 @@ jobs: source /opt/intel/sgxsdk/environment - name: Build Sample [wasm-c-api] - if: ${{ matrix.light == 'green' }} run: | - mkdir build && cd build - cmake .. ${{ matrix.make_options }} - cmake --build . --config Release --parallel 4 - ./callback - ./callback_chain - ./empty_imports - ./global - ./hello - ./hostref - ./memory - ./reflect - ./table - ./trap + cmake -S . -B build ${{ matrix.make_options }} + cmake --build build --config Release --parallel 4 + ctest --test-dir build working-directory: samples/wasm-c-api build_samples_others: - needs: [build_iwasm, check_repo] + needs: [build_iwasm] runs-on: ${{ matrix.os }} strategy: matrix: - include: - - os: ubuntu-20.04 - light: ${{ needs.check_repo.outputs.traffic_light_on_ubuntu_2004 }} - wasi_sdk_release: https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-12/wasi-sdk-12.0-linux.tar.gz - wabt_release: https://github.com/WebAssembly/wabt/releases/download/1.0.24/wabt-1.0.24-ubuntu.tar.gz + os: [ubuntu-20.04] + wasi_sdk_release: + [ + "https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-19/wasi-sdk-19.0-linux.tar.gz", + ] + wabt_release: + [ + "https://github.com/WebAssembly/wabt/releases/download/1.0.31/wabt-1.0.31-ubuntu.tar.gz", + ] steps: - - name: light status - run: echo "matrix.os=${{ matrix.os }}, light=${{ matrix.light }}" - - name: checkout - if: ${{ matrix.light == 'green' }} uses: actions/checkout@v3 - name: download and install wasi-sdk - if: ${{ matrix.light == 'green' }} run: | cd /opt sudo wget ${{ matrix.wasi_sdk_release }} - sudo tar -xzf wasi-sdk-12.0-*.tar.gz - sudo mv wasi-sdk-12.0 wasi-sdk + sudo tar -xzf wasi-sdk-*.tar.gz + sudo mv wasi-sdk-19.0 wasi-sdk - name: download and install wabt - if: ${{ matrix.light == 'green' }} run: | cd /opt sudo wget ${{ matrix.wabt_release }} - sudo tar -xzf wabt-1.0.24-*.tar.gz - sudo mv wabt-1.0.24 wabt + sudo tar -xzf wabt-1.0.31-*.tar.gz + sudo mv wabt-1.0.31 wabt + + - name: build wasi-libc (needed for wasi-threads) + run: | + mkdir wasi-libc + cd wasi-libc + git init + # "Fix a_store operation in atomic.h" commit on main branch + git fetch https://github.com/WebAssembly/wasi-libc \ + 1dfe5c302d1c5ab621f7abf04620fae92700fd22 + git checkout FETCH_HEAD + make \ + AR=/opt/wasi-sdk/bin/llvm-ar \ + NM=/opt/wasi-sdk/bin/llvm-nm \ + CC=/opt/wasi-sdk/bin/clang \ + THREAD_MODEL=posix + working-directory: core/deps - name: install SGX SDK and necessary libraries - if: ${{ matrix.light == 'green' }} run: | mkdir -p /opt/intel cd /opt/intel @@ -358,14 +293,12 @@ jobs: source /opt/intel/sgxsdk/environment - name: Build Sample [basic] - if: ${{ matrix.light == 'green' }} run: | cd samples/basic ./build.sh ./run.sh - name: Build Sample [file] - if: ${{ matrix.light == 'green' }} run: | cd samples/file mkdir build && cd build @@ -374,7 +307,6 @@ jobs: ./src/iwasm -f wasm-app/file.wasm -d . - name: Build Sample [multi-thread] - if: ${{ matrix.light == 'green' }} run: | cd samples/multi-thread mkdir build && cd build @@ -383,7 +315,6 @@ jobs: ./iwasm wasm-apps/test.wasm - name: Build Sample [multi-module] - if: ${{ matrix.light == 'green' }} run: | cd samples/multi-module mkdir build && cd build @@ -392,7 +323,6 @@ jobs: ./multi_module - name: Build Sample [spawn-thread] - if: ${{ matrix.light == 'green' }} run: | cd samples/spawn-thread mkdir build && cd build @@ -401,7 +331,6 @@ jobs: ./spawn_thread - name: Build Sample [ref-types] - if: ${{ matrix.light == 'green' }} run: | cd samples/ref-types mkdir build && cd build @@ -409,24 +338,36 @@ jobs: cmake --build . --config Release --parallel 4 ./hello + - name: Build Sample [wasi-threads] + run: | + cd samples/wasi-threads + mkdir build && cd build + cmake -DWASI_SYSROOT=`pwd`/../../../core/deps/wasi-libc/sysroot .. + cmake --build . --config Release --parallel 4 + ./iwasm wasm-apps/no_pthread.wasm + spec_test_default: - needs: [build_iwasm, build_llvm_libraries, build_wamrc, check_repo] + needs: [build_iwasm, build_llvm_libraries, build_wamrc] runs-on: ubuntu-20.04 strategy: matrix: running_mode: ["classic-interp", "fast-interp", "aot"] - test_option: ["-x -p -s spec -P", "-x -p -s spec -S -P"] - include: - - os: ubuntu-20.04 - light: ${{ needs.check_repo.outputs.traffic_light_on_ubuntu_2004 }} + test_option: ["-x -p -s spec -b -P", "-x -p -s spec -S -b -P"] + llvm_cache_key: ["${{ needs.build_llvm_libraries.outputs.cache_key }}"] + # classic-interp and fast-interp don't support simd + exclude: + - running_mode: "classic-interp" + test_option: "-x -p -s spec -S -b -P" + - running_mode: "fast-interp" + test_option: "-x -p -s spec -S -b -P" + steps: - name: checkout - if: ${{ matrix.light == 'green' }} uses: actions/checkout@v3 - name: Get LLVM libraries - if: ${{ matrix.light == 'green' }} - id: cache_llvm + if: matrix.running_mode == 'aot' + id: retrieve_llvm_libs uses: actions/cache@v3 with: path: | @@ -435,18 +376,13 @@ jobs: ./core/deps/llvm/build/lib ./core/deps/llvm/build/libexec ./core/deps/llvm/build/share - key: ubuntu-20.04-${{ env.LLVM_CACHE_SUFFIX }} + key: ${{ matrix.llvm_cache_key }} - name: Quit if cache miss - if: ${{ matrix.light == 'green' && steps.cache_llvm.outputs.cache-hit != 'true' }} + if: matrix.running_mode == 'aot' && steps.retrieve_llvm_libs.outputs.cache-hit != 'true' run: echo "::error::can not get prebuilt llvm libraries" && exit 1 - - name: install Ninja - if: ${{ matrix.light == 'green' }} - run: sudo apt install -y ninja-build - - name: install SGX SDK and necessary libraries - if: ${{ matrix.light == 'green' }} run: | mkdir -p /opt/intel cd /opt/intel @@ -459,7 +395,6 @@ jobs: sudo apt install -y libsgx-launch libsgx-urts - name: run spec tests - if: ${{ matrix.light == 'green' }} run: | source /opt/intel/sgxsdk/environment ./test_wamr.sh ${{ matrix.test_option }} -t ${{ matrix.running_mode }} diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/.github/workflows/compilation_on_windows.yml b/lib/wasm-micro-runtime-WAMR-1.2.2/.github/workflows/compilation_on_windows.yml new file mode 100644 index 00000000000..0d38e8ae554 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/.github/workflows/compilation_on_windows.yml @@ -0,0 +1,77 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +name: compilation on windows-latest + +on: + # will be triggered on PR events + pull_request: + types: + - opened + - synchronize + paths: + - ".github/workflows/compilation_on_windows.yml" + - "build-scripts/**" + - "core/**" + - "!core/deps/**" + - "product-mini/**" + - "samples/**" + - "!samples/workload/**" + - "tests/wamr-test-suites/**" + - "wamr-compiler/**" + - "wamr-sdk/**" + # will be triggered on push events + push: + branches: + - main + - "dev/**" + paths: + - ".github/workflows/compilation_on_windows.yml" + - "build-scripts/**" + - "core/**" + - "!core/deps/**" + - "product-mini/**" + - "samples/**" + - "!samples/workload/**" + - "tests/wamr-test-suites/**" + - "wamr-compiler/**" + - "wamr-sdk/**" + # 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: + build: + runs-on: windows-latest + strategy: + matrix: + build_options: [ + "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_INTERP=0", + "-DWAMR_BUILD_AOT=0", + "-DWAMR_BUILD_TAIL_CALL=1", + "-DWAMR_BUILD_CUSTOM_NAME_SECTION=1", + "-DWAMR_DISABLE_HW_BOUND_CHECK=1", + "-DWAMR_BUILD_REF_TYPES=1", + "-DWAMR_BUILD_SIMD=1", + "-DWAMR_BUILD_DEBUG_INTERP=1", + "-DWAMR_BUILD_LIB_PTHREAD=1", + "-DWAMR_BUILD_LIB_WASI_THREADS=1" + ] + steps: + - uses: actions/checkout@v3 + + - name: clone uvwasi library + run: | + cd core/deps + git clone https://github.com/nodejs/uvwasi.git + - name: Build iwasm + run: | + cd product-mini/platforms/windows + mkdir build && cd build + cmake .. ${{ matrix.build_options }} + cmake --build . --config Release --parallel 4 diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/.github/workflows/create_tag.yml b/lib/wasm-micro-runtime-WAMR-1.2.2/.github/workflows/create_tag.yml new file mode 100644 index 00000000000..3a145bf041e --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/.github/workflows/create_tag.yml @@ -0,0 +1,68 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +name: create a tag + +on: + workflow_call: + outputs: + minor_version: + description: "the new version is a minor version or a major version" + value: ${{ jobs.create_tag.outputs.minor_version}} + new_ver: + description: "the new version" + value: ${{ jobs.create_tag.outputs.new_ver}} + new_tag: + description: "the new tag just created" + value: ${{ jobs.create_tag.outputs.new_tag}} + +jobs: + create_tag: + runs-on: ubuntu-latest + outputs: + minor_version: ${{ steps.preparation.outputs.minor_version }} + new_ver: ${{ steps.preparation.outputs.new_ver }} + new_tag: ${{ steps.preparation.outputs.new_tag }} + + steps: + - uses: actions/checkout@v3 + # Full git history is needed to get a proper list of commits and tags + with: + fetch-depth: 0 + + - name: prepare + id: preparation + run: | + # show latest 3 versions + git tag --list WAMR-*.*.* --sort=committerdate --format="%(refname:short)" | tail -n 3 + # compare latest git tag and semantic version definition + result=$(python3 ./.github/scripts/fetch_and_compare_version.py) + echo "script result is ${result}" + # + # return in a form like "WAMR-X.Y.Z,major_minor_change" or ",patch_change" + new_ver=$(echo "${result}" | awk -F',' '{print $1}') + diff_versioning=$(echo "${result}" | awk -F',' '{print $2}') + echo "next version is ${new_ver}, it ${diff_versioning}" + # + # set output + if [[ ${diff_versioning} == 'major_minor_change' ]];then + echo "minor_version=true" >> "$GITHUB_OUTPUT" + else + echo "minor_version=false" >> "$GITHUB_OUTPUT" + fi + # + # + if [[ -z ${new_ver} ]]; then + echo "::error::please indicate the right semantic version in core/version.h" + echo "new_ver=''" >> "$GITHUB_OUTPUT" + echo "new_tag=''" >> "$GITHUB_OUTPUT" + exit 1 + else + echo "new_ver=${new_ver}" >> "$GITHUB_OUTPUT" + echo "new_tag=WAMR-${new_ver}" >> "$GITHUB_OUTPUT" + fi + + - name: push tag + if: steps.preparation.outputs.new_tag != '' + run: | + git tag ${{ steps.preparation.outputs.new_tag }} + git push origin --force --tags diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/.github/workflows/release_process.yml b/lib/wasm-micro-runtime-WAMR-1.2.2/.github/workflows/release_process.yml new file mode 100644 index 00000000000..4188b4d40ad --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/.github/workflows/release_process.yml @@ -0,0 +1,215 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +name: the binary release processes + +on: + workflow_dispatch: + inputs: + require_confirmation: + description: "If the process requires a confirmation" + type: boolean + required: false + default: false + +# 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: + create_tag: + uses: ./.github/workflows/create_tag.yml + + create_release: + needs: [create_tag] + runs-on: ubuntu-latest + outputs: + upload_url: ${{ steps.create_release.outputs.upload_url }} + steps: + - uses: actions/checkout@v3 + + - name: prepare the release note + run: | + extract_result="$(python3 ./.github/scripts/extract_from_release_notes.py RELEASE_NOTES.md)" + echo "RELEASE_NOTE<> $GITHUB_ENV + echo "${extract_result}" >> $GITHUB_ENV + echo "EOF" >> $GITHUB_ENV + + - name: create a release + id: create_release + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: ${{ needs.create_tag.outputs.new_tag }} + release_name: ${{ needs.create_tag.outputs.new_tag }} + prerelease: ${{ inputs.require_confirmation || needs.create_tag.outputs.minor_version }} + draft: false + body: ${{ env.RELEASE_NOTE }} + + # + # LLVM_LIBRARIES + build_llvm_libraries_on_ubuntu_2004: + needs: [create_tag, create_release] + uses: ./.github/workflows/build_llvm_libraries.yml + with: + os: "ubuntu-20.04" + arch: "X86" + + build_llvm_libraries_on_ubuntu_2204: + needs: [create_tag, create_release] + uses: ./.github/workflows/build_llvm_libraries.yml + with: + os: "ubuntu-22.04" + arch: "X86" + + build_llvm_libraries_on_macos: + needs: [create_tag, create_release] + uses: ./.github/workflows/build_llvm_libraries.yml + with: + os: "macos-latest" + arch: "X86" + + # + # WAMRC + release_wamrc_on_ubuntu_2004: + needs: [create_tag, create_release, build_llvm_libraries_on_ubuntu_2004] + uses: ./.github/workflows/build_wamrc.yml + with: + llvm_cache_key: ${{ needs.build_llvm_libraries_on_ubuntu_2004.outputs.cache_key }} + release: true + runner: ubuntu-20.04 + upload_url: ${{ needs.create_release.outputs.upload_url }} + ver_num: ${{ needs.create_tag.outputs.new_ver}} + + release_wamrc_on_ubuntu_2204: + needs: [create_tag, create_release, build_llvm_libraries_on_ubuntu_2204 ] + uses: ./.github/workflows/build_wamrc.yml + with: + llvm_cache_key: ${{ needs.build_llvm_libraries_on_ubuntu_2204.outputs.cache_key }} + release: true + runner: ubuntu-22.04 + upload_url: ${{ needs.create_release.outputs.upload_url }} + ver_num: ${{ needs.create_tag.outputs.new_ver }} + + release_wamrc_on_ubuntu_macos: + needs: [create_tag, create_release, build_llvm_libraries_on_macos] + uses: ./.github/workflows/build_wamrc.yml + with: + llvm_cache_key: ${{ needs.build_llvm_libraries_on_macos.outputs.cache_key }} + release: true + runner: macos-latest + upload_url: ${{ needs.create_release.outputs.upload_url }} + ver_num: ${{ needs.create_tag.outputs.new_ver }} + + # + # IWASM + release_iwasm_on_ubuntu_2004: + needs: [create_tag, create_release, build_llvm_libraries_on_ubuntu_2004] + uses: ./.github/workflows/build_iwasm_release.yml + with: + cwd: product-mini/platforms/linux + llvm_cache_key: ${{ needs.build_llvm_libraries_on_ubuntu_2004.outputs.cache_key }} + runner: ubuntu-20.04 + upload_url: ${{ needs.create_release.outputs.upload_url }} + ver_num: ${{ needs.create_tag.outputs.new_ver}} + + release_iwasm_on_ubuntu_2204: + needs: [create_tag, create_release, build_llvm_libraries_on_ubuntu_2204] + uses: ./.github/workflows/build_iwasm_release.yml + with: + cwd: product-mini/platforms/linux + llvm_cache_key: ${{ needs.build_llvm_libraries_on_ubuntu_2204.outputs.cache_key }} + runner: ubuntu-22.04 + upload_url: ${{ needs.create_release.outputs.upload_url }} + ver_num: ${{ needs.create_tag.outputs.new_ver}} + + release_iwasm_on_macos: + needs: [create_tag, create_release, build_llvm_libraries_on_macos] + uses: ./.github/workflows/build_iwasm_release.yml + with: + cwd: product-mini/platforms/darwin + llvm_cache_key: ${{ needs.build_llvm_libraries_on_macos.outputs.cache_key }} + runner: macos-latest + upload_url: ${{ needs.create_release.outputs.upload_url }} + ver_num: ${{ needs.create_tag.outputs.new_ver}} + + # + # WAMR_SDK + release_wamr_sdk_on_ubuntu_2004: + needs: [create_tag, create_release] + uses: ./.github/workflows/build_wamr_sdk.yml + with: + config_file: wamr_config_ubuntu_release.cmake + runner: ubuntu-20.04 + upload_url: ${{ needs.create_release.outputs.upload_url }} + ver_num: ${{ needs.create_tag.outputs.new_ver}} + wasi_sdk_url: https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-19/wasi-sdk-19.0-linux.tar.gz + + release_wamr_sdk_on_ubuntu_2204: + needs: [create_tag, create_release] + uses: ./.github/workflows/build_wamr_sdk.yml + with: + config_file: wamr_config_ubuntu_release.cmake + runner: ubuntu-22.04 + upload_url: ${{ needs.create_release.outputs.upload_url }} + ver_num: ${{ needs.create_tag.outputs.new_ver}} + wasi_sdk_url: https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-19/wasi-sdk-19.0-linux.tar.gz + + release_wamr_sdk_on_macos: + needs: [create_tag, create_release] + uses: ./.github/workflows/build_wamr_sdk.yml + with: + config_file: wamr_config_macos_release.cmake + runner: macos-latest + upload_url: ${{ needs.create_release.outputs.upload_url }} + ver_num: ${{ needs.create_tag.outputs.new_ver}} + wasi_sdk_url: https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-19/wasi-sdk-19.0-macos.tar.gz + + # + # vscode extension cross-platform + release_wamr_ide_vscode_ext: + needs: [create_tag, create_release] + uses: ./.github/workflows/build_wamr_vscode_ext.yml + secrets: inherit + with: + upload_url: ${{ needs.create_release.outputs.upload_url }} + ver_num: ${{ needs.create_tag.outputs.new_ver }} + + # + # vscode extension docker images package + release_wamr_ide_docker_images_package: + needs: [create_tag, create_release] + uses: ./.github/workflows/build_docker_images.yml + with: + upload_url: ${{ needs.create_release.outputs.upload_url }} + ver_num: ${{ needs.create_tag.outputs.new_ver }} + + # + # WAMR_LLDB + release_wamr_lldb_on_ubuntu_2004: + needs: [create_tag, create_release] + uses: ./.github/workflows/build_wamr_lldb.yml + with: + runner: ubuntu-20.04 + upload_url: ${{ needs.create_release.outputs.upload_url }} + ver_num: ${{ needs.create_tag.outputs.new_ver}} + + release_wamr_lldb_on_ubuntu_2204: + needs: [create_tag, create_release] + uses: ./.github/workflows/build_wamr_lldb.yml + with: + runner: ubuntu-22.04 + upload_url: ${{ needs.create_release.outputs.upload_url }} + ver_num: ${{ needs.create_tag.outputs.new_ver}} + + release_wamr_lldb_on_macos_universal: + needs: [create_tag, create_release] + uses: ./.github/workflows/build_wamr_lldb.yml + with: + runner: macos-latest + arch: universal + upload_url: ${{ needs.create_release.outputs.upload_url }} + ver_num: ${{ needs.create_tag.outputs.new_ver}} diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/.github/workflows/reuse_latest_release_binaries.yml b/lib/wasm-micro-runtime-WAMR-1.2.2/.github/workflows/reuse_latest_release_binaries.yml new file mode 100644 index 00000000000..7f82672a69a --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/.github/workflows/reuse_latest_release_binaries.yml @@ -0,0 +1,68 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +name: reuse binaries of the latest release if no more modification on the_path since last_commit + +on: + workflow_call: + inputs: + binary_name_stem: + type: string + required: true + last_commit: + type: string + required: true + the_path: + type: string + required: true + upload_url: + description: upload binary assets to the URL of release + type: string + required: true + outputs: + result: + value: ${{ jobs.build.outputs.result }} + +jobs: + reuse: + runs-on: ubuntu-latest + outputs: + result: ${{ steps.try_reuse.outputs.result }} + steps: + - uses: actions/checkout@v3 + # Full git history is needed to get a proper list of commits and tags + with: + fetch-depth: 0 + + - name: try to reuse binaries + id: try_reuse + run: | + echo '::echo::on' + python3 ./.github/scripts/reuse_latest_release_binaries.py \ + --binary_name_stem ${{ inputs.binary_name_stem }} \ + --last_commit ${{ inputs.last_commit }} \ + --the_path ${{ inputs.the_path }} . + ls -lh . + + - run: echo ${{ steps.try_reuse.outputs.result }} + + - name: upload release tar.gz + if: steps.try_reuse.outputs.result == 'hit' + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ inputs.upload_url }} + asset_path: ${{ inputs.binary_name_stem }}.tar.gz + asset_name: ${{ inputs.binary_name_stem }}.tar.gz + asset_content_type: application/x-gzip + + - name: upload release zip + if: steps.try_reuse.outputs.result == 'hit' + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ inputs.upload_url }} + asset_path: ${{ inputs.binary_name_stem }}.zip + asset_name: ${{ inputs.binary_name_stem }}.zip + asset_content_type: application/zip diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/.github/workflows/spec_test_on_nuttx.yml b/lib/wasm-micro-runtime-WAMR-1.2.2/.github/workflows/spec_test_on_nuttx.yml new file mode 100644 index 00000000000..7b8403777fa --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/.github/workflows/spec_test_on_nuttx.yml @@ -0,0 +1,145 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +name: spec test on nuttx + +on: + schedule: + - cron: '0 0 * * *' + + workflow_dispatch: + +env: + LLVM_CACHE_SUFFIX: "build-llvm_libraries_ex" + WASI_SDK_PATH: "/opt/wasi-sdk" + +jobs: + build_llvm_libraries: + uses: ./.github/workflows/build_llvm_libraries.yml + with: + os: "ubuntu-22.04" + arch: "ARM RISCV AArch64" + + spec_test_on_qemu: + runs-on: ${{ matrix.os }} + needs: [build_llvm_libraries] + strategy: + matrix: + os: [ubuntu-22.04] + nuttx_board_config: [ + # cortex-a9 + "boards/arm/imx6/sabre-6quad/configs/nsh", + # riscv32imac + "boards/risc-v/qemu-rv/rv-virt/configs/nsh", + # riscv64imac + # "boards/risc-v/qemu-rv/rv-virt/configs/nsh64", + ] + wamr_test_option: [ + # "-t fast-interp", + "-t aot", + "-t aot -X" + ] + llvm_cache_key: [ "${{ needs.build_llvm_libraries.outputs.cache_key }}" ] + steps: + - name: Install Utilities + run: | + sudo apt install -y kconfig-frontends-nox genromfs + + - name: Install ARM Compilers + if: contains(matrix.nuttx_board_config, 'arm') + run: sudo apt install -y gcc-arm-none-eabi + + - name: Install RISC-V Compilers + if: contains(matrix.nuttx_board_config, 'risc-v') + run: | + curl -L https://static.dev.sifive.com/dev-tools/freedom-tools/v2020.12/riscv64-unknown-elf-toolchain-10.2.0-2020.12.8-x86_64-linux-ubuntu14.tar.gz > riscv.tar.gz + tar xvf riscv.tar.gz + echo "$PWD/riscv64-unknown-elf-toolchain-10.2.0-2020.12.8-x86_64-linux-ubuntu14/bin" >> $GITHUB_PATH + + - name: Install WASI-SDK + run: | + curl -L https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-19/wasi-sdk-19.0-linux.tar.gz > wasi-sdk.tar.gz + tar xvf wasi-sdk.tar.gz + sudo mv wasi-sdk-* /opt/wasi-sdk + + - name: Checkout NuttX + uses: actions/checkout@v3 + with: + repository: apache/incubator-nuttx + path: nuttx + + - name: Checkout NuttX Apps + uses: actions/checkout@v3 + with: + repository: apache/incubator-nuttx-apps + path: apps + + - name: Checkout WAMR + uses: actions/checkout@v3 + with: + repository: ${{ github.repository }} + path: apps/interpreters/wamr/wamr + + - name: Get LLVM libraries + id: retrieve_llvm_libs + uses: actions/cache@v3 + with: + path: | + ./core/deps/llvm/build/bin + ./core/deps/llvm/build/include + ./core/deps/llvm/build/lib + ./core/deps/llvm/build/libexec + ./core/deps/llvm/build/share + key: ${{ matrix.llvm_cache_key }} + + - name: Quit if cache miss + if: steps.retrieve_llvm_libs.outputs.cache-hit != 'true' + run: echo "::error::can not get prebuilt llvm libraries" && exit 1 + + - name: Copy LLVM + run: cp -r core/deps/llvm apps/interpreters/wamr/wamr/core/deps/llvm + + - name: Enable WAMR for NuttX + run: | + find nuttx/boards -name defconfig | xargs sed -i '$a\CONFIG_INTERPRETERS_WAMR=y\nCONFIG_INTERPRETERS_WAMR_STACKSIZE=32768\nCONFIG_INTERPRETERS_WAMR_AOT=y\nCONFIG_INTERPRETERS_WAMR_FAST=y\nCONFIG_INTERPRETERS_WAMR_LOG=y\nCONFIG_INTERPRETERS_WAMR_LIBC_BUILTIN=y\nCONFIG_INTERPRETERS_WAMR_REF_TYPES=y\nCONFIG_INTERPRETERS_WAMR_ENABLE_SPEC_TEST=y\nCONFIG_INTERPRETERS_WAMR_SHARED_MEMORY=y\nCONFIG_INTERPRETERS_WAMR_BULK_MEMORY=y\n' + find nuttx/boards -name defconfig | xargs sed -i '$a\CONFIG_EOL_IS_LF=y\nCONFIG_ARM_SEMIHOSTING_HOSTFS=y\nCONFIG_ARM_SEMIHOSTING_HOSTFS_CACHE_COHERENCE=y\nCONFIG_RISCV_SEMIHOSTING_HOSTFS=y\nCONFIG_FS_HOSTFS=y\nCONFIG_LIBC_FLOATINGPOINT=y\n' + + - name: Build wamrc + working-directory: apps/interpreters/wamr/wamr/wamr-compiler + run: | + cmake -Bbuild . + cmake --build build + + - name: Build + run: | + cd nuttx + tools/configure.sh ${{ matrix.nuttx_board_config }} + make -j$(nproc) + echo "firmware=$PWD/nuttx" >> $GITHUB_ENV + + - name: Test on ARM + if: endsWith(matrix.nuttx_board_config, 'sabre-6quad/configs/nsh') + run: | + curl -L https://github.com/xpack-dev-tools/qemu-arm-xpack/releases/download/v7.1.0-1/xpack-qemu-arm-7.1.0-1-linux-x64.tar.gz > xpack-qemu-arm.tar.gz + tar xvf xpack-qemu-arm.tar.gz + export PATH=$PATH:$PWD/xpack-qemu-arm-7.1.0-1/bin + cd apps/interpreters/wamr/wamr/tests/wamr-test-suites + ./test_wamr.sh -s spec ${{ matrix.wamr_test_option }} -m thumbv7_vfp -b -Q -P -F ${{ env.firmware }} + + - name: Test on RISCV32 + if: endsWith(matrix.nuttx_board_config, 'rv-virt/configs/nsh') + run: | + curl -L https://github.com/xpack-dev-tools/qemu-riscv-xpack/releases/download/v7.1.0-1/xpack-qemu-riscv-7.1.0-1-linux-x64.tar.gz > xpack-qemu-riscv.tar.gz + tar xvf xpack-qemu-riscv.tar.gz + export PATH=$PATH:$PWD/xpack-qemu-riscv-7.1.0-1/bin + cd apps/interpreters/wamr/wamr/tests/wamr-test-suites + ./test_wamr.sh -s spec ${{ matrix.wamr_test_option }} -m RISCV32 -b -Q -P -F ${{ env.firmware }} + + - name: Test on RISCV64 + if: endsWith(matrix.nuttx_board_config, 'rv-virt/configs/nsh64') + run: | + curl -L https://github.com/xpack-dev-tools/qemu-riscv-xpack/releases/download/v7.1.0-1/xpack-qemu-riscv-7.1.0-1-linux-x64.tar.gz > xpack-qemu-riscv.tar.gz + tar xvf xpack-qemu-riscv.tar.gz + export PATH=$PATH:$PWD/xpack-qemu-riscv-7.1.0-1/bin + cd apps/interpreters/wamr/wamr/tests/wamr-test-suites + ./test_wamr.sh -s spec ${{ matrix.wamr_test_option }} -m riscv64 -b -Q -P -F ${{ env.firmware }} diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/.gitignore b/lib/wasm-micro-runtime-WAMR-1.2.2/.gitignore similarity index 68% rename from lib/wasm-micro-runtime-WAMR-1.1.1/.gitignore rename to lib/wasm-micro-runtime-WAMR-1.2.2/.gitignore index 8b9e2b7db51..a4889fb7f5f 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/.gitignore +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/.gitignore @@ -8,10 +8,13 @@ *.obj *.a *.so +.DS_Store core/deps/** core/shared/mem-alloc/tlsf core/app-framework/wgl +core/iwasm/libraries/lib-wasi-threads/test/*.wasm +core/iwasm/libraries/lib-socket/test/*.wasm wamr-sdk/out/ wamr-sdk/runtime/build_runtime_sdk/ @@ -28,4 +31,11 @@ tests/wamr-test-suites/workspace samples/socket-api/wasm-src/inc/pthread.h -**/__pycache__ \ No newline at end of file +**/__pycache__ + +tests/benchmarks/coremark/coremark* + +samples/workload/include/** +!samples/workload/include/.gitkeep + +# core/iwasm/libraries/wasi-threads \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/ATTRIBUTIONS.md b/lib/wasm-micro-runtime-WAMR-1.2.2/ATTRIBUTIONS.md similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/ATTRIBUTIONS.md rename to lib/wasm-micro-runtime-WAMR-1.2.2/ATTRIBUTIONS.md diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/CMakeLists.txt b/lib/wasm-micro-runtime-WAMR-1.2.2/CMakeLists.txt similarity index 80% rename from lib/wasm-micro-runtime-WAMR-1.1.1/CMakeLists.txt rename to lib/wasm-micro-runtime-WAMR-1.2.2/CMakeLists.txt index aedc15b9074..1c87994945a 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/CMakeLists.txt +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/CMakeLists.txt @@ -1,13 +1,15 @@ # Copyright (C) 2019 Intel Corporation. All rights reserved. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -cmake_minimum_required (VERSION 2.9) +cmake_minimum_required (VERSION 3.0) project (iwasm) set (CMAKE_VERBOSE_MAKEFILE OFF) -string (TOLOWER ${CMAKE_HOST_SYSTEM_NAME} WAMR_BUILD_PLATFORM) +if (NOT DEFINED WAMR_BUILD_PLATFORM) + string (TOLOWER ${CMAKE_HOST_SYSTEM_NAME} WAMR_BUILD_PLATFORM) +endif () # Reset default linker flags set (CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") @@ -83,6 +85,11 @@ if (NOT DEFINED WAMR_BUILD_LIB_PTHREAD) set (WAMR_BUILD_LIB_PTHREAD 0) endif () +if (NOT DEFINED WAMR_BUILD_LIB_WASI_THREADS) + # Disable wasi threads library by default + set (WAMR_BUILD_LIB_WASI_THREADS 0) +endif () + if (NOT DEFINED WAMR_BUILD_MINI_LOADER) # Disable wasm mini loader by default set (WAMR_BUILD_MINI_LOADER 0) @@ -98,18 +105,11 @@ if (NOT DEFINED WAMR_BUILD_REF_TYPES) set (WAMR_BUILD_REF_TYPES 0) endif () -if (COLLECT_CODE_COVERAGE EQUAL 1) - set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage") - set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage") -endif () - set (WAMR_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}) include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake) -set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections -pie -fPIE") - -set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wformat -Wformat-security -Wshadow") +set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wformat -Wformat-security -Wshadow -Wno-unused-parameter") # set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wconversion -Wsign-conversion") set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wformat -Wformat-security -Wno-unused") @@ -133,16 +133,25 @@ include (${SHARED_DIR}/utils/uncommon/shared_uncommon.cmake) # STATIC LIBRARY add_library(iwasm_static STATIC ${WAMR_RUNTIME_LIB_SOURCE}) set_target_properties (iwasm_static PROPERTIES OUTPUT_NAME vmlib) +target_include_directories(iwasm_static INTERFACE ${WAMR_ROOT_DIR}/core/iwasm/include) +target_link_libraries (iwasm_static INTERFACE ${LLVM_AVAILABLE_LIBS} ${UV_A_LIBS} -lm -ldl -lpthread) +if (WAMR_BUILD_WASM_CACHE EQUAL 1) + target_link_libraries(iwasm_static INTERFACE boringssl_crypto) +endif () install (TARGETS iwasm_static ARCHIVE DESTINATION lib) # SHARED LIBRARY add_library (iwasm_shared SHARED ${WAMR_RUNTIME_LIB_SOURCE}) set_target_properties (iwasm_shared PROPERTIES OUTPUT_NAME iwasm) -target_link_libraries (iwasm_shared ${LLVM_AVAILABLE_LIBS} ${UV_A_LIBS} -lm -ldl -lpthread) +target_include_directories(iwasm_shared INTERFACE ${WAMR_ROOT_DIR}/core/iwasm/include) +target_link_libraries (iwasm_shared INTERFACE ${LLVM_AVAILABLE_LIBS} ${UV_A_LIBS} -lm -ldl -lpthread) +if (WAMR_BUILD_WASM_CACHE EQUAL 1) + target_link_libraries(iwasm_shared INTERFACE boringssl_crypto) +endif () if (MINGW) -target_link_libraries (iwasm_shared -lWs2_32) + target_link_libraries (iwasm_shared -lWs2_32) endif () install (TARGETS iwasm_shared LIBRARY DESTINATION lib) @@ -151,4 +160,5 @@ install (TARGETS iwasm_shared LIBRARY DESTINATION lib) install (FILES ${WAMR_ROOT_DIR}/core/iwasm/include/wasm_c_api.h ${WAMR_ROOT_DIR}/core/iwasm/include/wasm_export.h + ${WAMR_ROOT_DIR}/core/iwasm/include/lib_export.h DESTINATION include) diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/CODE_OF_CONDUCT.md b/lib/wasm-micro-runtime-WAMR-1.2.2/CODE_OF_CONDUCT.md similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/CODE_OF_CONDUCT.md rename to lib/wasm-micro-runtime-WAMR-1.2.2/CODE_OF_CONDUCT.md diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/CONTRIBUTING.md b/lib/wasm-micro-runtime-WAMR-1.2.2/CONTRIBUTING.md similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/CONTRIBUTING.md rename to lib/wasm-micro-runtime-WAMR-1.2.2/CONTRIBUTING.md diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/LICENSE b/lib/wasm-micro-runtime-WAMR-1.2.2/LICENSE similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/LICENSE rename to lib/wasm-micro-runtime-WAMR-1.2.2/LICENSE diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/ORG_CODE_OF_CONDUCT.md b/lib/wasm-micro-runtime-WAMR-1.2.2/ORG_CODE_OF_CONDUCT.md similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/ORG_CODE_OF_CONDUCT.md rename to lib/wasm-micro-runtime-WAMR-1.2.2/ORG_CODE_OF_CONDUCT.md diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/README.md b/lib/wasm-micro-runtime-WAMR-1.2.2/README.md new file mode 100644 index 00000000000..8cbdcf49592 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/README.md @@ -0,0 +1,113 @@ +# WebAssembly Micro Runtime + + +**A [Bytecode Alliance][BA] project** + +[BA]: https://bytecodealliance.org/ + +**[Guide](https://wamr.gitbook.io/)**  **[Website](https://bytecodealliance.github.io/wamr.dev)**  **[Chat](https://bytecodealliance.zulipchat.com/#narrow/stream/290350-wamr)** + +[Build WAMR](./doc/build_wamr.md) | [Build AOT Compiler](./wamr-compiler/README.md) | [Embed WAMR](./doc/embed_wamr.md) | [Export Native API](./doc/export_native_api.md) | [Build Wasm Apps](./doc/build_wasm_app.md) | [Samples](./samples/README.md) + +WebAssembly Micro Runtime (WAMR) is a lightweight standalone WebAssembly (Wasm) runtime with small footprint, high performance and highly configurable features for applications cross from embedded, IoT, edge to Trusted Execution Environment (TEE), smart contract, cloud native and so on. It includes a few parts as below: +- [**VMcore**](./core/iwasm/): A set of runtime libraries for loading and running Wasm modules. It supports several execution modes including interpreter, Ahead-of-Time compilation(AoT) and Just-in-Time compilation (JIT). The WAMR supports two JIT tiers - Fast JIT, LLVM JIT, and dynamic tier-up from Fast JIT to LLVM JIT. +- [**iwasm**](./product-mini/): The executable binary built with WAMR VMcore supports WASI and command line interface. +- [**wamrc**](./wamr-compiler/): The AOT compiler to compile Wasm file into AOT file +- Useful components and tools for building real solutions with WAMR vmcore: + - [App-framework](./core/app-framework/README.md): A framework for supporting APIs for the Wasm applications + - [App-manager](./core/app-mgr/README.md): a framework for dynamical loading the Wasm module remotely + - [WAMR-IDE](./test-tools/wamr-ide): An experimental VSCode extension for developping WebAssembly applications with C/C++ + + +### Key features +- Full compliant to the W3C Wasm MVP +- Small runtime binary size (~85K for interpreter and ~50K for AOT) and low memory usage +- Near to native speed by AOT and JIT +- Self-implemented AOT module loader to enable AOT working on Linux, Windows, MacOS, Android, SGX and MCU systems +- Choices of Wasm application libc support: the built-in libc subset for the embedded environment or [WASI](https://github.com/WebAssembly/WASI) for the standard libc +- [The simple C APIs to embed WAMR into host environment](./doc/embed_wamr.md), see [how to integrate WAMR](./doc/embed_wamr.md) and the [API list](./core/iwasm/include/wasm_export.h) +- [The mechanism to export native APIs to Wasm applications](./doc/export_native_api.md), see [how to register native APIs](./doc/export_native_api.md) +- [Multiple modules as dependencies](./doc/multi_module.md), ref to [document](./doc/multi_module.md) and [sample](samples/multi-module) +- [Multi-thread, pthread APIs and thread management](./doc/pthread_library.md), ref to [document](./doc/pthread_library.md) and [sample](samples/multi-thread) +- [wasi-threads](./doc/pthread_impls.md#wasi-threads-new), ref to [document](./doc/pthread_impls.md#wasi-threads-new) and [sample](samples/wasi-threads) +- [Linux SGX (Intel Software Guard Extension) support](./doc/linux_sgx.md), ref to [document](./doc/linux_sgx.md) +- [Source debugging support](./doc/source_debugging.md), ref to [document](./doc/source_debugging.md) +- [XIP (Execution In Place) support](./doc/xip.md), ref to [document](./doc/xip.md) +- [Berkeley/Posix Socket support](./doc/socket_api.md), ref to [document](./doc/socket_api.md) and [sample](./samples/socket-api) +- [Multi-tier JIT](./product-mini#linux) and [Running mode control](https://bytecodealliance.github.io/wamr.dev/blog/introduction-to-wamr-running-modes/) +- Language bindings: [Go](./language-bindings/go/README.md), [Python](./language-bindings/python/README.md) + +### Wasm post-MVP features +- [wasm-c-api](https://github.com/WebAssembly/wasm-c-api), ref to [document](doc/wasm_c_api.md) and [sample](samples/wasm-c-api) +- [128-bit SIMD](https://github.com/WebAssembly/simd), ref to [samples/workload](samples/workload) +- [Reference Types](https://github.com/WebAssembly/reference-types), ref to [document](doc/ref_types.md) and [sample](samples/ref-types) +- [Non-trapping float-to-int conversions](https://github.com/WebAssembly/nontrapping-float-to-int-conversions) +- [Sign-extension operators](https://github.com/WebAssembly/sign-extension-ops), [Bulk memory operations](https://github.com/WebAssembly/bulk-memory-operations) +- [Multi-value](https://github.com/WebAssembly/multi-value), [Tail-call](https://github.com/WebAssembly/tail-call), [Shared memory](https://github.com/WebAssembly/threads/blob/main/proposals/threads/Overview.md#shared-linear-memory) + +### Supported architectures and platforms +The WAMR VMcore supports the following architectures: +- X86-64, X86-32 +- ARM, THUMB (ARMV7 Cortex-M7 and Cortex-A15 are tested) +- AArch64 (Cortex-A57 and Cortex-A53 are tested) +- RISCV64, RISCV32 (RISC-V LP64 and RISC-V LP64D are tested) +- XTENSA, MIPS, ARC + +The following platforms are supported, click each link below for how to build iwasm on that platform. Refer to [WAMR porting guide](./doc/port_wamr.md) for how to port WAMR to a new platform. +- [Linux](./product-mini/README.md#linux), [Linux SGX (Intel Software Guard Extension)](./doc/linux_sgx.md), [MacOS](./product-mini/README.md#macos), [Android](./product-mini/README.md#android), [Windows](./product-mini/README.md#windows), [Windows (MinGW)](./product-mini/README.md#mingw) +- [Zephyr](./product-mini/README.md#zephyr), [AliOS-Things](./product-mini/README.md#alios-things), [VxWorks](./product-mini/README.md#vxworks), [NuttX](./product-mini/README.md#nuttx), [RT-Thread](./product-mini/README.md#RT-Thread), [ESP-IDF](./product-mini/README.md#esp-idf) + + +## Getting started +- [Build VM core](./doc/build_wamr.md) and [Build wamrc AOT compiler](./wamr-compiler/README.md) +- [Build iwasm (mini product)](./product-mini/README.md): [Linux](./product-mini/README.md#linux), [SGX](./doc/linux_sgx.md), [MacOS](./product-mini/README.md#macos) and [Windows](./product-mini/README.md#windows) +- [Embed into C/C++](./doc/embed_wamr.md), [Embed into Python](./language-bindings/python), [Embed into Go](./language-bindings/go) +- [Register native APIs for Wasm applications](./doc/export_native_api.md) +- [Build wamrc AOT compiler](./wamr-compiler/README.md) +- [Build Wasm applications](./doc/build_wasm_app.md) +- [Port WAMR to a new platform](./doc/port_wamr.md) +- [VS Code development container](./doc/devcontainer.md) +- [Samples](./samples) and [Benchmarks](./tests/benchmarks) + + + +### Performance and memory +- [Blog: The WAMR memory model](https://bytecodealliance.github.io/wamr.dev/blog/the-wamr-memory-model/) +- [Blog: Understand WAMR heaps](https://bytecodealliance.github.io/wamr.dev/blog/understand-the-wamr-heaps/) and [stacks](https://bytecodealliance.github.io/wamr.dev/blog/understand-the-wamr-stacks/) +- [Blog: Introduction to WAMR running modes](https://bytecodealliance.github.io/wamr.dev/blog/introduction-to-wamr-running-modes/) +- [Memory usage tunning](./doc/memory_tune.md): the memory model and how to tune the memory usage +- [Memory usage profiling](./doc/build_wamr.md#enable-memory-profiling-experiment): how to profile the memory usage +- [Benchmarks](./tests/benchmarks): checkout these links for how to run the benchmarks: [PolyBench](./tests/benchmarks/polybench), [CoreMark](./tests/benchmarks/coremark), [Sightglass](./tests/benchmarks/sightglass), [JetStream2](./tests/benchmarks/jetstream) +- [Performance and footprint data](https://github.com/bytecodealliance/wasm-micro-runtime/wiki/Performance): the performance and footprint data + + + +Project Technical Steering Committee +==================================== +The [WAMR PTSC Charter](./TSC_Charter.md) governs the operations of the project TSC. +The current TSC members: +- [dongsheng28849455](https://github.com/dongsheng28849455) - **Dongsheng Yan**, +- [loganek](https://github.com/loganek) - **Marcin Kolny**, +- [lum1n0us](https://github.com/lum1n0us) - **Liang He**, +- [no1wudi](https://github.com/no1wudi) **Qi Huang**, +- [qinxk-inter](https://github.com/qinxk-inter) - **Xiaokang Qin**, +- [wei-tang](https://github.com/wei-tang) - **Wei Tang**, +- [wenyongh](https://github.com/wenyongh) - **Wenyong Huang**, +- [xujuntwt95329](https://github.com/xujuntwt95329) - **Jun Xu**, +- [xwang98](https://github.com/xwang98) - **Xin Wang**, (chair) +- [yamt](https://github.com/yamt) - **Takashi Yamamoto**, + + +License +======= +WAMR uses the same license as LLVM: the `Apache 2.0 license` with the LLVM +exception. See the LICENSE file for details. This license allows you to freely +use, modify, distribute and sell your own products based on WAMR. +Any contributions you make will be under the same license. + +# More resources +- [Who use WAMR?](https://github.com/bytecodealliance/wasm-micro-runtime/wiki) +- [WAMR Blogs](https://bytecodealliance.github.io/wamr.dev/blog/) +- [Community news and events](https://bytecodealliance.github.io/wamr.dev/events/) +- [WAMR TSC meetings](https://github.com/bytecodealliance/wasm-micro-runtime/wiki/TSC-meeting-notes) + diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/RELEASE_NOTES.md b/lib/wasm-micro-runtime-WAMR-1.2.2/RELEASE_NOTES.md new file mode 100644 index 00000000000..d6308ce671e --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/RELEASE_NOTES.md @@ -0,0 +1,402 @@ +## WAMR-1.2.2 + +### Breaking Changes + +### New Features +- Implement Fast JIT multi-threading feature (#2134) + +### Bug Fixes +- Update request.ts wasm_response_send signature (#2122) +- Fix ems allocator unaligned memory access on riscv64 (#2140) +- libc_wasi_wrapper.c: Fix min func issue for size_t < 8 bytes on some platforms (#2152) +- Fix three multi-threading and wasm-c-api-imports issues (#2173) +- Fix build polybench benchmark error with wasi-sdk-19.0 (#2187) +- Fix wamr-ide debugger ignoring launch config (#2155) + +### Enhancements +- Add test for validating linear memory size updates (#2078) +- Update Zephyr docs to remove unsupported west subcommand (#2128) +- Update messages/comments to refer the new place of the version definition (#2133) +- build_wamr_lldb.yml: sync lldb build options between ubuntu and macos (#2132) +- build_wamr_vscode_ext.yml: vsce publish only on the official repo (#2130) +- VSCode-Extension: Download lldb built for ubuntu 20.04 (#2139) +- Avoid re-installing if Tensorflow is already installed for WASI-NN (#2148) +- wamrc: Add --stack-usage option (#2158) +- Fix URL in language-bindings/python/README.md (#2166) +- Fix URL in embed_wamr.md (#2165) +- Fix URL in README.md (#2168) +- Return error when exception was raised after main thread finishes (#2169) +- wasi-nn: Add external delegation to support several NPU/GPU (#2162) +- Update document for iwasm/wamrc dependent packages (#2183) +- Use a manual flag to disable clock_nanosleep on the unsupported platforms (#2176) +- Fix compile warnings on windows platform (#2208) + +### Others +- CI: Add ubsan checks to samples/wasm-c-api (#2147) +- CI: More precise trigger paths for github actions (#2157) + +--- + +## WAMR-1.2.1 + +### Breaking Changes + +### New Features + +### Bug Fixes +- libc-wasi/posix.c: Fix POLL{RD,WR}NORM in uClibc (#2069) +- Fix bh_assert for 64-bit platforms (#2071) +- wamr-ide: Modify Dockerfile to update base image version and fix build issue (#2068) +- Fix module_malloc/module_free issues (#2072) +- Fix use after free when dumping call stack (#2084) +- Fix compilation errors of workload xnnpack and meshoptimizer (#2081) +- Fix typo in Fast JIT's BUILD_COND_BR Macro (#2092) +- Fix sanitizer pointer overflow warning when perform pointer arithmetic (#2098) +- Update sample workload tensorflow (#2101) +- Fix ref.func forward-declared function check (#2099) +- Fix interpreter read linear memory size for multi-threading (#2088) + +### Enhancements +- Limit the minimal size of bh_hashmap (#2073) +- Bump tensorflow to 2.11.1 in /core/iwasm/libraries/wasi-nn/test (#2061) +- Bump tensorflow to 2.11.1 in install_tensorflow.sh (#2076) +- Add support for universal binaries on OSX (#2060) +- Update documents (#2100) + +### Others +- spectest/nuttx: Increase stack size of iwasm task (#2082) +- ci: Refactor windows build definition (#2087) +- ci: Enable WASI threads in CI (#2086) +- Use wasi-sdk-20 to build wasi-threads cases in CI (#2095) + +--- + +## WAMR-1.2.0 + +### Breaking Changes + + +### New Features +- Implement two-level Multi-tier JIT engine: tier-up from Fast JIT to LLVM JIT to get quick cold startup and better performance +- Enable running mode control for runtime, wasm module instance and iwasm +- Implement wasi-threads feature +- Upgrade toolkits: upgrade to llvm-15.0, wasi-sdk-19.0, emsdk-3.1.28 and so on +- Port WAMR to the FreeBSD platform +- Refactor wasi-nn to simplify the support for multiple frameworks +- wasi-nn: Enable GPU support +- wasi-nn: Support multiple TFLite models +- Add WAMR API bindings in Python +- Add libsodium benchmark + +### Bug Fixes +- Fix wasm-c-api import func link issue in wasm_instance_new +- Fix watchpoint segfault when using debug interp without server +- libc-wasi: Fix spurious poll timeout +- Fix typo verify_module in aot_compiler.c +- Fix failure about preopen of reactor modules +- Fix equal check in AOT XIP float cmp intrinsic +- Fix issue of resolving func name in custom name section +- Fix go language binding build on macos arm64 +- Prevent undefined behavior from c_api_func_imports == NULL +- Fix potential block issue in source debugger +- SGX IPFS: Fix a segfault and support seeking beyond the end of files while using SEEK_CUR/SEEK_END +- Fix undef error about WAMR_BUILD_MEMORY_PROFILING +- Fix jit memory overwritten after instance deinstantiate +- Fix stack alignment issue on ia32 +- Fix explicit casts and types in espidf_socket.c +- Fix potential integer overflow issue in wasm-c-api +- Fix libc-wasi build failure when using clang +- Fix wamrapi python binding for darwin +- Fix getting port issue in posix os_socket_bind +- Fix key error in build_llvm.py +- nuttx: Add missing pthread.h header +- Fix os_socket_addr_resolve() for IPv6 +- Enhance/Fix sample socket-api and workload +- Fix fast-jit build error +- Fix dead lock in source debugger +- fix debugger: Set termination flags also when in debug mode + +### Enhancements +- Add WAMR-IDE vscode extension to the Visual Studio Marketplace +- Refine Windows thread waiting list operations +- Improve wasm-c-api instantiation-time linking +- Enable platform support for esp-idf v5.0.1 +- Readme refactoring +- Add architecture diagram for wasm function +- Add architecture document for wasm export +- Add architecture diagram for wasm globals and classic-interp stack frame +- Use boringssl instead of openssl to implement wasm cache loading +- Implement i32.rem_s and i32.rem_u intrinsic +- Perfect the codebase for wamr-ide +- Remove unnecessary ret value control when spec test is enabled +- Use float version library routine for XIP aot_intrinsic_xxx APIs +- Register missing symbols for f32 to 64 bit integer conversion +- Report error in instantiation when meeting unlinked import globals +- Add more types and APIs for attr_container +- Simplify fcmp intrinsic logic for AOT/XIP +- Add some missing macros for int literals in wamr-sdk libc-builtin-sysroot stdint.h +- nuttx: Mock socket APIs if NET is disabled +- Main thread spread exception when thread-mgr is enabled +- Implement opcode atomic.wait and atomic.notify for Fast JIT +- Add docker images auto check and setup support for WAMR-IDE +- Make memory profiling show native stack usage +- Enable gcc-4.8 compilation +- Enable specifying out-of-source platform configuration cmake file +- Add gh api call for fetching llvm version (#1942) Fixes +- Don't terminate other threads when create thread failed +- Modify poll_oneoff in libc-wasi to make it interruptible +- Expose wasm_runtime_call_indirect +- Make a workaround for EGO when fstat returns NOT_SUPPORT +- Re-org calling post instantiation functions +- Enable custom llvm build flags +- support SSH for git clone llvm +- Support dump call stack on exception and dump call stack on nuttx +- Update document for source debugging +- Document some info about estimating memory usage +- Document the summary of two pthread implementations +- Refine aot compiler check suspend_flags and fix issue of multi-tier jit + +### Others +- Enable XIP in CI daily test +- Integrate wasi test suite to wamr-test-suites and CI +- Add CI for wasi-threads tests +- Update CIs and documents to make naming of generated binaries consist +- Enable CI wasi test suite for x86-32 classic/fast interpreter +- CI: Enable libc-wasi compilation test on NuttX +- CI: Enable Multi-tier JIT by default for released iwasm binary +- Enable CI build for gcc 4.8 on linux + +--- + +## WAMR-1.1.2 + +### Breaking Changes +- Remove the LLVM MCJIT mode, replace it with LLVM ORC JIT eager mode +- Add option to pass user data to the allocator functions of RuntimeInitArgs +- Change how iwasm returns: + - return 1 if an exception was thrown, else + - return the wasi exit code if the wasm app is a wasi app, else + - keep the same behavior as before +- Enable bulk memory by default + +### New Features +- Add control for the native stack check with hardware trap +- Add memory watchpoint support to debugger +- Add wasm_module_obtain() to clone wasm_module_t +- Implement Fast JIT dump call stack and perf profiling +- esp-idf: Add socket support for esp-idf platform + +### Bug Fixes +- Fix XIP issue caused by rem_s on RISC-V +- Fix XIP issues of fp to int cast and int rem/div +- Fix missing float cmp for XIP +- Correct the arch name for armv7a on NuttX +- Fix issue of restoring wasm operand stack +- Fix issue of thumb relocation R_ARM_THM_MOVT_ABS +- Fix fast jit issue of translating opcode i32.rem_s/i64.rem_s +- Fix interp/fast-jit float min/max issues +- Fix missing intrinsics for risc-v which were reported by spec test +- wasm-c-api: Fix init/destroy thread env multiple times issue +- Fix wasm-c-api import func link issue in wasm_instance_new +- Fix sample ref-types/wasm-c-api build error with wat2wasm low version +- Fix zephyr sample build errors +- Fix source debugger error handling: continue executing when detached +- Fix scenario where the timeout for atomic wait is set to negative number +- Fix link cxx object file error when building wamrc for docker image +- Fix XIP issue of handling 64-bit const in 32-bit target + +### Enhancements +- Refactor the layout of interpreter and AOT module instance +- Refactor LLVM JIT: remove mcjit and legacy pass manager, upgrade to ORCv2 JIT +- Refine Fast JIT call indirect and call native process +- Refine Fast JIT accessing memory/table instance and global data +- Refine AOT exception check when function return +- Enable source debugger reconnection +- Add wasm_runtime_get_wasi_exit_code +- linux-sgx: Use non-destructive modes for opening files using SGX IPFS +- Add wasm_runtime_unregister_natives +- Implement invokeNative asm code for MinGW +- Add wamr Blog link and Gitbook link to readme +- Remove unnecessary app heap memory clean operations to reduce process RSS +- Normalize how the global heap pool is configured across iwasm apps +- Refine the stack frame size check in interpreter +- Enlarge the default wasm operand stack size to 64KB +- Use cmake POSITION_INDEPENDENT_CODE instead of hardcoding -pie -fPIE +- Implement R_ARM_THM_MOVT_[ABS|REPL] for thumb +- Suppress the warnings when building with GCC11 +- samples/native-lib: Add a bit more complicated example +- Add mutex initializer for wasm-c-api engine operations +- XIP adaptation for xtensa platform +- Update libuv version number +- Remove an improper assumption when creating wasm_trap +- Avoid initialize LLVM repeatedly +- linux-sgx: Improve the remote attestation +- linux-sgx: Improve the documentation of SGX-RA sample +- linux-sgx: Allow to open files with arbitrary paths in the sandbox using IPFS +- Avoid raising exception when debugging with VSCode +- wamr-test-suites: Update runtest.py to support python3 +- Enable Nuttx spec test option and register aot symbols +- Use wabt binary instead of building from source in spec test +- nuttx: Enable ref types by Kconfig +- Update xtensa LLVM version to 15.x +- Add bh_print_proc_mem() to dump memory info of current process +- Create trap for error message when wasm_instance_new fails +- wamr-test-suites: Add support for ARM/RISCV by QEMU +- Enable to compile WAMR on platforms that don't support IPV6 +- Fix warnings in the posix socket implementation +- Update document for MacOS compilation +- Install patched LLDB on vscode extension activation +- Add ARM aeabi memcpy/memmove/memset symbols for AOT bulk memory ops +- Enable wasm cache loading in wasm-c-api + +### Others +- Add CIs to release new version and publish binary files +- Add more compilation groups of fast jit into CI +- Enable spec test on nuttx and daily run it + +--- + +## WAMR-1.1.1 + +- Implement Linux SGX socket API getpeername, recvfrom and sendto +- Implement Linux SGX POSIX calls based on getsockname and set/getbool +- Integrate WASI-NN into WAMR: support TensorFlow/CPU/F32 in the first stage +- Add timeout send/recv and multicast client/server socket examples +- Support cross building and linking LLVM shared libs for wamrc +- Add darwin support for app_framework +- Add ios support for product-mini +- Update export_native_api.md: Relax the "ground rule" +- wasm_export.h: Add comments on wasm_runtime_register_natives +- Remove unused wasm_runtime_is_module_registered +- samples/multi-module: Examine module registration a bit +- samples/native-lib: Fix exec_env type +- Fix Linux SGX directional OCALL parameter for getsockname +- Fix threads issue to enable running threads spec proposal test cases +- Fix the "register native with iwasm" stuff for macOS +- Fix issues in assemblyscript lib +- Wrap wasi_socket_ext api with extern "C" to fix link failure with cxx project +- Fix invalid size of memory allocated in wasi init +- posix_thread.c: Avoid sem_getvalue deprecation warning on macOS + +--- + +## WAMR-1.1.0 + +- Extend support for Socket API: + - Implement IPv6 (along with IPv4) for all the socket-related operations + - Enable resolving host name IP address by adding a host call to WASI + - Implement a security feature for controlling what domains are allowed to be resolved + - Allow configuring socket options by adding host calls to WASI for setting and reading the options + - Enable connection-less communication between hosts by adding host calls to WASI for sending + - data directly to a given address and receiving messages from a specific address + - Fix verification of the address in the address pool + - Add more samples and update the documents + - Implement SGX IPFS as POSIX backend for file interaction for linux-sgx +- Integrates the Intel SGX feature called Intel Protection File System Library (IPFS) into the runtime + to create, operate and delete files inside the enclave, while guaranteeing the confidentiality and + integrity of the data persisted +- Make libc-builtin buffered printf be a common feature +- Enable passing through arguments for build_llvm.sh +- Update \_\_wasi_sock_accept signature to match wasi_snapshot_preview1 +- Enable build wasi_socket_ext.c with both clang and clang++ +- Add check for code section size, fix interpreter float operations +- Prevent an already detached thread from being detached again for thread manager +- Fix several issues related to AOT debug and update source_debugging.md +- Fix Windows/MSVC build issues and compile warnings +- Fix wasm loader: function sub local count can be 0 +- Fix crash in dumping call stack when the AOT file doesn't contain custom name section +- Fix Dockerfile lint errors and suppress hadolint warnings for pinning versions part +- Fix Fast JIT issues reported by instrument test +- Fix link error for ESP-IDF 4.4.2 +- Fix syntax errors and undefined names in Python code +- Fix issues reported by Coverity +- Fix Go binding build error +- Fix a wrongly named parameter and enhance the docs in bh_hashmap.h + +--- + +## WAMR-1.0.0 + +- Implement Python language binding +- Implement Go language binding +- Implement Fast JIT engine +- Implement hw bound check for interpreter and Fast JIT +- Enable the semantic version mechanism for WAMR +- Implement POSIX semaphore support for linux platform +- Implement SGX getrandom/getentropy without ocall +- Enable remote attestation by librats in SGX mode +- Upgrade WAMR-IDE and source debugging +- Support print exception info in source debugger +- Support emit specified custom sections into AoT file +- Refactor spec test script and CI workflows +- Support integrate 3rd-party toolchains into wamrc +- Enable dump call stack to a buffer +- Enable aot compiler with llvm-14/15 +- Don't suppress prev signal handler in hw bound check +- Remove unnecessary memset after mmap +- Refine wasm\*runtime_call_wasm_a/v +- Enable app management and thread support for esp32 arch +- Enable libc-wasi support for esp-idf arch +- Implement xtensa XIP +- Enable memory leak check +- Introduce basic CI for nuttx +- Update documents +- Fix module_realloc with NULL ptr issue +- Fix a typo of macro in wasm_application.c +- nuttx: add CONFIG_INTERPRETERS_WAMR_PERF_PROFILING +- aot_reloc_xtensa.c: define \_\_packed if not available +- Fix bh_vector extend_vector not locked issue +- Enable build libc-wasi for nuttx +- Fix typo in embed_wamr.md +- Fix drop opcode issue in fast interpreter +- Fix typos in wasm_mini_loader.c +- Fix issues reported by Coverity and Klocwork +- Add missing aot relocation symbols for xtensa target +- Add arc compiler-rt functions and reloc type for mwdt +- Fix get invokeNative float ret value issue with clang compiler +- Make robust on choosing target assumption for X86_32 support +- Fix an issue of wasm_cluster_spread_custom_data when called before exec +- Fix socket api verification of addresses in the address pool +- Add API wasm_runtime_set_module_inst +- Set noexecstack CXX link flags for wamrc +- Add import subtyping validation +- Fix libc-wasi/uvwasi poll/environ_get issues +- Add missing symbol for aot_reloc_arc.c +- Add a dev docker container for WAMR repo +- Fix dump call stack issue in interpreter +- Fix windows thread data issue and enhance windows os_mmap +- Support custom stack guard size +- Implement i64.div and i64.rem intrinsics +- Let iwasm return non-zero value when running failed +- Reserve one pointer size for fast-interp code_compiled_size +- Enable libc-wasi support for esp-idf +- Expose wasm_runtime_get_exec_env_singleton to the API users +- Normalize wasm types to refine interpreter call_indirect +- Remove unused wasm_runtime_create_exec_env_and_call_wasm +- Fix linear memory page count issues +- debug: Retire wasm_debug\*(get|set)\_engine_active mechanism +- wasm_application.c: Do not start debug instance automatically +- Fix typo in simd_conversions.c +- nuttx: Add CONFIG_INTERPRETERS_WAMR_DEBUG_INTERP +- Add a new API to get free memory in memory pool +- Fix multi-module and some other issues +- Fix build issue of the meshoptimizer workload +- Fix build error on alios platform + +--- + +## WAMR-X.Y.Z + +### Breaking Changes + +### New Features + +### Bug Fixes + +### Enhancements + +### Others + +--- + + diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/SConscript b/lib/wasm-micro-runtime-WAMR-1.2.2/SConscript similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/SConscript rename to lib/wasm-micro-runtime-WAMR-1.2.2/SConscript diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/SECURITY.md b/lib/wasm-micro-runtime-WAMR-1.2.2/SECURITY.md similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/SECURITY.md rename to lib/wasm-micro-runtime-WAMR-1.2.2/SECURITY.md diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/TSC_Charter.md b/lib/wasm-micro-runtime-WAMR-1.2.2/TSC_Charter.md similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/TSC_Charter.md rename to lib/wasm-micro-runtime-WAMR-1.2.2/TSC_Charter.md diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/assembly-script/.gitignore b/lib/wasm-micro-runtime-WAMR-1.2.2/assembly-script/.gitignore similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/assembly-script/.gitignore rename to lib/wasm-micro-runtime-WAMR-1.2.2/assembly-script/.gitignore diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/assembly-script/README.md b/lib/wasm-micro-runtime-WAMR-1.2.2/assembly-script/README.md similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/assembly-script/README.md rename to lib/wasm-micro-runtime-WAMR-1.2.2/assembly-script/README.md diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/assembly-script/package-lock.json b/lib/wasm-micro-runtime-WAMR-1.2.2/assembly-script/package-lock.json similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/assembly-script/package-lock.json rename to lib/wasm-micro-runtime-WAMR-1.2.2/assembly-script/package-lock.json diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/assembly-script/package.json b/lib/wasm-micro-runtime-WAMR-1.2.2/assembly-script/package.json similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/assembly-script/package.json rename to lib/wasm-micro-runtime-WAMR-1.2.2/assembly-script/package.json diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/assembly-script/samples/event_publisher.ts b/lib/wasm-micro-runtime-WAMR-1.2.2/assembly-script/samples/event_publisher.ts similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/assembly-script/samples/event_publisher.ts rename to lib/wasm-micro-runtime-WAMR-1.2.2/assembly-script/samples/event_publisher.ts diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/assembly-script/samples/event_subscriber.ts b/lib/wasm-micro-runtime-WAMR-1.2.2/assembly-script/samples/event_subscriber.ts similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/assembly-script/samples/event_subscriber.ts rename to lib/wasm-micro-runtime-WAMR-1.2.2/assembly-script/samples/event_subscriber.ts diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/assembly-script/samples/request_handler.ts b/lib/wasm-micro-runtime-WAMR-1.2.2/assembly-script/samples/request_handler.ts similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/assembly-script/samples/request_handler.ts rename to lib/wasm-micro-runtime-WAMR-1.2.2/assembly-script/samples/request_handler.ts diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/assembly-script/samples/request_sender.ts b/lib/wasm-micro-runtime-WAMR-1.2.2/assembly-script/samples/request_sender.ts similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/assembly-script/samples/request_sender.ts rename to lib/wasm-micro-runtime-WAMR-1.2.2/assembly-script/samples/request_sender.ts diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/assembly-script/samples/timer.ts b/lib/wasm-micro-runtime-WAMR-1.2.2/assembly-script/samples/timer.ts similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/assembly-script/samples/timer.ts rename to lib/wasm-micro-runtime-WAMR-1.2.2/assembly-script/samples/timer.ts diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/assembly-script/samples/tsconfig.json b/lib/wasm-micro-runtime-WAMR-1.2.2/assembly-script/samples/tsconfig.json similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/assembly-script/samples/tsconfig.json rename to lib/wasm-micro-runtime-WAMR-1.2.2/assembly-script/samples/tsconfig.json diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/assembly-script/wamr_app_lib/console.ts b/lib/wasm-micro-runtime-WAMR-1.2.2/assembly-script/wamr_app_lib/console.ts similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/assembly-script/wamr_app_lib/console.ts rename to lib/wasm-micro-runtime-WAMR-1.2.2/assembly-script/wamr_app_lib/console.ts diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/assembly-script/wamr_app_lib/request.ts b/lib/wasm-micro-runtime-WAMR-1.2.2/assembly-script/wamr_app_lib/request.ts similarity index 99% rename from lib/wasm-micro-runtime-WAMR-1.1.1/assembly-script/wamr_app_lib/request.ts rename to lib/wasm-micro-runtime-WAMR-1.2.2/assembly-script/wamr_app_lib/request.ts index db72ddd13f7..16a229277a1 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/assembly-script/wamr_app_lib/request.ts +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/assembly-script/wamr_app_lib/request.ts @@ -7,7 +7,7 @@ import * as console from './console' import * as timer from './timer' @external("env", "wasm_response_send") -declare function wasm_response_send(buffer: ArrayBuffer, size: i32): void; +declare function wasm_response_send(buffer: ArrayBuffer, size: i32): bool; @external("env", "wasm_register_resource") declare function wasm_register_resource(url: ArrayBuffer): void; @@ -492,4 +492,4 @@ export function on_response(buffer_offset: i32, size: i32): void { trans.cb(resp); } -} \ No newline at end of file +} diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/assembly-script/wamr_app_lib/timer.ts b/lib/wasm-micro-runtime-WAMR-1.2.2/assembly-script/wamr_app_lib/timer.ts similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/assembly-script/wamr_app_lib/timer.ts rename to lib/wasm-micro-runtime-WAMR-1.2.2/assembly-script/wamr_app_lib/timer.ts diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/assembly-script/wamr_app_lib/tsconfig.json b/lib/wasm-micro-runtime-WAMR-1.2.2/assembly-script/wamr_app_lib/tsconfig.json similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/assembly-script/wamr_app_lib/tsconfig.json rename to lib/wasm-micro-runtime-WAMR-1.2.2/assembly-script/wamr_app_lib/tsconfig.json diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/build-scripts/SConscript b/lib/wasm-micro-runtime-WAMR-1.2.2/build-scripts/SConscript similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/build-scripts/SConscript rename to lib/wasm-micro-runtime-WAMR-1.2.2/build-scripts/SConscript diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/build-scripts/SConscript_config b/lib/wasm-micro-runtime-WAMR-1.2.2/build-scripts/SConscript_config similarity index 98% rename from lib/wasm-micro-runtime-WAMR-1.1.1/build-scripts/SConscript_config rename to lib/wasm-micro-runtime-WAMR-1.2.2/build-scripts/SConscript_config index df96940e9dd..2401f3aa352 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/build-scripts/SConscript_config +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/build-scripts/SConscript_config @@ -92,6 +92,7 @@ else: if GetDepend(['WAMR_DISABLE_HW_BOUND_CHECK']): CPPDEFINES += ['WASM_DISABLE_HW_BOUND_CHECK=1'] + CPPDEFINES += ['WASM_DISABLE_STACK_HW_BOUND_CHECK=1'] print("[WAMR] Hardware boundary check disabled") if GetDepend(['WAMR_BUILD_SIMD']): diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/build-scripts/build_llvm.py b/lib/wasm-micro-runtime-WAMR-1.2.2/build-scripts/build_llvm.py similarity index 64% rename from lib/wasm-micro-runtime-WAMR-1.1.1/build-scripts/build_llvm.py rename to lib/wasm-micro-runtime-WAMR-1.2.2/build-scripts/build_llvm.py index 4e37e390b4f..3957f4b8950 100755 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/build-scripts/build_llvm.py +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/build-scripts/build_llvm.py @@ -7,6 +7,7 @@ import argparse import os import pathlib +import requests import shlex import shutil import subprocess @@ -21,28 +22,44 @@ def clone_llvm(dst_dir, llvm_repo, llvm_branch): llvm_dir = dst_dir.joinpath("llvm").resolve() if not llvm_dir.exists(): - print(f"Clone llvm to {llvm_dir} ...") GIT_CLONE_CMD = f"git clone --depth 1 --branch {llvm_branch} {llvm_repo} llvm" + print(GIT_CLONE_CMD) subprocess.check_output(shlex.split(GIT_CLONE_CMD), cwd=dst_dir) - else: - print(f"There is an LLVM local repo in {llvm_dir}, clean and keep using it") return llvm_dir -def build_llvm(llvm_dir, platform, backends, projects): +def query_llvm_version(llvm_info): + github_token = os.environ['GH_TOKEN'] + owner_project = llvm_info['repo'].replace("https://github.com/", "").replace(".git", "") + url = f"https://api.github.com/repos/{owner_project}/commits/{llvm_info['branch']}" + headers = { + 'Authorization': f"Bearer {github_token}" + } + + try: + response = requests.request("GET", url, headers=headers, data={}) + response.raise_for_status() + except requests.exceptions.HTTPError as error: + print (error) # for debugging purpose + return None + + response = response.json() + return response['sha'] + + +def build_llvm(llvm_dir, platform, backends, projects, use_clang=False, extra_flags=''): LLVM_COMPILE_OPTIONS = [ '-DCMAKE_BUILD_TYPE:STRING="Release"', "-DCMAKE_EXPORT_COMPILE_COMMANDS=ON", "-DLLVM_APPEND_VC_REV:BOOL=ON", - "-DLLVM_BUILD_BENCHMARKS:BOOL=OFF", - "-DLLVM_BUILD_DOCS:BOOL=OFF", "-DLLVM_BUILD_EXAMPLES:BOOL=OFF", "-DLLVM_BUILD_LLVM_DYLIB:BOOL=OFF", "-DLLVM_BUILD_TESTS:BOOL=OFF", - "-DLLVM_CCACHE_BUILD:BOOL=OFF", + "-DLLVM_CCACHE_BUILD:BOOL=ON", "-DLLVM_ENABLE_BINDINGS:BOOL=OFF", "-DLLVM_ENABLE_IDE:BOOL=OFF", + "-DLLVM_ENABLE_LIBEDIT=OFF", "-DLLVM_ENABLE_TERMINFO:BOOL=OFF", "-DLLVM_ENABLE_ZLIB:BOOL=OFF", "-DLLVM_INCLUDE_BENCHMARKS:BOOL=OFF", @@ -54,6 +71,18 @@ def build_llvm(llvm_dir, platform, backends, projects): "-DLLVM_OPTIMIZED_TABLEGEN:BOOL=ON", ] + # use clang/clang++/lld. but macos doesn't support lld + if not sys.platform.startswith("darwin") and use_clang: + if shutil.which("clang") and shutil.which("clang++") and shutil.which("lld"): + os.environ["CC"] = "clang" + os.environ["CXX"] = "clang++" + LLVM_COMPILE_OPTIONS.append('-DLLVM_USE_LINKER:STRING="lld"') + print("Use the clang toolchain") + else: + print("Can not find clang, clang++ and lld, keep using the gcc toolchain") + else: + print("Use the gcc toolchain") + LLVM_EXTRA_COMPILE_OPTIONS = { "arc": [ '-DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD:STRING="ARC"', @@ -99,8 +128,10 @@ def build_llvm(llvm_dir, platform, backends, projects): lib_llvm_core_library = build_dir.joinpath("lib/libLLVMCore.a").resolve() if lib_llvm_core_library.exists(): - print(f"Please remove {build_dir} manually and try again") - return build_dir + print( + f"It has already been fully compiled. If want to a re-build, please remove {build_dir} manually and try again" + ) + return None compile_options = " ".join( LLVM_COMPILE_OPTIONS @@ -113,16 +144,17 @@ def build_llvm(llvm_dir, platform, backends, projects): + LLVM_INCLUDE_TOOLS_OPTION ) - CONFIG_CMD = f"cmake {compile_options} ../llvm" + CONFIG_CMD = f"cmake {compile_options} {extra_flags} ../llvm" if "windows" == platform: if "mingw" in sysconfig.get_platform().lower(): CONFIG_CMD += " -G'Unix Makefiles'" else: CONFIG_CMD += " -A x64" - print(f"{CONFIG_CMD}") + else: + CONFIG_CMD += " -G'Ninja'" subprocess.check_call(shlex.split(CONFIG_CMD), cwd=build_dir) - BUILD_CMD = f"cmake --build . --target package --parallel {os.cpu_count()}" + ( + BUILD_CMD = "cmake --build . --target package" + ( " --config Release" if "windows" == platform else "" ) subprocess.check_call(shlex.split(BUILD_CMD), cwd=build_dir) @@ -133,23 +165,25 @@ def build_llvm(llvm_dir, platform, backends, projects): def repackage_llvm(llvm_dir): build_dir = llvm_dir.joinpath("./build").resolve() - packs = [f for f in build_dir.glob("LLVM-13*.tar.gz")] + packs = [f for f in build_dir.glob("LLVM-*.tar.gz")] if len(packs) > 1: - raise Exception("Find more than one LLVM-13*.tar.gz") + raise Exception("Find more than one LLVM-*.tar.gz") if not packs: return llvm_package = packs[0].name - # mv build/LLVM-13.0.0*.gz . + # mv build/LLVM-*.gz . shutil.move(str(build_dir.joinpath(llvm_package).resolve()), str(llvm_dir)) # rm -r build shutil.rmtree(str(build_dir)) # mkdir build build_dir.mkdir() - # tar xf ./LLVM-13.0.0-*.tar.gz --strip-components=1 --directory=build + # tar xf ./LLVM-*.tar.gz --strip-components=1 --directory=build CMD = f"tar xf {llvm_dir.joinpath(llvm_package).resolve()} --strip-components=1 --directory={build_dir}" subprocess.check_call(shlex.split(CMD), cwd=llvm_dir) + # rm ./LLVM-1*.gz + os.remove(llvm_dir.joinpath(llvm_package).resolve()) def main(): @@ -184,8 +218,23 @@ def main(): choices=["clang", "lldb"], help="identify extra LLVM projects, separate by space, like '--project clang lldb'", ) + parser.add_argument( + "--llvm-ver", + action="store_true", + help="return the version info of generated llvm libraries", + ) + parser.add_argument( + "--use-clang", + action="store_true", + help="use clang instead of gcc", + ) + parser.add_argument( + "--extra-cmake-flags", + type=str, + default="", + help="custom extra cmake flags", + ) options = parser.parse_args() - print(f"options={options}") # if the "platform" is not identified in the command line option, # detect it @@ -199,20 +248,21 @@ def main(): else: platform = options.platform - print(f"========== Build LLVM for {platform} ==========\n") - llvm_repo_and_branch = { "arc": { "repo": "https://github.com/llvm/llvm-project.git", - "branch": "release/13.x", + "repo_ssh": "git@github.com:llvm/llvm-project.git", + "branch": "release/15.x", }, "xtensa": { - "repo": "https://github.com/espressif/llvm-project.git", - "branch": "xtensa_release_13.0.0", + "repo": "https://github.com/espressif/llvm-project.git", + "repo_ssh": "git@github.com:espressif/llvm-project.git", + "branch": "xtensa_release_15.x", }, "default": { "repo": "https://github.com/llvm/llvm-project.git", - "branch": "release/13.x", + "repo_ssh": "git@github.com:llvm/llvm-project.git", + "branch": "release/15.x", }, } @@ -225,19 +275,29 @@ def main(): deps_dir = current_dir.joinpath("../core/deps").resolve() try: - print(f"==================== CLONE LLVM ====================") llvm_info = llvm_repo_and_branch.get(platform, llvm_repo_and_branch["default"]) - llvm_dir = clone_llvm(deps_dir, llvm_info["repo"], llvm_info["branch"]) - print() - print(f"==================== BUILD LLVM ====================") - build_llvm(llvm_dir, platform, options.arch, options.project) - - print() - print(f"==================== PACKAGE LLVM ====================") - repackage_llvm(llvm_dir) + if options.llvm_ver: + commit_hash = query_llvm_version(llvm_info) + print(commit_hash) + return commit_hash is not None + + repo_addr = llvm_info["repo"] + if os.environ.get('USE_GIT_SSH') == "true": + repo_addr = llvm_info["repo_ssh"] + else: + print("To use ssh for git clone, run: export USE_GIT_SSH=true") + + llvm_dir = clone_llvm(deps_dir, repo_addr, llvm_info["branch"]) + if ( + build_llvm( + llvm_dir, platform, options.arch, options.project, options.use_clang, + options.extra_cmake_flags + ) + is not None + ): + repackage_llvm(llvm_dir) - print() return True except subprocess.CalledProcessError: return False diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/build-scripts/config_common.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/build-scripts/config_common.cmake similarity index 64% rename from lib/wasm-micro-runtime-WAMR-1.1.1/build-scripts/config_common.cmake rename to lib/wasm-micro-runtime-WAMR-1.2.2/build-scripts/config_common.cmake index c99d1564f92..ea8ad1f3204 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/build-scripts/config_common.cmake +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/build-scripts/config_common.cmake @@ -3,7 +3,6 @@ string(TOUPPER ${WAMR_BUILD_TARGET} WAMR_BUILD_TARGET) - # Add definitions for the build target if (WAMR_BUILD_TARGET STREQUAL "X86_64") add_definitions(-DBUILD_TARGET_X86_64) @@ -58,7 +57,9 @@ if (CMAKE_SIZEOF_VOID_P EQUAL 8) if (NOT WAMR_BUILD_PLATFORM STREQUAL "windows") # Add -fPIC flag if build as 64-bit set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC") + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") set (CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "${CMAKE_SHARED_LIBRARY_LINK_C_FLAGS} -fPIC") + set (CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "${CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS} -fPIC") endif () else () include(CheckCCompilerFlag) @@ -84,54 +85,48 @@ if (NOT WAMR_BUILD_AOT EQUAL 1) endif () endif () +if (WAMR_BUILD_FAST_JIT EQUAL 1) + if (NOT WAMR_BUILD_LAZY_JIT EQUAL 0) + # Enable Lazy JIT by default + set (WAMR_BUILD_LAZY_JIT 1) + endif () +endif () + if (WAMR_BUILD_JIT EQUAL 1) - if (WAMR_BUILD_AOT EQUAL 1) - add_definitions("-DWASM_ENABLE_JIT=1") - if (NOT WAMR_BUILD_LAZY_JIT EQUAL 0) - # Enable Lazy JIT by default - set (WAMR_BUILD_LAZY_JIT 1) - add_definitions("-DWASM_ENABLE_LAZY_JIT=1") + if (NOT WAMR_BUILD_LAZY_JIT EQUAL 0) + # Enable Lazy JIT by default + set (WAMR_BUILD_LAZY_JIT 1) + endif () + if (NOT DEFINED LLVM_DIR) + set (LLVM_SRC_ROOT "${WAMR_ROOT_DIR}/core/deps/llvm") + set (LLVM_BUILD_ROOT "${LLVM_SRC_ROOT}/build") + if (WAMR_BUILD_PLATFORM STREQUAL "windows") + set (LLVM_BUILD_ROOT "${LLVM_SRC_ROOT}/win32build") endif () - if (NOT DEFINED LLVM_DIR) - set (LLVM_SRC_ROOT "${WAMR_ROOT_DIR}/core/deps/llvm") - set (LLVM_BUILD_ROOT "${LLVM_SRC_ROOT}/build") - if (WAMR_BUILD_PLATFORM STREQUAL "windows") - set (LLVM_BUILD_ROOT "${LLVM_SRC_ROOT}/win32build") - endif () - if (NOT EXISTS "${LLVM_BUILD_ROOT}") + if (NOT EXISTS "${LLVM_BUILD_ROOT}") message (FATAL_ERROR "Cannot find LLVM dir: ${LLVM_BUILD_ROOT}") - endif () - set (CMAKE_PREFIX_PATH "${LLVM_BUILD_ROOT};${CMAKE_PREFIX_PATH}") endif () - find_package(LLVM REQUIRED CONFIG) - include_directories(${LLVM_INCLUDE_DIRS}) - add_definitions(${LLVM_DEFINITIONS}) - message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") - message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") - else () - set (WAMR_BUILD_JIT 0) - message ("-- WAMR JIT disabled due to WAMR AOT is disabled") - endif () + set (CMAKE_PREFIX_PATH "${LLVM_BUILD_ROOT};${CMAKE_PREFIX_PATH}") + set (LLVM_DIR ${LLVM_BUILD_ROOT}/lib/cmake/llvm) + endif () + find_package(LLVM REQUIRED CONFIG) + include_directories(${LLVM_INCLUDE_DIRS}) + add_definitions(${LLVM_DEFINITIONS}) + message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") + message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") + + # Disable -Wredundant-move when building LLVM JIT + include(CheckCXXCompilerFlag) + if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + check_cxx_compiler_flag("-Wredundant-move" CXX_SUPPORTS_REDUNDANT_MOVE_FLAG) + if (CXX_SUPPORTS_REDUNDANT_MOVE_FLAG) + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-redundant-move") + endif () + endif () else () unset (LLVM_AVAILABLE_LIBS) endif () -######################################## -## semantic version information - -if (NOT DEFINED WAMR_VERSION_MAJOR) - set (WAMR_VERSION_MAJOR 1) -endif () - -if (NOT DEFINED WAMR_VERSION_MINOR) - set (WAMR_VERSION_MINOR 1) -endif () - -if (NOT DEFINED WAMR_VERSION_PATCH) - set (WAMR_VERSION_PATCH 1) -endif () - -configure_file(${WAMR_ROOT_DIR}/core/version.h.in ${WAMR_ROOT_DIR}/core/version.h @ONLY) ######################################## message ("-- Build Configurations:") @@ -139,9 +134,6 @@ message (" Build as target ${WAMR_BUILD_TARGET}") message (" CMAKE_BUILD_TYPE " ${CMAKE_BUILD_TYPE}) if (WAMR_BUILD_INTERP EQUAL 1) message (" WAMR Interpreter enabled") -elseif (WAMR_BUILD_JIT EQUAL 1) - set (WAMR_BUILD_INTERP 1) - message (" WAMR Interpreter enabled due to WAMR JIT is enabled") else () message (" WAMR Interpreter disabled") endif () @@ -150,16 +142,30 @@ if (WAMR_BUILD_AOT EQUAL 1) else () message (" WAMR AOT disabled") endif () +if (WAMR_BUILD_FAST_JIT EQUAL 1) + if (WAMR_BUILD_LAZY_JIT EQUAL 1) + add_definitions("-DWASM_ENABLE_LAZY_JIT=1") + message (" WAMR Fast JIT enabled with Lazy Compilation") + else () + message (" WAMR Fast JIT enabled with Eager Compilation") + endif () +else () + message (" WAMR Fast JIT disabled") +endif () if (WAMR_BUILD_JIT EQUAL 1) + add_definitions("-DWASM_ENABLE_JIT=1") if (WAMR_BUILD_LAZY_JIT EQUAL 1) - message (" WAMR LLVM Orc Lazy JIT enabled") + add_definitions("-DWASM_ENABLE_LAZY_JIT=1") + message (" WAMR LLVM ORC JIT enabled with Lazy Compilation") else () - message (" WAMR LLVM MC JIT enabled") + message (" WAMR LLVM ORC JIT enabled with Eager Compilation") endif () -elseif (WAMR_BUILD_FAST_JIT EQUAL 1) - message (" WAMR Fast JIT enabled") else () - message (" WAMR JIT disabled") + message (" WAMR LLVM ORC JIT disabled") +endif () +if (WAMR_BUILD_FAST_JIT EQUAL 1 AND WAMR_BUILD_JIT EQUAL 1 + AND WAMR_BUILD_LAZY_JIT EQUAL 1) + message (" Multi-tier JIT enabled") endif () if (WAMR_BUILD_LIBC_BUILTIN EQUAL 1) message (" Libc builtin enabled") @@ -191,11 +197,16 @@ if (WAMR_BUILD_SPEC_TEST EQUAL 1) add_definitions (-DWASM_ENABLE_SPEC_TEST=1) message (" spec test compatible mode is on") endif () +if (NOT DEFINED WAMR_BUILD_BULK_MEMORY) + # Enable bulk memory by default + set (WAMR_BUILD_BULK_MEMORY 1) +endif () if (WAMR_BUILD_BULK_MEMORY EQUAL 1) add_definitions (-DWASM_ENABLE_BULK_MEMORY=1) message (" Bulk memory feature enabled") else () add_definitions (-DWASM_ENABLE_BULK_MEMORY=0) + message (" Bulk memory feature disabled") endif () if (WAMR_BUILD_SHARED_MEMORY EQUAL 1) add_definitions (-DWASM_ENABLE_SHARED_MEMORY=1) @@ -212,6 +223,9 @@ endif () if (WAMR_BUILD_LIB_PTHREAD_SEMAPHORE EQUAL 1) message (" Lib pthread semaphore enabled") endif () +if (WAMR_BUILD_LIB_WASI_THREADS EQUAL 1) + message (" Lib wasi-threads enabled") +endif () if (WAMR_BUILD_LIBC_EMCC EQUAL 1) message (" Libc emcc enabled") endif () @@ -226,9 +240,16 @@ else () endif () if (WAMR_DISABLE_HW_BOUND_CHECK EQUAL 1) add_definitions (-DWASM_DISABLE_HW_BOUND_CHECK=1) + add_definitions (-DWASM_DISABLE_STACK_HW_BOUND_CHECK=1) message (" Hardware boundary check disabled") else () add_definitions (-DWASM_DISABLE_HW_BOUND_CHECK=0) + if (WAMR_DISABLE_STACK_HW_BOUND_CHECK EQUAL 1) + add_definitions (-DWASM_DISABLE_STACK_HW_BOUND_CHECK=1) + message (" Hardware boundary check for native stack disabled") + else () + add_definitions (-DWASM_DISABLE_STACK_HW_BOUND_CHECK=0) + endif () endif () if (WAMR_BUILD_SIMD EQUAL 1) if (NOT WAMR_BUILD_TARGET MATCHES "RISCV64.*") @@ -283,6 +304,28 @@ if (WAMR_BUILD_LOAD_CUSTOM_SECTION EQUAL 1) add_definitions (-DWASM_ENABLE_LOAD_CUSTOM_SECTION=1) message (" Load custom section enabled") endif () +if (WAMR_BUILD_GLOBAL_HEAP_POOL EQUAL 1) + add_definitions(-DWASM_ENABLE_GLOBAL_HEAP_POOL=1) + message (" Global heap pool enabled") +endif () +if (WAMR_BUILD_GLOBAL_HEAP_SIZE GREATER 0) + add_definitions (-DWASM_GLOBAL_HEAP_SIZE=${WAMR_BUILD_GLOBAL_HEAP_SIZE}) + message (" Custom global heap size: " ${WAMR_BUILD_GLOBAL_HEAP_SIZE}) +else () + # Spec test requires more heap pool size + if (WAMR_BUILD_SPEC_TEST EQUAL 1) + if (WAMR_BUILD_PLATFORM STREQUAL "linux-sgx") + math(EXPR WAMR_BUILD_GLOBAL_HEAP_SIZE "100 * 1024 * 1024") + else () + math(EXPR WAMR_BUILD_GLOBAL_HEAP_SIZE "300 * 1024 * 1024") + endif () + add_definitions (-DWASM_GLOBAL_HEAP_SIZE=${WAMR_BUILD_GLOBAL_HEAP_SIZE}) + else () + # By default, the global heap size is of 10 MB + math(EXPR WAMR_BUILD_GLOBAL_HEAP_SIZE "10 * 1024 * 1024") + add_definitions (-DWASM_GLOBAL_HEAP_SIZE=${WAMR_BUILD_GLOBAL_HEAP_SIZE}) + endif () +endif () if (WAMR_BUILD_STACK_GUARD_SIZE GREATER 0) add_definitions (-DWASM_STACK_GUARD_SIZE=${WAMR_BUILD_STACK_GUARD_SIZE}) message (" Custom stack guard size: " ${WAMR_BUILD_STACK_GUARD_SIZE}) @@ -293,4 +336,33 @@ if (WAMR_BUILD_SGX_IPFS EQUAL 1) endif () if (WAMR_BUILD_WASI_NN EQUAL 1) message (" WASI-NN enabled") + add_definitions (-DWASM_ENABLE_WASI_NN=1) + if (WASI_NN_ENABLE_GPU EQUAL 1) + message (" WASI-NN: GPU enabled") + add_definitions (-DWASI_NN_ENABLE_GPU=1) + endif () + if (WAMR_BUILD_WASI_NN_ENABLE_EXT EQUAL 1) + message (" WASI-NN: External Delegation enabled") + add_definitions (-DWASI_NN_ENABLE_EXTERNAL_DELEGATE=1) + endif () + if (DEFINED WASI_NN_EXT_DELEGATE_PATH) + add_definitions (-DWASI_NN_EXT_DELEGATE_PATH="${WASI_NN_EXT_DELEGATE_PATH}") + endif () +endif () +if (WAMR_BUILD_ALLOC_WITH_USER_DATA EQUAL 1) + add_definitions(-DWASM_MEM_ALLOC_WITH_USER_DATA=1) +endif() +if (WAMR_BUILD_WASM_CACHE EQUAL 1) + add_definitions (-DWASM_ENABLE_WASM_CACHE=1) + message (" Wasm files cache enabled") +endif () +if (WAMR_BUILD_GC_HEAP_VERIFY EQUAL 1) + add_definitions (-DWASM_ENABLE_GC_VERIFY=1) + message (" GC heap verification enabled") +endif () +if ("$ENV{COLLECT_CODE_COVERAGE}" STREQUAL "1" OR COLLECT_CODE_COVERAGE EQUAL 1) + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage") + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage") + add_definitions (-DCOLLECT_CODE_COVERAGE) + message (" Collect code coverage enabled") endif () diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/build-scripts/esp-idf/README.md b/lib/wasm-micro-runtime-WAMR-1.2.2/build-scripts/esp-idf/README.md similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/build-scripts/esp-idf/README.md rename to lib/wasm-micro-runtime-WAMR-1.2.2/build-scripts/esp-idf/README.md diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/build-scripts/esp-idf/wamr/CMakeLists.txt b/lib/wasm-micro-runtime-WAMR-1.2.2/build-scripts/esp-idf/wamr/CMakeLists.txt similarity index 97% rename from lib/wasm-micro-runtime-WAMR-1.1.1/build-scripts/esp-idf/wamr/CMakeLists.txt rename to lib/wasm-micro-runtime-WAMR-1.2.2/build-scripts/esp-idf/wamr/CMakeLists.txt index c7b6100ec84..5ac04ddc92e 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/build-scripts/esp-idf/wamr/CMakeLists.txt +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/build-scripts/esp-idf/wamr/CMakeLists.txt @@ -51,7 +51,7 @@ endif() idf_component_register(SRCS ${WAMR_RUNTIME_LIB_SOURCE} ${PLATFORM_SHARED_SOURCE} INCLUDE_DIRS ${IWASM_DIR}/include ${UTILS_SHARED_DIR} ${PLATFORM_SHARED_DIR} ${PLATFORM_SHARED_DIR}/../include - REQUIRES pthread + REQUIRES pthread lwip esp_timer ) diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/build-scripts/involve_boringssl.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/build-scripts/involve_boringssl.cmake new file mode 100644 index 00000000000..a0e069ba888 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/build-scripts/involve_boringssl.cmake @@ -0,0 +1,41 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +message(STATUS "involving boringssl...") + +include(ExternalProject) + +ExternalProject_Add(boringssl + PREFIX external/boringssl + # follow envoy, which tracks BoringSSL, which tracks Chromium + # https://github.com/envoyproxy/envoy/blob/main/bazel/repository_locations.bzl#L112 + # chromium-105.0.5195.37 (linux/beta) + URL https://github.com/google/boringssl/archive/098695591f3a2665fccef83a3732ecfc99acdcdd.tar.gz + URL_HASH SHA256=e141448cf6f686b6e9695f6b6459293fd602c8d51efe118a83106752cf7e1280 + DOWNLOAD_EXTRACT_TIMESTAMP NEW + # SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/../external/boringssl + INSTALL_COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_BINARY_DIR}/external/boringssl/src/boringssl-build/libssl.a + ${CMAKE_CURRENT_BINARY_DIR}/external/boringssl/ + && ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_BINARY_DIR}/external/boringssl/src/boringssl-build/libcrypto.a + ${CMAKE_CURRENT_BINARY_DIR}/external/boringssl/ + && ${CMAKE_COMMAND} -E create_symlink ${CMAKE_CURRENT_BINARY_DIR}/external/boringssl/src/boringssl/src/include/openssl + ${CMAKE_CURRENT_BINARY_DIR}/external/boringssl/openssl +) + +add_library(boringssl_ssl STATIC IMPORTED GLOBAL) +set_target_properties( + boringssl_ssl + PROPERTIES + IMPORTED_LOCATION ${CMAKE_CURRENT_BINARY_DIR}/external/boringssl/libssl.a + INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_BINARY_DIR}/external/boringssl/ +) +add_dependencies(boringssl_ssl boringssl) + +add_library(boringssl_crypto STATIC IMPORTED GLOBAL) +set_target_properties( + boringssl_crypto + PROPERTIES + IMPORTED_LOCATION ${CMAKE_CURRENT_BINARY_DIR}/external/boringssl/libcrypto.a + INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_BINARY_DIR}/external/boringssl/ +) +add_dependencies(boringssl_crypto boringssl) \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/build-scripts/lldb-wasm.patch b/lib/wasm-micro-runtime-WAMR-1.2.2/build-scripts/lldb-wasm.patch similarity index 99% rename from lib/wasm-micro-runtime-WAMR-1.1.1/build-scripts/lldb-wasm.patch rename to lib/wasm-micro-runtime-WAMR-1.2.2/build-scripts/lldb-wasm.patch index 74dd4dfe1de..d6044e3a3ee 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/build-scripts/lldb-wasm.patch +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/build-scripts/lldb-wasm.patch @@ -1,3 +1,15 @@ +diff --git a/lldb/include/lldb/Breakpoint/Breakpoint.h b/lldb/include/lldb/Breakpoint/Breakpoint.h +index f2e2a0d22..426d1129b 100644 +--- a/lldb/include/lldb/Breakpoint/Breakpoint.h ++++ b/lldb/include/lldb/Breakpoint/Breakpoint.h +@@ -9,6 +9,7 @@ + #ifndef LLDB_BREAKPOINT_BREAKPOINT_H + #define LLDB_BREAKPOINT_BREAKPOINT_H + ++#include + #include + #include + #include diff --git a/lldb/include/lldb/Core/Module.h b/lldb/include/lldb/Core/Module.h index dd7100c46..97d70daad 100644 --- a/lldb/include/lldb/Core/Module.h @@ -5829,3 +5841,27 @@ index 4ec2e25c7..24c88fe9a 100644 default: return std::make_shared(); } +diff --git a/llvm/include/llvm/ExecutionEngine/Orc/OrcRPCExecutorProcessControl.h b/llvm/include/llvm/ExecutionEngine/Orc/OrcRPCExecutorProcessControl.h +index 4310ba9ce..297b33879 100644 +--- a/llvm/include/llvm/ExecutionEngine/Orc/OrcRPCExecutorProcessControl.h ++++ b/llvm/include/llvm/ExecutionEngine/Orc/OrcRPCExecutorProcessControl.h +@@ -13,6 +13,7 @@ + #ifndef LLVM_EXECUTIONENGINE_ORC_ORCRPCEXECUTORPROCESSCONTROL_H + #define LLVM_EXECUTIONENGINE_ORC_ORCRPCEXECUTORPROCESSCONTROL_H + ++#include "llvm/ExecutionEngine/Orc/Core.h" + #include "llvm/ExecutionEngine/Orc/ExecutorProcessControl.h" + #include "llvm/ExecutionEngine/Orc/Shared/RPCUtils.h" + #include "llvm/ExecutionEngine/Orc/Shared/RawByteChannel.h" +diff --git a/llvm/include/llvm/Support/MathExtras.h b/llvm/include/llvm/Support/MathExtras.h +index 753b1998c..27370c62d 100644 +--- a/llvm/include/llvm/Support/MathExtras.h ++++ b/llvm/include/llvm/Support/MathExtras.h +@@ -16,6 +16,7 @@ + #include "llvm/Support/Compiler.h" + #include + #include ++#include + #include + #include + #include diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/build-scripts/requirements.txt b/lib/wasm-micro-runtime-WAMR-1.2.2/build-scripts/requirements.txt new file mode 100644 index 00000000000..bf0d9d41143 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/build-scripts/requirements.txt @@ -0,0 +1 @@ +requests==2.28.2 \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/build-scripts/runtime_lib.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/build-scripts/runtime_lib.cmake similarity index 80% rename from lib/wasm-micro-runtime-WAMR-1.1.1/build-scripts/runtime_lib.cmake rename to lib/wasm-micro-runtime-WAMR-1.2.2/build-scripts/runtime_lib.cmake index 2a46d4325f2..6931ece74b9 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/build-scripts/runtime_lib.cmake +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/build-scripts/runtime_lib.cmake @@ -1,7 +1,6 @@ # Copyright (C) 2019 Intel Corporation. All rights reserved. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - if (NOT DEFINED WAMR_ROOT_DIR) set (WAMR_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../) endif () @@ -20,6 +19,11 @@ endif () if (NOT DEFINED DEPS_DIR) set (DEPS_DIR ${WAMR_ROOT_DIR}/core/deps) endif () +if (NOT DEFINED SHARED_PLATFORM_CONFIG) + # CMake file for platform configuration. The PLATFORM_SHARED_SOURCE varable + # should point to a list of platform-specfic source files to compile. + set (SHARED_PLATFORM_CONFIG ${SHARED_DIR}/platform/${WAMR_BUILD_PLATFORM}/shared_platform.cmake) +endif () if (DEFINED EXTRA_SDK_INCLUDE_PATH) message(STATUS, "EXTRA_SDK_INCLUDE_PATH = ${EXTRA_SDK_INCLUDE_PATH} ") @@ -50,25 +54,30 @@ if (NOT DEFINED WAMR_BUILD_TARGET) endif () ################ optional according to settings ################ -if (WAMR_BUILD_INTERP EQUAL 1 OR WAMR_BUILD_JIT EQUAL 1 - OR WAMR_BUILD_FAST_JIT EQUAL 1) - if (WAMR_BUILD_FAST_JIT EQUAL 1 OR WAMR_BUILD_JIT EQUAL 1) - set (WAMR_BUILD_FAST_INTERP 0) - endif () - include (${IWASM_DIR}/interpreter/iwasm_interp.cmake) +if (WAMR_BUILD_FAST_JIT EQUAL 1 OR WAMR_BUILD_JIT EQUAL 1) + # Enable classic interpreter if Fast JIT or LLVM JIT is enabled + set (WAMR_BUILD_INTERP 1) + set (WAMR_BUILD_FAST_INTERP 0) endif () -if (WAMR_BUILD_AOT EQUAL 1) - include (${IWASM_DIR}/aot/iwasm_aot.cmake) - if (WAMR_BUILD_JIT EQUAL 1) - include (${IWASM_DIR}/compilation/iwasm_compl.cmake) - endif () +if (WAMR_BUILD_INTERP EQUAL 1) + include (${IWASM_DIR}/interpreter/iwasm_interp.cmake) endif () -if (NOT WAMR_BUILD_JIT EQUAL 1 AND WAMR_BUILD_FAST_JIT EQUAL 1) +if (WAMR_BUILD_FAST_JIT EQUAL 1) include (${IWASM_DIR}/fast-jit/iwasm_fast_jit.cmake) endif () +if (WAMR_BUILD_JIT EQUAL 1) + # Enable AOT if LLVM JIT is enabled + set (WAMR_BUILD_AOT 1) + include (${IWASM_DIR}/compilation/iwasm_compl.cmake) +endif () + +if (WAMR_BUILD_AOT EQUAL 1) + include (${IWASM_DIR}/aot/iwasm_aot.cmake) +endif () + if (WAMR_BUILD_APP_FRAMEWORK EQUAL 1) include (${APP_FRAMEWORK_DIR}/app_framework.cmake) include (${SHARED_DIR}/coap/lib_coap.cmake) @@ -92,15 +101,6 @@ if (WAMR_BUILD_LIB_PTHREAD_SEMAPHORE EQUAL 1) endif () if (WAMR_BUILD_WASI_NN EQUAL 1) - execute_process(COMMAND ${WAMR_ROOT_DIR}/core/deps/install_tensorflow.sh - RESULT_VARIABLE TENSORFLOW_RESULT - ) - set(TENSORFLOW_SOURCE_DIR "${WAMR_ROOT_DIR}/core/deps/tensorflow-src") - include_directories (${CMAKE_CURRENT_BINARY_DIR}/flatbuffers/include) - include_directories (${TENSORFLOW_SOURCE_DIR}) - add_subdirectory( - "${TENSORFLOW_SOURCE_DIR}/tensorflow/lite" - "${CMAKE_CURRENT_BINARY_DIR}/tensorflow-lite" EXCLUDE_FROM_ALL) include (${IWASM_DIR}/libraries/wasi-nn/wasi_nn.cmake) endif () @@ -112,6 +112,14 @@ if (WAMR_BUILD_LIB_PTHREAD EQUAL 1) set (WAMR_BUILD_SHARED_MEMORY 1) endif () +if (WAMR_BUILD_LIB_WASI_THREADS EQUAL 1) + include (${IWASM_DIR}/libraries/lib-wasi-threads/lib_wasi_threads.cmake) + # Enable the dependent feature if lib wasi threads is enabled + set (WAMR_BUILD_THREAD_MGR 1) + set (WAMR_BUILD_BULK_MEMORY 1) + set (WAMR_BUILD_SHARED_MEMORY 1) +endif () + if (WAMR_BUILD_DEBUG_INTERP EQUAL 1) set (WAMR_BUILD_THREAD_MGR 1) include (${IWASM_DIR}/libraries/debug-engine/debug_engine.cmake) @@ -135,6 +143,10 @@ if (WAMR_BUILD_LIB_RATS EQUAL 1) include (${IWASM_DIR}/libraries/lib-rats/lib_rats.cmake) endif () +if (WAMR_BUILD_WASM_CACHE EQUAL 1) + include (${WAMR_ROOT_DIR}/build-scripts/involve_boringssl.cmake) +endif () + ####################### Common sources ####################### if (NOT MSVC) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99 -ffunction-sections -fdata-sections \ @@ -153,7 +165,7 @@ LIST (APPEND RUNTIME_LIB_HEADER_LIST ${header}) enable_language (ASM) -include (${SHARED_DIR}/platform/${WAMR_BUILD_PLATFORM}/shared_platform.cmake) +include (${SHARED_PLATFORM_CONFIG}) include (${SHARED_DIR}/mem-alloc/mem_alloc.cmake) include (${IWASM_DIR}/common/iwasm_common.cmake) include (${SHARED_DIR}/utils/shared_utils.cmake) @@ -174,6 +186,7 @@ set (source_all ${WASM_APP_LIB_SOURCE_ALL} ${NATIVE_INTERFACE_SOURCE} ${APP_MGR_SOURCE} + ${LIB_WASI_THREADS_SOURCE} ${LIB_PTHREAD_SOURCE} ${THREAD_MGR_SOURCE} ${LIBC_EMCC_SOURCE} diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/ci/build_wamr.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/ci/build_wamr.sh similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/ci/build_wamr.sh rename to lib/wasm-micro-runtime-WAMR-1.2.2/ci/build_wamr.sh diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/ci/coding_guidelines_check.py b/lib/wasm-micro-runtime-WAMR-1.2.2/ci/coding_guidelines_check.py similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/ci/coding_guidelines_check.py rename to lib/wasm-micro-runtime-WAMR-1.2.2/ci/coding_guidelines_check.py diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/README.md b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/README.md similarity index 81% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/README.md rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/README.md index 34f0e27eb9a..d1476fd8bc1 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/README.md +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/README.md @@ -1,28 +1,27 @@ -Application framework -======= - -## Directory structure +# Application framework +By using the WAMR VM core, we are flexible to build different application frameworks for the specific domains, although it would take quite some effort. +The WAMR has offered a comprehensive framework for programming WASM applications for device and IoT usages. The framework supports running multiple applications, that are based on the event driven programming model. Here are the supporting API sets by the [WAMR application framework library](../doc/wamr_api.md) : -This folder "app-native-shared" is for the source files shared by both WASM APP and native runtime +- Timer, Inter-app communication (request/response and pub/sub), Sensor, Connectivity and data transmission, 2D graphic UI -- The c files in this directory are compiled into both the WASM APP and runtime. -- The header files for distributing to SDK are placed in the "bi-inc" folder. +Browse the folder [core/app-framework](./app-framework) for how to extend the application framework. +## Directory structure +This folder "app-native-shared" is for the source files shared by both WASM APP and native runtime -This folder "template" contains a pre-defined directory structure for a framework component. The developers can copy the template folder to create new components to the application framework. - +- The c files in this directory are compiled into both the WASM APP and runtime. +- The header files for distributing to SDK are placed in the "bi-inc" folder. +This folder "template" contains a pre-defined directory structure for a framework component. The developers can copy the template folder to create new components to the application framework. -Every other subfolder is framework component. Each component contains two library parts: **app and native**. +Every other subfolder is framework component. Each component contains two library parts: **app and native**. - The "base" component provide timer API and inter-app communication support. It must be enabled if other components are selected. - Under the "app" folder of a component, the subfolder "wa_inc" holds all header files that should be included by the WASM applications - - ## Application framework basic model The app framework is built on top of two fundamental operations: @@ -116,10 +115,6 @@ Generally you should follow following steps to create a new component: ``` - ## Sensor component working flow - - - ![](../../doc/pics/sensor_callflow.PNG) diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/app-native-shared/README.md b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/app-native-shared/README.md similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/app-native-shared/README.md rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/app-native-shared/README.md diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/app-native-shared/attr_container.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/app-native-shared/attr_container.c similarity index 81% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/app-native-shared/attr_container.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/app-native-shared/attr_container.c index e8c12019600..e1e9f4e359b 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/app-native-shared/attr_container.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/app-native-shared/attr_container.c @@ -7,11 +7,14 @@ typedef union jvalue { bool z; - int8_t b; - uint16_t c; - int16_t s; - int32_t i; - int64_t j; + int8_t i8; + uint8_t u8; + int16_t i16; + uint16_t u16; + int32_t i32; + uint32_t u32; + int64_t i64; + uint64_t u64; float f; double d; } jvalue; @@ -27,7 +30,9 @@ get_int16(const char *buf) static inline uint16_t get_uint16(const char *buf) { - return get_int16(buf); + uint16_t ret; + bh_memcpy_s(&ret, sizeof(uint16_t), buf, sizeof(uint16_t)); + return ret; } static inline int32_t @@ -41,7 +46,9 @@ get_int32(const char *buf) static inline uint32_t get_uint32(const char *buf) { - return get_int32(buf); + uint32_t ret; + bh_memcpy_s(&ret, sizeof(uint32_t), buf, sizeof(uint32_t)); + return ret; } static inline int64_t @@ -55,7 +62,9 @@ get_int64(const char *buf) static inline uint64_t get_uint64(const char *buf) { - return get_int64(buf); + uint64_t ret; + bh_memcpy_s(&ret, sizeof(uint64_t), buf, sizeof(uint64_t)); + return ret; } static inline void @@ -145,8 +154,8 @@ attr_container_get_attr_next(const char *curr_attr) p += sizeof(uint16_t) + get_uint16(p); type = *p++; - /* Short type to Boolean type */ - if (type >= ATTR_TYPE_SHORT && type <= ATTR_TYPE_BOOLEAN) { + /* Byte type to Boolean type */ + if (type >= ATTR_TYPE_BYTE && type <= ATTR_TYPE_BOOLEAN) { p += 1 << (type & 3); return p; } @@ -342,7 +351,7 @@ attr_container_set_attr(attr_container_t **p_attr_cont, const char *key, /* key len + key + '\0' + type */ attr_len = sizeof(uint16_t) + strlen(key) + 1 + 1; - if (type >= ATTR_TYPE_SHORT && type <= ATTR_TYPE_BOOLEAN) + if (type >= ATTR_TYPE_BYTE && type <= ATTR_TYPE_BOOLEAN) attr_len += 1 << (type & 3); else if (type == ATTR_TYPE_STRING) attr_len += sizeof(uint16_t) + value_length; @@ -362,7 +371,7 @@ attr_container_set_attr(attr_container_t **p_attr_cont, const char *key, p += str_len; *p++ = type; - if (type >= ATTR_TYPE_SHORT && type <= ATTR_TYPE_BOOLEAN) + if (type >= ATTR_TYPE_BYTE && type <= ATTR_TYPE_BOOLEAN) bh_memcpy_s(p, 1 << (type & 3), value, 1 << (type & 3)); else if (type == ATTR_TYPE_STRING) { set_uint16(p, value_length); @@ -460,6 +469,14 @@ attr_container_set_short(attr_container_t **p_attr_cont, const char *key, 2); } +bool +attr_container_set_int16(attr_container_t **p_attr_cont, const char *key, + int16_t value) +{ + return attr_container_set_attr(p_attr_cont, key, ATTR_TYPE_INT16, &value, + 2); +} + bool attr_container_set_int(attr_container_t **p_attr_cont, const char *key, int value) @@ -467,6 +484,22 @@ attr_container_set_int(attr_container_t **p_attr_cont, const char *key, return attr_container_set_attr(p_attr_cont, key, ATTR_TYPE_INT, &value, 4); } +bool +attr_container_set_int32(attr_container_t **p_attr_cont, const char *key, + int32_t value) +{ + return attr_container_set_attr(p_attr_cont, key, ATTR_TYPE_INT32, &value, + 4); +} + +bool +attr_container_set_uint32(attr_container_t **p_attr_cont, const char *key, + uint32_t value) +{ + return attr_container_set_attr(p_attr_cont, key, ATTR_TYPE_UINT32, &value, + 4); +} + bool attr_container_set_int64(attr_container_t **p_attr_cont, const char *key, int64_t value) @@ -475,6 +508,14 @@ attr_container_set_int64(attr_container_t **p_attr_cont, const char *key, 8); } +bool +attr_container_set_uint64(attr_container_t **p_attr_cont, const char *key, + uint64_t value) +{ + return attr_container_set_attr(p_attr_cont, key, ATTR_TYPE_UINT64, &value, + 8); +} + bool attr_container_set_byte(attr_container_t **p_attr_cont, const char *key, int8_t value) @@ -482,6 +523,21 @@ attr_container_set_byte(attr_container_t **p_attr_cont, const char *key, return attr_container_set_attr(p_attr_cont, key, ATTR_TYPE_BYTE, &value, 1); } +bool +attr_container_set_int8(attr_container_t **p_attr_cont, const char *key, + int8_t value) +{ + return attr_container_set_attr(p_attr_cont, key, ATTR_TYPE_INT8, &value, 1); +} + +bool +attr_container_set_uint8(attr_container_t **p_attr_cont, const char *key, + uint8_t value) +{ + return attr_container_set_attr(p_attr_cont, key, ATTR_TYPE_UINT8, &value, + 1); +} + bool attr_container_set_uint16(attr_container_t **p_attr_cont, const char *key, uint16_t value) @@ -552,7 +608,7 @@ attr_container_get_attr(const attr_container_t *attr_cont, const char *key) if (!(attr_addr = attr_container_find_attr(attr_cont, key))) { attr_container_printf("Get attribute failed: lookup key failed.\r\n"); - return false; + return NULL; } /* key len + key + '\0' */ @@ -566,14 +622,17 @@ attr_container_get_attr(const attr_container_t *attr_cont, const char *key) uint8_t type; \ if (!addr) \ return 0; \ - val.j = 0; \ + val.i64 = 0; \ type = *(uint8_t *)addr++; \ switch (type) { \ - case ATTR_TYPE_SHORT: \ - case ATTR_TYPE_INT: \ + case ATTR_TYPE_BYTE: /* = ATTR_TYPE_INT8 */ \ + case ATTR_TYPE_SHORT: /* = ATTR_TYPE_INT16 */ \ + case ATTR_TYPE_INT: /* = ATTR_TYPE_INT32 */ \ case ATTR_TYPE_INT64: \ - case ATTR_TYPE_BYTE: \ + case ATTR_TYPE_UINT8: \ case ATTR_TYPE_UINT16: \ + case ATTR_TYPE_UINT32: \ + case ATTR_TYPE_UINT64: \ case ATTR_TYPE_FLOAT: \ case ATTR_TYPE_DOUBLE: \ case ATTR_TYPE_BOOLEAN: \ @@ -608,31 +667,67 @@ attr_container_get_attr(const attr_container_t *attr_cont, const char *key) short attr_container_get_as_short(const attr_container_t *attr_cont, const char *key) { - TEMPLATE_ATTR_BUF_TO_VALUE(attr_cont, key, s); + TEMPLATE_ATTR_BUF_TO_VALUE(attr_cont, key, i16); +} + +int16_t +attr_container_get_as_int16(const attr_container_t *attr_cont, const char *key) +{ + return (int16_t)attr_container_get_as_short(attr_cont, key); } int attr_container_get_as_int(const attr_container_t *attr_cont, const char *key) { - TEMPLATE_ATTR_BUF_TO_VALUE(attr_cont, key, i); + TEMPLATE_ATTR_BUF_TO_VALUE(attr_cont, key, i32); +} + +int32_t +attr_container_get_as_int32(const attr_container_t *attr_cont, const char *key) +{ + return (int32_t)attr_container_get_as_int(attr_cont, key); +} + +uint32_t +attr_container_get_as_uint32(const attr_container_t *attr_cont, const char *key) +{ + return (uint32_t)attr_container_get_as_int(attr_cont, key); } int64_t attr_container_get_as_int64(const attr_container_t *attr_cont, const char *key) { - TEMPLATE_ATTR_BUF_TO_VALUE(attr_cont, key, j); + TEMPLATE_ATTR_BUF_TO_VALUE(attr_cont, key, i64); +} + +uint64_t +attr_container_get_as_uint64(const attr_container_t *attr_cont, const char *key) +{ + return (uint64_t)attr_container_get_as_int64(attr_cont, key); } int8_t attr_container_get_as_byte(const attr_container_t *attr_cont, const char *key) { - TEMPLATE_ATTR_BUF_TO_VALUE(attr_cont, key, b); + TEMPLATE_ATTR_BUF_TO_VALUE(attr_cont, key, i8); +} + +int8_t +attr_container_get_as_int8(const attr_container_t *attr_cont, const char *key) +{ + return attr_container_get_as_byte(attr_cont, key); +} + +uint8_t +attr_container_get_as_uint8(const attr_container_t *attr_cont, const char *key) +{ + return (uint8_t)attr_container_get_as_byte(attr_cont, key); } uint16_t attr_container_get_as_uint16(const attr_container_t *attr_cont, const char *key) { - TEMPLATE_ATTR_BUF_TO_VALUE(attr_cont, key, s); + return (uint16_t)attr_container_get_as_short(attr_cont, key); } float @@ -671,11 +766,14 @@ attr_container_get_as_bytearray(const attr_container_t *attr_cont, type = *(uint8_t *)addr++; switch (type) { - case ATTR_TYPE_SHORT: - case ATTR_TYPE_INT: + case ATTR_TYPE_BYTE: /* = ATTR_TYPE_INT8 */ + case ATTR_TYPE_SHORT: /* = ATTR_TYPE_INT16 */ + case ATTR_TYPE_INT: /* = ATTR_TYPE_INT32 */ case ATTR_TYPE_INT64: - case ATTR_TYPE_BYTE: + case ATTR_TYPE_UINT8: case ATTR_TYPE_UINT16: + case ATTR_TYPE_UINT32: + case ATTR_TYPE_UINT64: case ATTR_TYPE_FLOAT: case ATTR_TYPE_DOUBLE: case ATTR_TYPE_BOOLEAN: @@ -807,34 +905,52 @@ attr_container_dump(const attr_container_t *attr_cont) attr_container_printf(" key: %s", key); switch (type) { - case ATTR_TYPE_SHORT: - bh_memcpy_s(&value.s, sizeof(int16_t), p, sizeof(int16_t)); + case ATTR_TYPE_BYTE: /* = ATTR_TYPE_INT8 */ + bh_memcpy_s(&value.i8, 1, p, 1); + attr_container_printf(", type: byte, value: 0x%x\n", + value.i8 & 0xFF); + p++; + break; + case ATTR_TYPE_SHORT: /* = ATTR_TYPE_INT16 */ + bh_memcpy_s(&value.i16, sizeof(int16_t), p, sizeof(int16_t)); attr_container_printf(", type: short, value: 0x%x\n", - value.s & 0xFFFF); + value.i16 & 0xFFFF); p += 2; break; - case ATTR_TYPE_INT: - bh_memcpy_s(&value.i, sizeof(int32_t), p, sizeof(int32_t)); - attr_container_printf(", type: int, value: 0x%x\n", value.i); + case ATTR_TYPE_INT: /* = ATTR_TYPE_INT32 */ + bh_memcpy_s(&value.i32, sizeof(int32_t), p, sizeof(int32_t)); + attr_container_printf(", type: int, value: 0x%x\n", value.i32); p += 4; break; case ATTR_TYPE_INT64: - bh_memcpy_s(&value.j, sizeof(uint64_t), p, sizeof(uint64_t)); + bh_memcpy_s(&value.i64, sizeof(int64_t), p, sizeof(int64_t)); attr_container_printf(", type: int64, value: 0x%llx\n", - (long long unsigned int)(value.j)); + (long long unsigned int)(value.i64)); p += 8; break; - case ATTR_TYPE_BYTE: - bh_memcpy_s(&value.b, 1, p, 1); - attr_container_printf(", type: byte, value: 0x%x\n", - value.b & 0xFF); + case ATTR_TYPE_UINT8: + bh_memcpy_s(&value.u8, 1, p, 1); + attr_container_printf(", type: uint8, value: 0x%x\n", value.u8); p++; break; case ATTR_TYPE_UINT16: - bh_memcpy_s(&value.c, sizeof(uint16_t), p, sizeof(uint16_t)); - attr_container_printf(", type: uint16, value: 0x%x\n", value.c); + bh_memcpy_s(&value.u16, sizeof(uint16_t), p, sizeof(uint16_t)); + attr_container_printf(", type: uint16, value: 0x%x\n", + value.u16); p += 2; break; + case ATTR_TYPE_UINT32: + bh_memcpy_s(&value.u32, sizeof(uint32_t), p, sizeof(uint32_t)); + attr_container_printf(", type: uint32, value: 0x%x\n", + value.u32); + p += 4; + break; + case ATTR_TYPE_UINT64: + bh_memcpy_s(&value.u64, sizeof(uint64_t), p, sizeof(uint64_t)); + attr_container_printf(", type: int64, value: 0x%llx\n", + (long long unsigned int)(value.u64)); + p += 8; + break; case ATTR_TYPE_FLOAT: bh_memcpy_s(&value.f, sizeof(float), p, sizeof(float)); attr_container_printf(", type: float, value: %f\n", value.f); diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/app-native-shared/bi-inc/attr_container.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/app-native-shared/bi-inc/attr_container.h similarity index 67% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/app-native-shared/bi-inc/attr_container.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/app-native-shared/bi-inc/attr_container.h index 3b7be806262..f5d8759b8e2 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/app-native-shared/bi-inc/attr_container.h +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/app-native-shared/bi-inc/attr_container.h @@ -20,13 +20,27 @@ extern "C" { /* Attribute type */ enum { - ATTR_TYPE_BEGIN = 1, - ATTR_TYPE_SHORT = ATTR_TYPE_BEGIN, + ATTR_TYPE_BEGIN = 0, + ATTR_TYPE_BYTE = ATTR_TYPE_BEGIN, + ATTR_TYPE_INT8 = ATTR_TYPE_BYTE, + ATTR_TYPE_SHORT, + ATTR_TYPE_INT16 = ATTR_TYPE_SHORT, ATTR_TYPE_INT, + ATTR_TYPE_INT32 = ATTR_TYPE_INT, ATTR_TYPE_INT64, - ATTR_TYPE_BYTE, + ATTR_TYPE_UINT8, ATTR_TYPE_UINT16, - ATTR_TYPE_FLOAT, + ATTR_TYPE_UINT32, + ATTR_TYPE_UINT64, + /** + * Why ATTR_TYPE_FLOAT = 10? + * We determine the number of bytes that should be copied through 1<<(type & + * 3). ATTR_TYPE_BYTE = 0, so the number of bytes is 1 << 0 = 1. + * ATTR_TYPE_UINT64 = 7, so the number of bytes is 1 << 3 = 8. + * Since the float type takes up 4 bytes, ATTR_TYPE_FLOAT should be 10. + * Calculation: (1 << (10&3)) = (1 << 2) = 4 + */ + ATTR_TYPE_FLOAT = 10, ATTR_TYPE_DOUBLE, ATTR_TYPE_BOOLEAN, ATTR_TYPE_STRING, @@ -89,6 +103,20 @@ bool attr_container_set_short(attr_container_t **p_attr_cont, const char *key, short value); +/** + * Set int16 attribute in attribute container + * + * @param p_attr_cont pointer to attribute container to set attribute, and + * return the new attribute container if it is re-created + * @param key the attribute key + * @param value the attribute value + * + * @return true if success, false otherwise + */ +bool +attr_container_set_int16(attr_container_t **p_attr_cont, const char *key, + int16_t value); + /** * Set int attribute in attribute container * @@ -103,6 +131,34 @@ bool attr_container_set_int(attr_container_t **p_attr_cont, const char *key, int value); +/** + * Set int32 attribute in attribute container + * + * @param p_attr_cont pointer to attribute container to set attribute, and + * return the new attribute container if it is re-created + * @param key the attribute key + * @param value the attribute value + * + * @return true if success, false otherwise + */ +bool +attr_container_set_int32(attr_container_t **p_attr_cont, const char *key, + int32_t value); + +/** + * Set uint32 attribute in attribute container + * + * @param p_attr_cont pointer to attribute container to set attribute, and + * return the new attribute container if it is re-created + * @param key the attribute key + * @param value the attribute value + * + * @return true if success, false otherwise + */ +bool +attr_container_set_uint32(attr_container_t **p_attr_cont, const char *key, + uint32_t value); + /** * Set int64 attribute in attribute container * @@ -117,6 +173,20 @@ bool attr_container_set_int64(attr_container_t **p_attr_cont, const char *key, int64_t value); +/** + * Set uint64 attribute in attribute container + * + * @param p_attr_cont pointer to attribute container to set attribute, and + * return the new attribute container if it is re-created + * @param key the attribute key + * @param value the attribute value + * + * @return true if success, false otherwise + */ +bool +attr_container_set_uint64(attr_container_t **p_attr_cont, const char *key, + uint64_t value); + /** * Set byte attribute in attribute container * @@ -131,6 +201,34 @@ bool attr_container_set_byte(attr_container_t **p_attr_cont, const char *key, int8_t value); +/** + * Set int8 attribute in attribute container + * + * @param p_attr_cont pointer to attribute container to set attribute, and + * return the new attribute container if it is re-created + * @param key the attribute key + * @param value the attribute value + * + * @return true if success, false otherwise + */ +bool +attr_container_set_int8(attr_container_t **p_attr_cont, const char *key, + int8_t value); + +/** + * Set uint8 attribute in attribute container + * + * @param p_attr_cont pointer to attribute container to set attribute, and + * return the new attribute container if it is re-created + * @param key the attribute key + * @param value the attribute value + * + * @return true if success, false otherwise + */ +bool +attr_container_set_uint8(attr_container_t **p_attr_cont, const char *key, + uint8_t value); + /** * Set uint16 attribute in attribute container * @@ -259,6 +357,18 @@ attr_container_contain_key(const attr_container_t *attr_cont, const char *key); short attr_container_get_as_short(const attr_container_t *attr_cont, const char *key); +/** + * Get attribute from attribute container and return it as int16 value, + * return 0 if attribute isn't found in message. + * + * @param attr_cont the attribute container + * @param key the attribute key + * + * @return the short value of the attribute, 0 if key isn't found + */ +int16_t +attr_container_get_as_int16(const attr_container_t *attr_cont, const char *key); + /** * Get attribute from attribute container and return it as int value, * return 0 if attribute isn't found in message. @@ -271,6 +381,31 @@ attr_container_get_as_short(const attr_container_t *attr_cont, const char *key); int attr_container_get_as_int(const attr_container_t *attr_cont, const char *key); +/** + * Get attribute from attribute container and return it as int32 value, + * return 0 if attribute isn't found in message. + * + * @param attr_cont the attribute container + * @param key the attribute key + * + * @return the int value of the attribute, 0 if key isn't found + */ +int32_t +attr_container_get_as_int32(const attr_container_t *attr_cont, const char *key); + +/** + * Get attribute from attribute container and return it as uint32 value, + * return 0 if attribute isn't found in message. + * + * @param attr_cont the attribute container + * @param key the attribute key + * + * @return the unsigned int value of the attribute, 0 if key isn't found + */ +uint32_t +attr_container_get_as_uint32(const attr_container_t *attr_cont, + const char *key); + /** * Get attribute from attribute container and return it as int64 value, * return 0 if attribute isn't found in attribute container. @@ -283,6 +418,19 @@ attr_container_get_as_int(const attr_container_t *attr_cont, const char *key); int64_t attr_container_get_as_int64(const attr_container_t *attr_cont, const char *key); +/** + * Get attribute from attribute container and return it as uint64 value, + * return 0 if attribute isn't found in attribute container. + * + * @param attr_cont the attribute container + * @param key the attribute key + * + * @return the unsigned long value of the attribute, 0 if key isn't found + */ +uint64_t +attr_container_get_as_uint64(const attr_container_t *attr_cont, + const char *key); + /** * Get attribute from attribute container and return it as byte value, * return 0 if attribute isn't found in attribute container. @@ -295,6 +443,30 @@ attr_container_get_as_int64(const attr_container_t *attr_cont, const char *key); int8_t attr_container_get_as_byte(const attr_container_t *attr_cont, const char *key); +/** + * Get attribute from attribute container and return it as int8 value, + * return 0 if attribute isn't found in attribute container. + * + * @param attr_cont the attribute container + * @param key the attribute key + * + * @return the byte value of the attribute, 0 if key isn't found + */ +int8_t +attr_container_get_as_int8(const attr_container_t *attr_cont, const char *key); + +/** + * Get attribute from attribute container and return it as uint8 value, + * return 0 if attribute isn't found in attribute container. + * + * @param attr_cont the attribute container + * @param key the attribute key + * + * @return the uint8 value of the attribute, 0 if key isn't found + */ +uint8_t +attr_container_get_as_uint8(const attr_container_t *attr_cont, const char *key); + /** * Get attribute from attribute container and return it as uint16 value, * return 0 if attribute isn't found in attribute container. diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/app-native-shared/bi-inc/shared_utils.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/app-native-shared/bi-inc/shared_utils.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/app-native-shared/bi-inc/shared_utils.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/app-native-shared/bi-inc/shared_utils.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/app-native-shared/bi-inc/wgl_shared_utils.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/app-native-shared/bi-inc/wgl_shared_utils.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/app-native-shared/bi-inc/wgl_shared_utils.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/app-native-shared/bi-inc/wgl_shared_utils.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/app-native-shared/native_interface.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/app-native-shared/native_interface.cmake similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/app-native-shared/native_interface.cmake rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/app-native-shared/native_interface.cmake diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/app-native-shared/native_interface.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/app-native-shared/native_interface.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/app-native-shared/native_interface.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/app-native-shared/native_interface.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/app-native-shared/restful_utils.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/app-native-shared/restful_utils.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/app-native-shared/restful_utils.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/app-native-shared/restful_utils.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/app_ext_lib_export.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/app_ext_lib_export.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/app_ext_lib_export.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/app_ext_lib_export.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/app_framework.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/app_framework.cmake similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/app_framework.cmake rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/app_framework.cmake diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/base/app/bh_platform.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/base/app/bh_platform.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/base/app/bh_platform.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/base/app/bh_platform.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/base/app/bh_platform.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/base/app/bh_platform.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/base/app/bh_platform.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/base/app/bh_platform.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/base/app/req_resp_api.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/base/app/req_resp_api.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/base/app/req_resp_api.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/base/app/req_resp_api.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/base/app/request.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/base/app/request.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/base/app/request.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/base/app/request.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/base/app/timer.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/base/app/timer.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/base/app/timer.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/base/app/timer.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/base/app/timer_api.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/base/app/timer_api.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/base/app/timer_api.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/base/app/timer_api.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/base/app/wa-inc/request.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/base/app/wa-inc/request.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/base/app/wa-inc/request.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/base/app/wa-inc/request.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/base/app/wa-inc/timer_wasm_app.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/base/app/wa-inc/timer_wasm_app.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/base/app/wa-inc/timer_wasm_app.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/base/app/wa-inc/timer_wasm_app.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/base/app/wasm_app.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/base/app/wasm_app.cmake similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/base/app/wasm_app.cmake rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/base/app/wasm_app.cmake diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/base/app/wasm_app.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/base/app/wasm_app.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/base/app/wasm_app.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/base/app/wasm_app.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/base/native/base_lib.inl b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/base/native/base_lib.inl similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/base/native/base_lib.inl rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/base/native/base_lib.inl diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/base/native/base_lib_export.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/base/native/base_lib_export.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/base/native/base_lib_export.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/base/native/base_lib_export.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/base/native/req_resp_native_api.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/base/native/req_resp_native_api.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/base/native/req_resp_native_api.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/base/native/req_resp_native_api.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/base/native/request_response.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/base/native/request_response.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/base/native/request_response.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/base/native/request_response.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/base/native/runtime_lib.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/base/native/runtime_lib.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/base/native/runtime_lib.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/base/native/runtime_lib.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/base/native/timer_native_api.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/base/native/timer_native_api.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/base/native/timer_native_api.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/base/native/timer_native_api.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/base/native/timer_wrapper.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/base/native/timer_wrapper.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/base/native/timer_wrapper.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/base/native/timer_wrapper.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/base/native/wasm_lib.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/base/native/wasm_lib.cmake similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/base/native/wasm_lib.cmake rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/base/native/wasm_lib.cmake diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/connection/app/connection.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/connection/app/connection.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/connection/app/connection.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/connection/app/connection.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/connection/app/connection_api.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/connection/app/connection_api.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/connection/app/connection_api.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/connection/app/connection_api.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/connection/app/wa-inc/connection.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/connection/app/wa-inc/connection.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/connection/app/wa-inc/connection.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/connection/app/wa-inc/connection.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/connection/app/wasm_app.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/connection/app/wasm_app.cmake similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/connection/app/wasm_app.cmake rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/connection/app/wasm_app.cmake diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/connection/native/connection.inl b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/connection/native/connection.inl similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/connection/native/connection.inl rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/connection/native/connection.inl diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/connection/native/connection_lib.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/connection/native/connection_lib.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/connection/native/connection_lib.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/connection/native/connection_lib.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/connection/native/connection_native_api.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/connection/native/connection_native_api.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/connection/native/connection_native_api.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/connection/native/connection_native_api.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/connection/native/connection_wrapper.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/connection/native/connection_wrapper.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/connection/native/connection_wrapper.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/connection/native/connection_wrapper.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/connection/native/linux/conn_tcp.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/connection/native/linux/conn_tcp.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/connection/native/linux/conn_tcp.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/connection/native/linux/conn_tcp.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/connection/native/linux/conn_tcp.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/connection/native/linux/conn_tcp.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/connection/native/linux/conn_tcp.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/connection/native/linux/conn_tcp.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/connection/native/linux/conn_uart.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/connection/native/linux/conn_uart.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/connection/native/linux/conn_uart.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/connection/native/linux/conn_uart.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/connection/native/linux/conn_uart.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/connection/native/linux/conn_uart.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/connection/native/linux/conn_uart.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/connection/native/linux/conn_uart.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/connection/native/linux/conn_udp.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/connection/native/linux/conn_udp.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/connection/native/linux/conn_udp.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/connection/native/linux/conn_udp.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/connection/native/linux/conn_udp.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/connection/native/linux/conn_udp.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/connection/native/linux/conn_udp.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/connection/native/linux/conn_udp.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/connection/native/linux/connection_mgr.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/connection/native/linux/connection_mgr.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/connection/native/linux/connection_mgr.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/connection/native/linux/connection_mgr.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/connection/native/linux/connection_mgr.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/connection/native/linux/connection_mgr.cmake similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/connection/native/linux/connection_mgr.cmake rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/connection/native/linux/connection_mgr.cmake diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/connection/native/wasm_lib.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/connection/native/wasm_lib.cmake similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/connection/native/wasm_lib.cmake rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/connection/native/wasm_lib.cmake diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/connection/native/zephyr/connection_lib_impl.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/connection/native/zephyr/connection_lib_impl.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/connection/native/zephyr/connection_lib_impl.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/connection/native/zephyr/connection_lib_impl.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/connection/native/zephyr/connection_mgr.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/connection/native/zephyr/connection_mgr.cmake similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/connection/native/zephyr/connection_mgr.cmake rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/connection/native/zephyr/connection_mgr.cmake diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/sensor/app/sensor.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/sensor/app/sensor.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/sensor/app/sensor.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/sensor/app/sensor.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/sensor/app/sensor_api.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/sensor/app/sensor_api.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/sensor/app/sensor_api.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/sensor/app/sensor_api.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/sensor/app/wa-inc/sensor.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/sensor/app/wa-inc/sensor.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/sensor/app/wa-inc/sensor.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/sensor/app/wa-inc/sensor.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/sensor/app/wasm_app.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/sensor/app/wasm_app.cmake similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/sensor/app/wasm_app.cmake rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/sensor/app/wasm_app.cmake diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/sensor/native/runtime_sensor.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/sensor/native/runtime_sensor.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/sensor/native/runtime_sensor.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/sensor/native/runtime_sensor.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/sensor/native/runtime_sensor.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/sensor/native/runtime_sensor.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/sensor/native/runtime_sensor.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/sensor/native/runtime_sensor.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/sensor/native/runtime_sensor.inl b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/sensor/native/runtime_sensor.inl similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/sensor/native/runtime_sensor.inl rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/sensor/native/runtime_sensor.inl diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/sensor/native/sensor_mgr_ref.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/sensor/native/sensor_mgr_ref.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/sensor/native/sensor_mgr_ref.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/sensor/native/sensor_mgr_ref.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/sensor/native/sensor_native_api.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/sensor/native/sensor_native_api.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/sensor/native/sensor_native_api.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/sensor/native/sensor_native_api.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/sensor/native/wasm_lib.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/sensor/native/wasm_lib.cmake similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/sensor/native/wasm_lib.cmake rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/sensor/native/wasm_lib.cmake diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/template/app/wa-inc/app_xxx.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/template/app/wa-inc/app_xxx.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/template/app/wa-inc/app_xxx.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/template/app/wa-inc/app_xxx.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/template/app/wasm_app.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/template/app/wasm_app.cmake similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/template/app/wasm_app.cmake rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/template/app/wasm_app.cmake diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/template/native/app_xxx.inl b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/template/native/app_xxx.inl similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/template/native/app_xxx.inl rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/template/native/app_xxx.inl diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/template/native/wasm_lib.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/template/native/wasm_lib.cmake similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-framework/template/native/wasm_lib.cmake rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-framework/template/native/wasm_lib.cmake diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-mgr/README.md b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-mgr/README.md new file mode 100644 index 00000000000..31c705e1fb5 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-mgr/README.md @@ -0,0 +1,8 @@ +# Remote application management + +The WAMR application manager supports [remote application management](../core/app-mgr) from the host environment or the cloud through any physical communications such as TCP, UPD, UART, BLE, etc. Its modular design makes it able to support application management for different managed runtimes. + +The tool [host_tool](../test-tools/host-tool) communicates to the WAMR app manager for installing/uninstalling the WASM applications on companion chip from the host system. And the [IoT App Store Demo](../test-tools/IoT-APP-Store-Demo/) shows the conception of remotely managing the device applications from the cloud. + + + diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-mgr/app-manager/app_manager.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-mgr/app-manager/app_manager.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-mgr/app-manager/app_manager.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-mgr/app-manager/app_manager.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-mgr/app-manager/app_manager.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-mgr/app-manager/app_manager.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-mgr/app-manager/app_manager.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-mgr/app-manager/app_manager.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-mgr/app-manager/app_manager_host.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-mgr/app-manager/app_manager_host.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-mgr/app-manager/app_manager_host.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-mgr/app-manager/app_manager_host.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-mgr/app-manager/app_manager_host.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-mgr/app-manager/app_manager_host.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-mgr/app-manager/app_manager_host.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-mgr/app-manager/app_manager_host.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-mgr/app-manager/app_mgr.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-mgr/app-manager/app_mgr.cmake similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-mgr/app-manager/app_mgr.cmake rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-mgr/app-manager/app_mgr.cmake diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-mgr/app-manager/ble_msg.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-mgr/app-manager/ble_msg.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-mgr/app-manager/ble_msg.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-mgr/app-manager/ble_msg.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-mgr/app-manager/coding_rule.txt b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-mgr/app-manager/coding_rule.txt similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-mgr/app-manager/coding_rule.txt rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-mgr/app-manager/coding_rule.txt diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-mgr/app-manager/event.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-mgr/app-manager/event.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-mgr/app-manager/event.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-mgr/app-manager/event.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-mgr/app-manager/event.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-mgr/app-manager/event.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-mgr/app-manager/event.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-mgr/app-manager/event.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-mgr/app-manager/message.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-mgr/app-manager/message.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-mgr/app-manager/message.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-mgr/app-manager/message.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-mgr/app-manager/module_config.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-mgr/app-manager/module_config.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-mgr/app-manager/module_config.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-mgr/app-manager/module_config.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-mgr/app-manager/module_jeff.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-mgr/app-manager/module_jeff.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-mgr/app-manager/module_jeff.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-mgr/app-manager/module_jeff.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-mgr/app-manager/module_jeff.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-mgr/app-manager/module_jeff.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-mgr/app-manager/module_jeff.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-mgr/app-manager/module_jeff.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-mgr/app-manager/module_utils.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-mgr/app-manager/module_utils.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-mgr/app-manager/module_utils.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-mgr/app-manager/module_utils.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-mgr/app-manager/module_wasm_app.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-mgr/app-manager/module_wasm_app.c similarity index 99% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-mgr/app-manager/module_wasm_app.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-mgr/app-manager/module_wasm_app.c index 7b826d6d9e5..2005ad8e846 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-mgr/app-manager/module_wasm_app.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-mgr/app-manager/module_wasm_app.c @@ -993,6 +993,14 @@ wasm_app_module_uninstall(request_t *msg) app_manager_printf("Uninstall WASM app successful!\n"); +#ifdef COLLECT_CODE_COVERAGE + /* Exit app manager so as to collect code coverage data */ + if (!strcmp(m_name, "__exit_app_manager__")) { + app_manager_printf("Exit app manager\n"); + bh_queue_exit_loop_run(get_app_manager_queue()); + } +#endif + #if VALGRIND_CHECK != 0 bh_queue_exit_loop_run(get_app_manager_queue()); #endif diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-mgr/app-manager/module_wasm_app.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-mgr/app-manager/module_wasm_app.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-mgr/app-manager/module_wasm_app.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-mgr/app-manager/module_wasm_app.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-mgr/app-manager/module_wasm_lib.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-mgr/app-manager/module_wasm_lib.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-mgr/app-manager/module_wasm_lib.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-mgr/app-manager/module_wasm_lib.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-mgr/app-manager/module_wasm_lib.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-mgr/app-manager/module_wasm_lib.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-mgr/app-manager/module_wasm_lib.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-mgr/app-manager/module_wasm_lib.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-mgr/app-manager/platform/darwin/app_mgr_darwin.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-mgr/app-manager/platform/darwin/app_mgr_darwin.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-mgr/app-manager/platform/darwin/app_mgr_darwin.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-mgr/app-manager/platform/darwin/app_mgr_darwin.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-mgr/app-manager/platform/linux/app_mgr_linux.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-mgr/app-manager/platform/linux/app_mgr_linux.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-mgr/app-manager/platform/linux/app_mgr_linux.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-mgr/app-manager/platform/linux/app_mgr_linux.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-mgr/app-manager/platform/zephyr/app_mgr_zephyr.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-mgr/app-manager/platform/zephyr/app_mgr_zephyr.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-mgr/app-manager/platform/zephyr/app_mgr_zephyr.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-mgr/app-manager/platform/zephyr/app_mgr_zephyr.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-mgr/app-manager/resource_reg.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-mgr/app-manager/resource_reg.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-mgr/app-manager/resource_reg.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-mgr/app-manager/resource_reg.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-mgr/app-manager/watchdog.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-mgr/app-manager/watchdog.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-mgr/app-manager/watchdog.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-mgr/app-manager/watchdog.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-mgr/app-manager/watchdog.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-mgr/app-manager/watchdog.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-mgr/app-manager/watchdog.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-mgr/app-manager/watchdog.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-mgr/app-mgr-shared/app_manager_export.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-mgr/app-mgr-shared/app_manager_export.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-mgr/app-mgr-shared/app_manager_export.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-mgr/app-mgr-shared/app_manager_export.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-mgr/app-mgr-shared/app_mgr_shared.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-mgr/app-mgr-shared/app_mgr_shared.cmake similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-mgr/app-mgr-shared/app_mgr_shared.cmake rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-mgr/app-mgr-shared/app_mgr_shared.cmake diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-mgr/app-mgr-shared/host_link.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-mgr/app-mgr-shared/host_link.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-mgr/app-mgr-shared/host_link.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-mgr/app-mgr-shared/host_link.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/app-mgr/module.json b/lib/wasm-micro-runtime-WAMR-1.2.2/core/app-mgr/module.json similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/app-mgr/module.json rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/app-mgr/module.json diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/config.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/config.h similarity index 87% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/config.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/config.h index 024913b7cf3..feedb13fa62 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/config.h +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/config.h @@ -70,6 +70,10 @@ #define WASM_ENABLE_AOT 0 #endif +#ifndef WASM_ENABLE_WORD_ALIGN_READ +#define WASM_ENABLE_WORD_ALIGN_READ 0 +#endif + #define AOT_MAGIC_NUMBER 0x746f6100 #define AOT_CURRENT_VERSION 3 @@ -81,12 +85,26 @@ #define WASM_ENABLE_LAZY_JIT 0 #endif -#ifndef WASM_LAZY_JIT_COMPILE_THREAD_NUM -#define WASM_LAZY_JIT_COMPILE_THREAD_NUM 4 +#ifndef WASM_ORC_JIT_BACKEND_THREAD_NUM +/* The number of backend threads created by runtime */ +#define WASM_ORC_JIT_BACKEND_THREAD_NUM 4 +#endif + +#if WASM_ORC_JIT_BACKEND_THREAD_NUM < 1 +#error "WASM_ORC_JIT_BACKEND_THREAD_NUM must be greater than 0" +#endif + +#ifndef WASM_ORC_JIT_COMPILE_THREAD_NUM +/* The number of compilation threads created by LLVM JIT */ +#define WASM_ORC_JIT_COMPILE_THREAD_NUM 4 +#endif + +#if WASM_ORC_JIT_COMPILE_THREAD_NUM < 1 +#error "WASM_ORC_JIT_COMPILE_THREAD_NUM must be greater than 0" #endif #if (WASM_ENABLE_AOT == 0) && (WASM_ENABLE_JIT != 0) -/* LazyJIT or MCJIT can only be enabled when AOT is enabled */ +/* LLVM JIT can only be enabled when AOT is enabled */ #undef WASM_ENABLE_JIT #define WASM_ENABLE_JIT 0 @@ -110,14 +128,6 @@ #define WASM_ENABLE_WAMR_COMPILER 0 #endif -#if WASM_ENABLE_WAMR_COMPILER != 0 -#ifndef WASM_ENABLE_LLVM_LEGACY_PM -/* Whether to use LLVM legacy pass manager when building wamrc, - by default it is disabled and LLVM new pass manager is used */ -#define WASM_ENABLE_LLVM_LEGACY_PM 0 -#endif -#endif - #ifndef WASM_ENABLE_LIBC_BUILTIN #define WASM_ENABLE_LIBC_BUILTIN 0 #endif @@ -130,6 +140,10 @@ #define WASM_ENABLE_UVWASI 0 #endif +#ifndef WASM_ENABLE_WASI_NN +#define WASM_ENABLE_WASI_NN 0 +#endif + /* Default disable libc emcc */ #ifndef WASM_ENABLE_LIBC_EMCC #define WASM_ENABLE_LIBC_EMCC 0 @@ -147,6 +161,17 @@ #define WASM_ENABLE_LIB_PTHREAD_SEMAPHORE 0 #endif +#ifndef WASM_ENABLE_LIB_WASI_THREADS +#define WASM_ENABLE_LIB_WASI_THREADS 0 +#endif + +#ifndef WASM_ENABLE_HEAP_AUX_STACK_ALLOCATION +#define WASM_ENABLE_HEAP_AUX_STACK_ALLOCATION WASM_ENABLE_LIB_WASI_THREADS +#elif WASM_ENABLE_HEAP_AUX_STACK_ALLOCATION == 0 \ + && WASM_ENABLE_LIB_WASI_THREADS == 1 +#error "Heap aux stack allocation must be enabled for WASI threads" +#endif + #ifndef WASM_ENABLE_BASE_LIB #define WASM_ENABLE_BASE_LIB 0 #endif @@ -246,6 +271,12 @@ #define WASM_DISABLE_HW_BOUND_CHECK 0 #endif +/* Disable native stack access boundary check with hardware + * trap or not, enable it by default if it is supported */ +#ifndef WASM_DISABLE_STACK_HW_BOUND_CHECK +#define WASM_DISABLE_STACK_HW_BOUND_CHECK 0 +#endif + /* Disable SIMD unless it is manualy enabled somewhere */ #ifndef WASM_ENABLE_SIMD #define WASM_ENABLE_SIMD 0 @@ -292,13 +323,8 @@ /* Global heap pool size in bytes */ #ifndef WASM_GLOBAL_HEAP_SIZE -#if WASM_ENABLE_SPEC_TEST != 0 -/* Spec test requires more heap pool size */ -#define WASM_GLOBAL_HEAP_SIZE (300 * 1024 * 1024) -#else #define WASM_GLOBAL_HEAP_SIZE (10 * 1024 * 1024) #endif -#endif /* Max app number of all modules */ #define MAX_APP_INSTALLATIONS 3 @@ -411,4 +437,12 @@ #define WASM_ENABLE_SGX_IPFS 0 #endif +#ifndef WASM_MEM_ALLOC_WITH_USER_DATA +#define WASM_MEM_ALLOC_WITH_USER_DATA 0 +#endif + +#ifndef WASM_ENABLE_WASM_CACHE +#define WASM_ENABLE_WASM_CACHE 0 +#endif + #endif /* end of _CONFIG_H_ */ diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/README.md b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/README.md new file mode 100644 index 00000000000..65ab78a495c --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/README.md @@ -0,0 +1,14 @@ +# vmcore architecture +- [WAMR memory model overview](https://bytecodealliance.github.io/wamr.dev/blog/the-wamr-memory-model/) + +## Wasm function +- [Wasm function architecture](./doc/wasm_function.MD) + +## Exports +- [Wasm export architecture](./doc/wasm_exports.MD) + +## globals +- [Wasm globals architecture](./doc/wasm_globals.MD) + +## classic interpreter +- [classic interpreter](./doc/classic_interpreter.MD) \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/aot/SConscript b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/aot/SConscript similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/aot/SConscript rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/aot/SConscript diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/aot/aot_intrinsic.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/aot/aot_intrinsic.c similarity index 82% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/aot/aot_intrinsic.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/aot/aot_intrinsic.c index eed32748529..319eeda5cbc 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/aot/aot_intrinsic.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/aot/aot_intrinsic.c @@ -57,6 +57,10 @@ static const aot_intrinsic g_intrinsic_mapping[] = { { "i32_trunc_f32_s", "aot_intrinsic_f32_to_i32", AOT_INTRINSIC_FLAG_F32_TO_I32 }, { "i32_trunc_f64_u", "aot_intrinsic_f64_to_u32", AOT_INTRINSIC_FLAG_F64_TO_U32 }, { "i32_trunc_f64_s", "aot_intrinsic_f64_to_i32", AOT_INTRINSIC_FLAG_F64_TO_I32 }, + { "i64_trunc_f64_u", "aot_intrinsic_f64_to_u64", AOT_INTRINSIC_FLAG_F64_TO_U64 }, + { "i64_trunc_f32_s", "aot_intrinsic_f32_to_i64", AOT_INTRINSIC_FLAG_F32_TO_I64 }, + { "i64_trunc_f32_u", "aot_intrinsic_f32_to_u64", AOT_INTRINSIC_FLAG_F32_TO_U64 }, + { "i64_trunc_f64_s", "aot_intrinsic_f64_to_i64", AOT_INTRINSIC_FLAG_F64_TO_I64 }, { "f32_demote_f64", "aot_intrinsic_f64_to_f32", AOT_INTRINSIC_FLAG_F64_TO_F32 }, { "f64_promote_f32", "aot_intrinsic_f32_to_f64", AOT_INTRINSIC_FLAG_F32_TO_F64 }, { "f32_cmp", "aot_intrinsic_f32_cmp", AOT_INTRINSIC_FLAG_F32_CMP }, @@ -66,9 +70,15 @@ static const aot_intrinsic g_intrinsic_mapping[] = { { "f32.const", NULL, AOT_INTRINSIC_FLAG_F32_CONST }, { "f64.const", NULL, AOT_INTRINSIC_FLAG_F64_CONST }, { "i64.div_s", "aot_intrinsic_i64_div_s", AOT_INTRINSIC_FLAG_I64_DIV_S}, + { "i32.div_s", "aot_intrinsic_i32_div_s", AOT_INTRINSIC_FLAG_I32_DIV_S}, + { "i32.div_u", "aot_intrinsic_i32_div_u", AOT_INTRINSIC_FLAG_I32_DIV_U}, + { "i32.rem_s", "aot_intrinsic_i32_rem_s", AOT_INTRINSIC_FLAG_I32_REM_S}, + { "i32.rem_u", "aot_intrinsic_i32_rem_u", AOT_INTRINSIC_FLAG_I32_REM_U}, { "i64.div_u", "aot_intrinsic_i64_div_u", AOT_INTRINSIC_FLAG_I64_DIV_U}, { "i64.rem_s", "aot_intrinsic_i64_rem_s", AOT_INTRINSIC_FLAG_I64_REM_S}, { "i64.rem_u", "aot_intrinsic_i64_rem_u", AOT_INTRINSIC_FLAG_I64_REM_U}, + { "i64.or", "aot_intrinsic_i64_bit_or", AOT_INTRINSIC_FLAG_I64_BIT_OR}, + { "i64.and", "aot_intrinsic_i64_bit_and", AOT_INTRINSIC_FLAG_I64_BIT_AND}, }; /* clang-format on */ @@ -126,7 +136,7 @@ aot_intrinsic_fdiv_f64(float64 a, float64 b) float32 aot_intrinsic_fabs_f32(float32 a) { - return (float32)fabs(a); + return fabsf(a); } float64 @@ -138,7 +148,7 @@ aot_intrinsic_fabs_f64(float64 a) float32 aot_intrinsic_ceil_f32(float32 a) { - return (float32)ceilf(a); + return ceilf(a); } float64 @@ -150,7 +160,7 @@ aot_intrinsic_ceil_f64(float64 a) float32 aot_intrinsic_floor_f32(float32 a) { - return (float32)floorf(a); + return floorf(a); } float64 @@ -162,7 +172,7 @@ aot_intrinsic_floor_f64(float64 a) float32 aot_intrinsic_trunc_f32(float32 a) { - return (float32)trunc(a); + return truncf(a); } float64 @@ -174,7 +184,7 @@ aot_intrinsic_trunc_f64(float64 a) float32 aot_intrinsic_rint_f32(float32 a) { - return (float32)rint(a); + return rintf(a); } float64 @@ -186,7 +196,7 @@ aot_intrinsic_rint_f64(float64 a) float32 aot_intrinsic_sqrt_f32(float32 a) { - return (float32)sqrt(a); + return sqrtf(a); } float64 @@ -198,7 +208,7 @@ aot_intrinsic_sqrt_f64(float64 a) float32 aot_intrinsic_copysign_f32(float32 a, float32 b) { - return signbit(b) ? (float32)-fabs(a) : (float32)fabs(a); + return signbit(b) ? -fabsf(a) : fabsf(a); } float64 @@ -210,41 +220,45 @@ aot_intrinsic_copysign_f64(float64 a, float64 b) float32 aot_intrinsic_fmin_f32(float32 a, float32 b) { - if (isnan(a)) - return a; - else if (isnan(b)) - return b; + if (isnan(a) || isnan(b)) + return NAN; + else if (a == 0 && a == b) + return signbit(a) ? a : b; else - return (float32)fmin(a, b); + return a > b ? b : a; } float64 aot_intrinsic_fmin_f64(float64 a, float64 b) { - float64 c = fmin(a, b); - if (c == 0 && a == b) + if (isnan(a) || isnan(b)) + return NAN; + else if (a == 0 && a == b) return signbit(a) ? a : b; - return c; + else + return a > b ? b : a; } float32 aot_intrinsic_fmax_f32(float32 a, float32 b) { - if (isnan(a)) - return a; - else if (isnan(b)) - return b; + if (isnan(a) || isnan(b)) + return NAN; + else if (a == 0 && a == b) + return signbit(a) ? b : a; else - return (float32)fmax(a, b); + return a > b ? a : b; } float64 aot_intrinsic_fmax_f64(float64 a, float64 b) { - float64 c = fmax(a, b); - if (c == 0 && a == b) + if (isnan(a) || isnan(b)) + return NAN; + else if (a == 0 && a == b) return signbit(a) ? b : a; - return c; + else + return a > b ? a : b; } uint32 @@ -434,7 +448,7 @@ aot_intrinsic_f32_cmp(AOTFloatCond cond, float32 lhs, float32 rhs) { switch (cond) { case FLOAT_EQ: - return (float32)fabs(lhs - rhs) <= WA_FLT_EPSILON ? 1 : 0; + return lhs == rhs ? 1 : 0; case FLOAT_LT: return lhs < rhs ? 1 : 0; @@ -465,7 +479,7 @@ aot_intrinsic_f64_cmp(AOTFloatCond cond, float64 lhs, float64 rhs) { switch (cond) { case FLOAT_EQ: - return fabs(lhs - rhs) <= WA_DBL_EPSILON ? 1 : 0; + return lhs == rhs ? 1 : 0; case FLOAT_LT: return lhs < rhs ? 1 : 0; @@ -497,6 +511,30 @@ aot_intrinsic_i64_div_s(int64 l, int64 r) return l / r; } +int32 +aot_intrinsic_i32_div_s(int32 l, int32 r) +{ + return l / r; +} + +uint32 +aot_intrinsic_i32_div_u(uint32 l, uint32 r) +{ + return l / r; +} + +int32 +aot_intrinsic_i32_rem_s(int32 l, int32 r) +{ + return l % r; +} + +uint32 +aot_intrinsic_i32_rem_u(uint32 l, uint32 r) +{ + return l % r; +} + uint64 aot_intrinsic_i64_div_u(uint64 l, uint64 r) { @@ -515,6 +553,18 @@ aot_intrinsic_i64_rem_u(uint64 l, uint64 r) return l % r; } +uint64 +aot_intrinsic_i64_bit_or(uint64 l, uint64 r) +{ + return l | r; +} + +uint64 +aot_intrinsic_i64_bit_and(uint64 l, uint64 r) +{ + return l & r; +} + const char * aot_intrinsic_get_symbol(const char *llvm_intrinsic) { @@ -549,6 +599,17 @@ add_i64_common_intrinsics(AOTCompContext *comp_ctx) add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_I64_DIV_U); add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_I64_REM_S); add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_I64_REM_U); + add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_I64_BIT_OR); + add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_I64_BIT_AND); +} + +static void +add_i32_common_intrinsics(AOTCompContext *comp_ctx) +{ + add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_I32_DIV_S); + add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_I32_DIV_U); + add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_I32_REM_S); + add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_I32_REM_U); } static void @@ -561,6 +622,12 @@ add_f32_common_intrinsics(AOTCompContext *comp_ctx) add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F32_FDIV); add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F32_SQRT); add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F32_CMP); + add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F32_MIN); + add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F32_MAX); + add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F32_CEIL); + add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F32_FLOOR); + add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F32_TRUNC); + add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F32_RINT); } static void @@ -570,6 +637,12 @@ add_f64_common_intrinsics(AOTCompContext *comp_ctx) add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F64_FADD); add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F64_FSUB); add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F64_FMUL); + add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F64_MIN); + add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F64_MAX); + add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F64_CEIL); + add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F64_FLOOR); + add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F64_TRUNC); + add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F64_RINT); add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F64_FDIV); add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F64_SQRT); add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F64_CMP); @@ -638,6 +711,8 @@ aot_intrinsic_fill_capability_flags(AOTCompContext *comp_ctx) return; if (!strncmp(comp_ctx->target_arch, "thumb", 5)) { + add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_I32_CONST); + add_i32_common_intrinsics(comp_ctx); if (!strcmp(comp_ctx->target_cpu, "cortex-m7")) { } else if (!strcmp(comp_ctx->target_cpu, "cortex-m4")) { @@ -646,10 +721,12 @@ aot_intrinsic_fill_capability_flags(AOTCompContext *comp_ctx) else { add_f32_common_intrinsics(comp_ctx); add_f64_common_intrinsics(comp_ctx); + add_i64_common_intrinsics(comp_ctx); add_common_float_integer_convertion(comp_ctx); } } else if (!strncmp(comp_ctx->target_arch, "riscv", 5)) { + add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_I32_CONST); /* * Note: Use builtin intrinsics since hardware float operation * will cause rodata relocation @@ -657,9 +734,9 @@ aot_intrinsic_fill_capability_flags(AOTCompContext *comp_ctx) add_f32_common_intrinsics(comp_ctx); add_f64_common_intrinsics(comp_ctx); add_common_float_integer_convertion(comp_ctx); - } - else if (!strncmp(comp_ctx->target_arch, "riscv32", 7)) { - add_i64_common_intrinsics(comp_ctx); + if (!strncmp(comp_ctx->target_arch, "riscv32", 7)) { + add_i64_common_intrinsics(comp_ctx); + } } else if (!strncmp(comp_ctx->target_arch, "xtensa", 6)) { /* @@ -667,7 +744,9 @@ aot_intrinsic_fill_capability_flags(AOTCompContext *comp_ctx) * will cause rodata relocation */ add_f32_common_intrinsics(comp_ctx); + add_i32_common_intrinsics(comp_ctx); add_f64_common_intrinsics(comp_ctx); + add_i64_common_intrinsics(comp_ctx); add_common_float_integer_convertion(comp_ctx); add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F32_CONST); add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F64_CONST); diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/aot/aot_intrinsic.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/aot/aot_intrinsic.h similarity index 91% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/aot/aot_intrinsic.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/aot/aot_intrinsic.h index 92dccea09b5..2123058b95c 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/aot/aot_intrinsic.h +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/aot/aot_intrinsic.h @@ -7,7 +7,7 @@ #define _AOT_INTRINSIC_H #include "aot_runtime.h" -#if WASM_ENABLE_WAMR_COMPILER != 0 +#if WASM_ENABLE_WAMR_COMPILER != 0 || WASM_ENABLE_JIT != 0 #include "aot_llvm.h" #endif @@ -59,6 +59,10 @@ extern "C" { #define AOT_INTRINSIC_FLAG_F32_CMP AOT_INTRINSIC_FLAG(0, 25) #define AOT_INTRINSIC_FLAG_F32_CONST AOT_INTRINSIC_FLAG(0, 26) #define AOT_INTRINSIC_FLAG_I32_CONST AOT_INTRINSIC_FLAG(0, 27) +#define AOT_INTRINSIC_FLAG_I32_DIV_U AOT_INTRINSIC_FLAG(0, 28) +#define AOT_INTRINSIC_FLAG_I32_REM_S AOT_INTRINSIC_FLAG(0, 29) +#define AOT_INTRINSIC_FLAG_I32_REM_U AOT_INTRINSIC_FLAG(0, 30) +#define AOT_INTRINSIC_FLAG_I32_DIV_S AOT_INTRINSIC_FLAG(0, 31) #define AOT_INTRINSIC_FLAG_F64_FADD AOT_INTRINSIC_FLAG(1, 0) #define AOT_INTRINSIC_FLAG_F64_FSUB AOT_INTRINSIC_FLAG(1, 1) @@ -92,6 +96,8 @@ extern "C" { #define AOT_INTRINSIC_FLAG_I64_DIV_U AOT_INTRINSIC_FLAG(1, 29) #define AOT_INTRINSIC_FLAG_I64_REM_S AOT_INTRINSIC_FLAG(1, 30) #define AOT_INTRINSIC_FLAG_I64_REM_U AOT_INTRINSIC_FLAG(1, 31) +#define AOT_INTRINSIC_FLAG_I64_BIT_OR AOT_INTRINSIC_FLAG(1, 32) +#define AOT_INTRINSIC_FLAG_I64_BIT_AND AOT_INTRINSIC_FLAG(1, 33) /* clang-format on */ @@ -254,6 +260,18 @@ aot_intrinsic_f64_cmp(AOTFloatCond cond, float64 lhs, float64 rhs); int64 aot_intrinsic_i64_div_s(int64 l, int64 r); +int32 +aot_intrinsic_i32_div_s(int32 l, int32 r); + +uint32 +aot_intrinsic_i32_div_u(uint32 l, uint32 r); + +int32 +aot_intrinsic_i32_rem_s(int32 l, int32 r); + +uint32 +aot_intrinsic_i32_rem_u(uint32 l, uint32 r); + uint64 aot_intrinsic_i64_div_u(uint64 l, uint64 r); @@ -263,6 +281,12 @@ aot_intrinsic_i64_rem_s(int64 l, int64 r); uint64 aot_intrinsic_i64_rem_u(uint64 l, uint64 r); +uint64 +aot_intrinsic_i64_bit_or(uint64 l, uint64 r); + +uint64 +aot_intrinsic_i64_bit_and(uint64 l, uint64 r); + const char * aot_intrinsic_get_symbol(const char *llvm_intrinsic); diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/aot/aot_loader.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/aot/aot_loader.c similarity index 86% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/aot/aot_loader.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/aot/aot_loader.c index fca926abbd2..5345fb2d72e 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/aot/aot_loader.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/aot/aot_loader.c @@ -10,10 +10,6 @@ #include "../common/wasm_runtime_common.h" #include "../common/wasm_native.h" #include "../compilation/aot.h" -#if WASM_ENABLE_JIT != 0 -#include "../compilation/aot_llvm.h" -#include "../interpreter/wasm_loader.h" -#endif #if WASM_ENABLE_DEBUG_AOT != 0 #include "debug/elf_parser.h" @@ -127,6 +123,42 @@ GET_U64_FROM_ADDR(uint32 *addr) return u.val; } +#if (WASM_ENABLE_WORD_ALIGN_READ != 0) + +static inline uint8 +GET_U8_FROM_ADDR(const uint8 *p) +{ + uint8 res = 0; + bh_assert(p); + + const uint8 *p_aligned = align_ptr(p, 4); + p_aligned = (p_aligned > p) ? p_aligned - 4 : p_aligned; + + uint32 buf32 = *(const uint32 *)p_aligned; + const uint8 *pbuf = (const uint8 *)&buf32; + + res = *(uint8 *)(pbuf + (p - p_aligned)); + + return res; +} + +static inline uint16 +GET_U16_FROM_ADDR(const uint8 *p) +{ + uint16 res = 0; + bh_assert(p); + + const uint8 *p_aligned = align_ptr(p, 4); + p_aligned = (p_aligned > p) ? p_aligned - 4 : p_aligned; + + uint32 buf32 = *(const uint32 *)p_aligned; + const uint8 *pbuf = (const uint8 *)&buf32; + + res = *(uint16 *)(pbuf + (p - p_aligned)); + + return res; +} + #define TEMPLATE_READ(p, p_end, res, type) \ do { \ if (sizeof(type) != sizeof(uint64)) \ @@ -135,7 +167,11 @@ GET_U64_FROM_ADDR(uint32 *addr) /* align 4 bytes if type is uint64 */ \ p = (uint8 *)align_ptr(p, sizeof(uint32)); \ CHECK_BUF(p, p_end, sizeof(type)); \ - if (sizeof(type) != sizeof(uint64)) \ + if (sizeof(type) == sizeof(uint8)) \ + res = GET_U8_FROM_ADDR(p); \ + else if (sizeof(type) == sizeof(uint16)) \ + res = GET_U16_FROM_ADDR(p); \ + else if (sizeof(type) == sizeof(uint32)) \ res = *(type *)p; \ else \ res = (type)GET_U64_FROM_ADDR((uint32 *)p); \ @@ -144,10 +180,39 @@ GET_U64_FROM_ADDR(uint32 *addr) p += sizeof(type); \ } while (0) -#define read_uint8(p, p_end, res) TEMPLATE_READ(p, p_end, res, uint8) -#define read_uint16(p, p_end, res) TEMPLATE_READ(p, p_end, res, uint16) -#define read_uint32(p, p_end, res) TEMPLATE_READ(p, p_end, res, uint32) -#define read_uint64(p, p_end, res) TEMPLATE_READ(p, p_end, res, uint64) +#define read_byte_array(p, p_end, addr, len) \ + do { \ + CHECK_BUF(p, p_end, len); \ + bh_memcpy_wa(addr, len, p, len); \ + p += len; \ + } while (0) + +#define read_string(p, p_end, str) \ + do { \ + if (!(str = load_string((uint8 **)&p, p_end, module, \ + is_load_from_file_buf, true, error_buf, \ + error_buf_size))) \ + goto fail; \ + } while (0) + +#else /* else of (WASM_ENABLE_WORD_ALIGN_READ != 0) */ + +#define TEMPLATE_READ(p, p_end, res, type) \ + do { \ + if (sizeof(type) != sizeof(uint64)) \ + p = (uint8 *)align_ptr(p, sizeof(type)); \ + else \ + /* align 4 bytes if type is uint64 */ \ + p = (uint8 *)align_ptr(p, sizeof(uint32)); \ + CHECK_BUF(p, p_end, sizeof(type)); \ + if (sizeof(type) != sizeof(uint64)) \ + res = *(type *)p; \ + else \ + res = (type)GET_U64_FROM_ADDR((uint32 *)p); \ + if (!is_little_endian()) \ + exchange_##type((uint8 *)&res); \ + p += sizeof(type); \ + } while (0) #define read_byte_array(p, p_end, addr, len) \ do { \ @@ -164,6 +229,13 @@ GET_U64_FROM_ADDR(uint32 *addr) goto fail; \ } while (0) +#endif /* end of (WASM_ENABLE_WORD_ALIGN_READ != 0) */ + +#define read_uint8(p, p_end, res) TEMPLATE_READ(p, p_end, res, uint8) +#define read_uint16(p, p_end, res) TEMPLATE_READ(p, p_end, res, uint16) +#define read_uint32(p, p_end, res) TEMPLATE_READ(p, p_end, res, uint32) +#define read_uint64(p, p_end, res) TEMPLATE_READ(p, p_end, res, uint64) + /* Legal values for bin_type */ #define BIN_TYPE_ELF32L 0 /* 32-bit little endian */ #define BIN_TYPE_ELF32B 1 /* 32-bit big endian */ @@ -215,6 +287,9 @@ loader_malloc(uint64 size, char *error_buf, uint32 error_buf_size) static char * const_str_set_insert(const uint8 *str, int32 len, AOTModule *module, +#if (WASM_ENABLE_WORD_ALIGN_READ != 0) + bool is_vram_word_align, +#endif char *error_buf, uint32 error_buf_size) { HashMap *set = module->const_str_set; @@ -234,8 +309,15 @@ const_str_set_insert(const uint8 *str, int32 len, AOTModule *module, if (!(c_str = loader_malloc((uint32)len + 1, error_buf, error_buf_size))) { return NULL; } - - bh_memcpy_s(c_str, (uint32)(len + 1), str, (uint32)len); +#if (WASM_ENABLE_WORD_ALIGN_READ != 0) + if (is_vram_word_align) { + bh_memcpy_wa(c_str, (uint32)(len + 1), str, (uint32)len); + } + else +#endif + { + bh_memcpy_s(c_str, (uint32)(len + 1), str, (uint32)len); + } c_str[len] = '\0'; if ((value = bh_hash_map_find(set, c_str))) { @@ -255,7 +337,11 @@ const_str_set_insert(const uint8 *str, int32 len, AOTModule *module, static char * load_string(uint8 **p_buf, const uint8 *buf_end, AOTModule *module, - bool is_load_from_file_buf, char *error_buf, uint32 error_buf_size) + bool is_load_from_file_buf, +#if (WASM_ENABLE_WORD_ALIGN_READ != 0) + bool is_vram_word_align, +#endif + char *error_buf, uint32 error_buf_size) { uint8 *p = *p_buf; const uint8 *p_end = buf_end; @@ -268,6 +354,15 @@ load_string(uint8 **p_buf, const uint8 *buf_end, AOTModule *module, if (str_len == 0) { str = ""; } +#if (WASM_ENABLE_WORD_ALIGN_READ != 0) + else if (is_vram_word_align) { + if (!(str = const_str_set_insert((uint8 *)p, str_len, module, + is_vram_word_align, error_buf, + error_buf_size))) { + goto fail; + } + } +#endif else if (p[str_len - 1] == '\0') { /* The string is terminated with '\0', use it directly */ str = (char *)p; @@ -284,8 +379,11 @@ load_string(uint8 **p_buf, const uint8 *buf_end, AOTModule *module, /* Load from sections, the file buffer cannot be reffered to after loading, we must create another string and insert it into const string set */ - if (!(str = const_str_set_insert((uint8 *)p, str_len, module, error_buf, - error_buf_size))) { + if (!(str = const_str_set_insert((uint8 *)p, str_len, module, +#if (WASM_ENABLE_WORD_ALIGN_READ != 0) + is_vram_word_align, +#endif + error_buf, error_buf_size))) { goto fail; } } @@ -716,23 +814,19 @@ load_custom_section(const uint8 *buf, const uint8 *buf_end, AOTModule *module, } static void -destroy_import_memories(AOTImportMemory *import_memories, bool is_jit_mode) +destroy_import_memories(AOTImportMemory *import_memories) { - if (!is_jit_mode) - wasm_runtime_free(import_memories); + wasm_runtime_free(import_memories); } static void -destroy_mem_init_data_list(AOTMemInitData **data_list, uint32 count, - bool is_jit_mode) +destroy_mem_init_data_list(AOTMemInitData **data_list, uint32 count) { - if (!is_jit_mode) { - uint32 i; - for (i = 0; i < count; i++) - if (data_list[i]) - wasm_runtime_free(data_list[i]); - wasm_runtime_free(data_list); - } + uint32 i; + for (i = 0; i < count; i++) + if (data_list[i]) + wasm_runtime_free(data_list[i]); + wasm_runtime_free(data_list); } static bool @@ -828,30 +922,25 @@ load_memory_info(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module, } static void -destroy_import_tables(AOTImportTable *import_tables, bool is_jit_mode) +destroy_import_tables(AOTImportTable *import_tables) { - if (!is_jit_mode) - wasm_runtime_free(import_tables); + wasm_runtime_free(import_tables); } static void -destroy_tables(AOTTable *tables, bool is_jit_mode) +destroy_tables(AOTTable *tables) { - if (!is_jit_mode) - wasm_runtime_free(tables); + wasm_runtime_free(tables); } static void -destroy_table_init_data_list(AOTTableInitData **data_list, uint32 count, - bool is_jit_mode) +destroy_table_init_data_list(AOTTableInitData **data_list, uint32 count) { - if (!is_jit_mode) { - uint32 i; - for (i = 0; i < count; i++) - if (data_list[i]) - wasm_runtime_free(data_list[i]); - wasm_runtime_free(data_list); - } + uint32 i; + for (i = 0; i < count; i++) + if (data_list[i]) + wasm_runtime_free(data_list[i]); + wasm_runtime_free(data_list); } static bool @@ -1003,15 +1092,13 @@ load_table_info(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module, } static void -destroy_func_types(AOTFuncType **func_types, uint32 count, bool is_jit_mode) +destroy_func_types(AOTFuncType **func_types, uint32 count) { - if (!is_jit_mode) { - uint32 i; - for (i = 0; i < count; i++) - if (func_types[i]) - wasm_runtime_free(func_types[i]); - wasm_runtime_free(func_types); - } + uint32 i; + for (i = 0; i < count; i++) + if (func_types[i]) + wasm_runtime_free(func_types[i]); + wasm_runtime_free(func_types); } static bool @@ -1094,10 +1181,9 @@ load_func_type_info(const uint8 **p_buf, const uint8 *buf_end, } static void -destroy_import_globals(AOTImportGlobal *import_globals, bool is_jit_mode) +destroy_import_globals(AOTImportGlobal *import_globals) { - if (!is_jit_mode) - wasm_runtime_free(import_globals); + wasm_runtime_free(import_globals); } static bool @@ -1140,7 +1226,10 @@ load_import_globals(const uint8 **p_buf, const uint8 *buf_end, } import_globals[i].global_data_linked = tmp_global.global_data_linked; + import_globals[i].is_linked = true; } +#else + import_globals[i].is_linked = false; #endif import_globals[i].size = wasm_value_type_size(import_globals[i].type); @@ -1177,10 +1266,9 @@ load_import_global_info(const uint8 **p_buf, const uint8 *buf_end, } static void -destroy_globals(AOTGlobal *globals, bool is_jit_mode) +destroy_globals(AOTGlobal *globals) { - if (!is_jit_mode) - wasm_runtime_free(globals); + wasm_runtime_free(globals); } static bool @@ -1259,10 +1347,9 @@ load_global_info(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module, } static void -destroy_import_funcs(AOTImportFunc *import_funcs, bool is_jit_mode) +destroy_import_funcs(AOTImportFunc *import_funcs) { - if (!is_jit_mode) - wasm_runtime_free(import_funcs); + wasm_runtime_free(import_funcs); } static bool @@ -1652,10 +1739,9 @@ load_function_section(const uint8 *buf, const uint8 *buf_end, AOTModule *module, } static void -destroy_exports(AOTExport *exports, bool is_jit_mode) +destroy_exports(AOTExport *exports) { - if (!is_jit_mode) - wasm_runtime_free(exports); + wasm_runtime_free(exports); } static bool @@ -2826,427 +2912,46 @@ aot_load_from_aot_file(const uint8 *buf, uint32 size, char *error_buf, return module; } -#if WASM_ENABLE_JIT != 0 -#if WASM_ENABLE_LAZY_JIT != 0 -/* Orc JIT thread arguments */ -typedef struct OrcJitThreadArg { - AOTCompData *comp_data; - AOTCompContext *comp_ctx; - AOTModule *module; - int32 group_idx; - int32 group_stride; -} OrcJitThreadArg; - -static bool orcjit_stop_compiling = false; -static korp_tid orcjit_threads[WASM_LAZY_JIT_COMPILE_THREAD_NUM]; -static OrcJitThreadArg orcjit_thread_args[WASM_LAZY_JIT_COMPILE_THREAD_NUM]; - -static void * -orcjit_thread_callback(void *arg) -{ - LLVMErrorRef error; - LLVMOrcJITTargetAddress func_addr = 0; - OrcJitThreadArg *thread_arg = (OrcJitThreadArg *)arg; - AOTCompData *comp_data = thread_arg->comp_data; - AOTCompContext *comp_ctx = thread_arg->comp_ctx; - AOTModule *module = thread_arg->module; - char func_name[32]; - int32 i; - - /* Compile wasm functions of this group */ - for (i = thread_arg->group_idx; i < (int32)comp_data->func_count; - i += thread_arg->group_stride) { - if (!module->func_ptrs[i]) { - snprintf(func_name, sizeof(func_name), "%s%d", AOT_FUNC_PREFIX, i); - if ((error = LLVMOrcLLJITLookup(comp_ctx->orc_lazyjit, &func_addr, - func_name))) { - char *err_msg = LLVMGetErrorMessage(error); - os_printf("failed to compile orc jit function: %s", err_msg); - LLVMDisposeErrorMessage(err_msg); - break; - } - /** - * No need to lock the func_ptr[func_idx] here as it is basic - * data type, the load/store for it can be finished by one cpu - * instruction, and there can be only one cpu instruction - * loading/storing at the same time. - */ - module->func_ptrs[i] = (void *)func_addr; - } - if (orcjit_stop_compiling) { - break; - } - } - - /* Try to compile functions that haven't been compiled by other threads */ - for (i = (int32)comp_data->func_count - 1; i > 0; i--) { - if (orcjit_stop_compiling) { - break; - } - if (!module->func_ptrs[i]) { - snprintf(func_name, sizeof(func_name), "%s%d", AOT_FUNC_PREFIX, i); - if ((error = LLVMOrcLLJITLookup(comp_ctx->orc_lazyjit, &func_addr, - func_name))) { - char *err_msg = LLVMGetErrorMessage(error); - os_printf("failed to compile orc jit function: %s", err_msg); - LLVMDisposeErrorMessage(err_msg); - break; - } - module->func_ptrs[i] = (void *)func_addr; - } - } - - return NULL; -} - -static void -orcjit_stop_compile_threads() -{ - uint32 i; - - orcjit_stop_compiling = true; - for (i = 0; i < WASM_LAZY_JIT_COMPILE_THREAD_NUM; i++) { - os_thread_join(orcjit_threads[i], NULL); - } -} -#endif - -static AOTModule * -aot_load_from_comp_data(AOTCompData *comp_data, AOTCompContext *comp_ctx, - char *error_buf, uint32 error_buf_size) -{ - uint32 i; - uint64 size; - char func_name[32]; - AOTModule *module; - - /* Allocate memory for module */ - if (!(module = - loader_malloc(sizeof(AOTModule), error_buf, error_buf_size))) { - return NULL; - } - - module->module_type = Wasm_Module_AoT; - - module->import_memory_count = comp_data->import_memory_count; - module->import_memories = comp_data->import_memories; - - module->memory_count = comp_data->memory_count; - if (module->memory_count) { - size = sizeof(AOTMemory) * (uint64)module->memory_count; - if (!(module->memories = - loader_malloc(size, error_buf, error_buf_size))) { - goto fail1; - } - - bh_memcpy_s(module->memories, (uint32)size, comp_data->memories, - (uint32)size); - } - - module->mem_init_data_list = comp_data->mem_init_data_list; - module->mem_init_data_count = comp_data->mem_init_data_count; - - module->import_table_count = comp_data->import_table_count; - module->import_tables = comp_data->import_tables; - - module->table_count = comp_data->table_count; - module->tables = comp_data->tables; - - module->table_init_data_list = comp_data->table_init_data_list; - module->table_init_data_count = comp_data->table_init_data_count; - - module->func_type_count = comp_data->func_type_count; - module->func_types = comp_data->func_types; - - module->import_global_count = comp_data->import_global_count; - module->import_globals = comp_data->import_globals; - - module->global_count = comp_data->global_count; - module->globals = comp_data->globals; - - module->global_count = comp_data->global_count; - module->globals = comp_data->globals; - - module->global_data_size = comp_data->global_data_size; - - module->import_func_count = comp_data->import_func_count; - module->import_funcs = comp_data->import_funcs; - - module->func_count = comp_data->func_count; - - /* Allocate memory for function pointers */ - size = (uint64)module->func_count * sizeof(void *); - if (size > 0 - && !(module->func_ptrs = - loader_malloc(size, error_buf, error_buf_size))) { - goto fail2; - } - -#if WASM_ENABLE_LAZY_JIT != 0 - /* Create threads to compile the wasm functions */ - for (i = 0; i < WASM_LAZY_JIT_COMPILE_THREAD_NUM; i++) { - orcjit_thread_args[i].comp_data = comp_data; - orcjit_thread_args[i].comp_ctx = comp_ctx; - orcjit_thread_args[i].module = module; - orcjit_thread_args[i].group_idx = (int32)i; - orcjit_thread_args[i].group_stride = WASM_LAZY_JIT_COMPILE_THREAD_NUM; - if (os_thread_create(&orcjit_threads[i], orcjit_thread_callback, - (void *)&orcjit_thread_args[i], - APP_THREAD_STACK_SIZE_DEFAULT) - != 0) { - uint32 j; - - set_error_buf(error_buf, error_buf_size, - "create orcjit compile thread failed"); - /* Terminate the threads created */ - orcjit_stop_compiling = true; - for (j = 0; j < i; j++) { - os_thread_join(orcjit_threads[j], NULL); - } - goto fail3; - } - } -#else - /* Resolve function addresses */ - bh_assert(comp_ctx->exec_engine); - for (i = 0; i < comp_data->func_count; i++) { - snprintf(func_name, sizeof(func_name), "%s%d", AOT_FUNC_PREFIX, i); - if (!(module->func_ptrs[i] = (void *)LLVMGetFunctionAddress( - comp_ctx->exec_engine, func_name))) { - set_error_buf(error_buf, error_buf_size, - "get function address failed"); - goto fail3; - } - } -#endif /* WASM_ENABLE_LAZY_JIT != 0 */ - - /* Allocation memory for function type indexes */ - size = (uint64)module->func_count * sizeof(uint32); - if (size > 0 - && !(module->func_type_indexes = - loader_malloc(size, error_buf, error_buf_size))) { - goto fail4; - } - for (i = 0; i < comp_data->func_count; i++) - module->func_type_indexes[i] = comp_data->funcs[i]->func_type_index; - - module->export_count = comp_data->wasm_module->export_count; - module->exports = comp_data->wasm_module->exports; - - module->start_func_index = comp_data->start_func_index; - if (comp_data->start_func_index != (uint32)-1) { - bh_assert(comp_data->start_func_index - < module->import_func_count + module->func_count); - /* TODO: fix issue that start func cannot be import func */ - if (comp_data->start_func_index >= module->import_func_count) { -#if WASM_ENABLE_LAZY_JIT != 0 - if (!module->func_ptrs[comp_data->start_func_index - - module->import_func_count]) { - LLVMErrorRef error; - LLVMOrcJITTargetAddress func_addr = 0; - - snprintf(func_name, sizeof(func_name), "%s%d", AOT_FUNC_PREFIX, - comp_data->start_func_index - - module->import_func_count); - if ((error = LLVMOrcLLJITLookup(comp_ctx->orc_lazyjit, - &func_addr, func_name))) { - char *err_msg = LLVMGetErrorMessage(error); - set_error_buf_v(error_buf, error_buf_size, - "failed to compile orc jit function: %s", - err_msg); - LLVMDisposeErrorMessage(err_msg); - goto fail5; - } - module->func_ptrs[comp_data->start_func_index - - module->import_func_count] = - (void *)func_addr; - } -#endif - module->start_function = - module->func_ptrs[comp_data->start_func_index - - module->import_func_count]; - } - } - - module->malloc_func_index = comp_data->malloc_func_index; - module->free_func_index = comp_data->free_func_index; - module->retain_func_index = comp_data->retain_func_index; - - module->aux_data_end_global_index = comp_data->aux_data_end_global_index; - module->aux_data_end = comp_data->aux_data_end; - module->aux_heap_base_global_index = comp_data->aux_heap_base_global_index; - module->aux_heap_base = comp_data->aux_heap_base; - module->aux_stack_top_global_index = comp_data->aux_stack_top_global_index; - module->aux_stack_bottom = comp_data->aux_stack_bottom; - module->aux_stack_size = comp_data->aux_stack_size; - - module->code = NULL; - module->code_size = 0; - - module->is_jit_mode = true; - - module->wasm_module = comp_data->wasm_module; - module->comp_ctx = comp_ctx; - module->comp_data = comp_data; - -#if WASM_ENABLE_LIBC_WASI != 0 - module->import_wasi_api = comp_data->wasm_module->import_wasi_api; -#endif - - return module; - -#if WASM_ENABLE_LAZY_JIT != 0 -fail5: - if (module->func_type_indexes) - wasm_runtime_free(module->func_type_indexes); -#endif - -fail4: -#if WASM_ENABLE_LAZY_JIT != 0 - /* Terminate all threads before free module->func_ptrs */ - orcjit_stop_compile_threads(); -#endif -fail3: - if (module->func_ptrs) - wasm_runtime_free(module->func_ptrs); -fail2: - if (module->memory_count > 0) - wasm_runtime_free(module->memories); -fail1: - wasm_runtime_free(module); - return NULL; -} - -AOTModule * -aot_convert_wasm_module(WASMModule *wasm_module, char *error_buf, - uint32 error_buf_size) -{ - AOTCompData *comp_data; - AOTCompContext *comp_ctx; - AOTModule *aot_module; - AOTCompOption option = { 0 }; - char *aot_last_error; - - comp_data = aot_create_comp_data(wasm_module); - if (!comp_data) { - aot_last_error = aot_get_last_error(); - bh_assert(aot_last_error != NULL); - set_error_buf(error_buf, error_buf_size, aot_last_error); - return NULL; - } - - option.is_jit_mode = true; - option.opt_level = 3; - option.size_level = 3; -#if WASM_ENABLE_BULK_MEMORY != 0 - option.enable_bulk_memory = true; -#endif -#if WASM_ENABLE_THREAD_MGR != 0 - option.enable_thread_mgr = true; -#endif -#if WASM_ENABLE_TAIL_CALL != 0 - option.enable_tail_call = true; -#endif -#if WASM_ENABLE_SIMD != 0 - option.enable_simd = true; -#endif -#if WASM_ENABLE_REF_TYPES != 0 - option.enable_ref_types = true; -#endif - option.enable_aux_stack_check = true; -#if (WASM_ENABLE_PERF_PROFILING != 0) || (WASM_ENABLE_DUMP_CALL_STACK != 0) - option.enable_aux_stack_frame = true; -#endif - - comp_ctx = aot_create_comp_context(comp_data, &option); - if (!comp_ctx) { - aot_last_error = aot_get_last_error(); - bh_assert(aot_last_error != NULL); - set_error_buf(error_buf, error_buf_size, aot_last_error); - goto fail1; - } - - if (!aot_compile_wasm(comp_ctx)) { - aot_last_error = aot_get_last_error(); - bh_assert(aot_last_error != NULL); - set_error_buf(error_buf, error_buf_size, aot_last_error); - goto fail2; - } - - aot_module = - aot_load_from_comp_data(comp_data, comp_ctx, error_buf, error_buf_size); - if (!aot_module) { - goto fail2; - } - - return aot_module; - -fail2: - aot_destroy_comp_context(comp_ctx); -fail1: - aot_destroy_comp_data(comp_data); - return NULL; -} -#endif - void aot_unload(AOTModule *module) { -#if WASM_ENABLE_JIT != 0 -#if WASM_ENABLE_LAZY_JIT != 0 - orcjit_stop_compile_threads(); -#endif - - if (module->comp_data) - aot_destroy_comp_data(module->comp_data); - - if (module->comp_ctx) - aot_destroy_comp_context(module->comp_ctx); - - if (module->wasm_module) - wasm_loader_unload(module->wasm_module); -#endif - if (module->import_memories) - destroy_import_memories(module->import_memories, module->is_jit_mode); + destroy_import_memories(module->import_memories); if (module->memories) wasm_runtime_free(module->memories); if (module->mem_init_data_list) destroy_mem_init_data_list(module->mem_init_data_list, - module->mem_init_data_count, - module->is_jit_mode); + module->mem_init_data_count); if (module->native_symbol_list) wasm_runtime_free(module->native_symbol_list); if (module->import_tables) - destroy_import_tables(module->import_tables, module->is_jit_mode); + destroy_import_tables(module->import_tables); if (module->tables) - destroy_tables(module->tables, module->is_jit_mode); + destroy_tables(module->tables); if (module->table_init_data_list) destroy_table_init_data_list(module->table_init_data_list, - module->table_init_data_count, - module->is_jit_mode); + module->table_init_data_count); if (module->func_types) - destroy_func_types(module->func_types, module->func_type_count, - module->is_jit_mode); + destroy_func_types(module->func_types, module->func_type_count); if (module->import_globals) - destroy_import_globals(module->import_globals, module->is_jit_mode); + destroy_import_globals(module->import_globals); if (module->globals) - destroy_globals(module->globals, module->is_jit_mode); + destroy_globals(module->globals); if (module->import_funcs) - destroy_import_funcs(module->import_funcs, module->is_jit_mode); + destroy_import_funcs(module->import_funcs); if (module->exports) - destroy_exports(module->exports, module->is_jit_mode); + destroy_exports(module->exports); if (module->func_type_indexes) wasm_runtime_free(module->func_type_indexes); diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/aot/aot_reloc.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/aot/aot_reloc.h similarity index 91% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/aot/aot_reloc.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/aot/aot_reloc.h index f97cea723cf..9f5c2d57fd8 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/aot/aot_reloc.h +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/aot/aot_reloc.h @@ -101,8 +101,12 @@ typedef struct { REG_SYM(aot_intrinsic_f64_to_f32), \ REG_SYM(aot_intrinsic_f32_to_i32), \ REG_SYM(aot_intrinsic_f32_to_u32), \ + REG_SYM(aot_intrinsic_f32_to_i64), \ + REG_SYM(aot_intrinsic_f32_to_u64), \ REG_SYM(aot_intrinsic_f64_to_i32), \ REG_SYM(aot_intrinsic_f64_to_u32), \ + REG_SYM(aot_intrinsic_f64_to_i64), \ + REG_SYM(aot_intrinsic_f64_to_u64), \ REG_SYM(aot_intrinsic_f32_to_f64), \ REG_SYM(aot_intrinsic_f32_cmp), \ REG_SYM(aot_intrinsic_f64_cmp), \ @@ -110,6 +114,12 @@ typedef struct { REG_SYM(aot_intrinsic_i64_div_u), \ REG_SYM(aot_intrinsic_i64_rem_s), \ REG_SYM(aot_intrinsic_i64_rem_u), \ + REG_SYM(aot_intrinsic_i64_bit_or), \ + REG_SYM(aot_intrinsic_i64_bit_and), \ + REG_SYM(aot_intrinsic_i32_div_s), \ + REG_SYM(aot_intrinsic_i32_div_u), \ + REG_SYM(aot_intrinsic_i32_rem_s), \ + REG_SYM(aot_intrinsic_i32_rem_u), \ #define REG_COMMON_SYMBOLS \ REG_SYM(aot_set_exception_with_id), \ @@ -121,6 +131,8 @@ typedef struct { { "memset", (void*)aot_memset }, \ { "memmove", (void*)aot_memmove }, \ { "memcpy", (void*)aot_memmove }, \ + { "sqrt", (void*)aot_sqrt }, \ + { "sqrtf", (void*)aot_sqrtf }, \ REG_SYM(fmin), \ REG_SYM(fminf), \ REG_SYM(fmax), \ diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/aot/aot_runtime.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/aot/aot_runtime.c similarity index 66% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/aot/aot_runtime.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/aot/aot_runtime.c index c1ae5e41825..b5c406b960d 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/aot/aot_runtime.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/aot/aot_runtime.c @@ -7,6 +7,7 @@ #include "bh_log.h" #include "mem_alloc.h" #include "../common/wasm_runtime_common.h" +#include "../interpreter/wasm_runtime.h" #if WASM_ENABLE_SHARED_MEMORY != 0 #include "../common/wasm_shared_memory.h" #endif @@ -29,6 +30,17 @@ bh_static_assert(offsetof(WASMExecEnv, aux_stack_boundary) bh_static_assert(offsetof(WASMExecEnv, aux_stack_bottom) == 7 * sizeof(uintptr_t)); bh_static_assert(offsetof(WASMExecEnv, native_symbol) == 8 * sizeof(uintptr_t)); +bh_static_assert(offsetof(WASMExecEnv, native_stack_top_min) + == 9 * sizeof(uintptr_t)); + +bh_static_assert(offsetof(AOTModuleInstance, memories) == 1 * sizeof(uint64)); +bh_static_assert(offsetof(AOTModuleInstance, func_ptrs) == 5 * sizeof(uint64)); +bh_static_assert(offsetof(AOTModuleInstance, func_type_indexes) + == 6 * sizeof(uint64)); +bh_static_assert(offsetof(AOTModuleInstance, cur_exception) + == 13 * sizeof(uint64)); +bh_static_assert(offsetof(AOTModuleInstance, global_table_data) + == 13 * sizeof(uint64) + 128 + 11 * sizeof(uint64)); static void set_error_buf(char *error_buf, uint32 error_buf_size, const char *string) @@ -114,7 +126,7 @@ init_global_data(uint8 *global_data, uint8 type, WASMValue *initial_value) break; #if WASM_ENABLE_SIMD != 0 case VALUE_TYPE_V128: - bh_memcpy_s(global_data, sizeof(V128), &initial_value->i64, + bh_memcpy_s(global_data, sizeof(V128), &initial_value->v128, sizeof(V128)); break; #endif @@ -129,14 +141,14 @@ global_instantiate(AOTModuleInstance *module_inst, AOTModule *module, { uint32 i; InitializerExpression *init_expr; - uint8 *p = (uint8 *)module_inst->global_data.ptr; + uint8 *p = module_inst->global_data; AOTImportGlobal *import_global = module->import_globals; AOTGlobal *global = module->globals; /* Initialize import global data */ for (i = 0; i < module->import_global_count; i++, import_global++) { bh_assert(import_global->data_offset - == (uint32)(p - (uint8 *)module_inst->global_data.ptr)); + == (uint32)(p - module_inst->global_data)); init_global_data(p, import_global->type, &import_global->global_data_linked); p += import_global->size; @@ -145,7 +157,7 @@ global_instantiate(AOTModuleInstance *module_inst, AOTModule *module, /* Initialize defined global data */ for (i = 0; i < module->global_count; i++, global++) { bh_assert(global->data_offset - == (uint32)(p - (uint8 *)module_inst->global_data.ptr)); + == (uint32)(p - module_inst->global_data)); init_expr = &global->init_expr; switch (init_expr->init_expr_type) { case INIT_EXPR_TYPE_GET_GLOBAL: @@ -177,39 +189,26 @@ global_instantiate(AOTModuleInstance *module_inst, AOTModule *module, } bh_assert(module_inst->global_data_size - == (uint32)(p - (uint8 *)module_inst->global_data.ptr)); + == (uint32)(p - module_inst->global_data)); return true; } -AOTTableInstance * -aot_next_tbl_inst(const AOTTableInstance *tbl_inst) -{ - uint32 offset = offsetof(AOTTableInstance, data); - offset += tbl_inst->max_size * sizeof(uint32); - return (AOTTableInstance *)((uint8 *)tbl_inst + offset); -} - -static inline AOTTableInstance * -aot_get_table_inst(const AOTModuleInstance *module_inst, uint32 tbl_idx) -{ - uint32 i = 0; - AOTTableInstance *tbl_inst = (AOTTableInstance *)module_inst->tables.ptr; - - while (i != tbl_idx) { - tbl_inst = aot_next_tbl_inst(tbl_inst); - ++i; - } - - return tbl_inst; -} - static bool -table_instantiate(AOTModuleInstance *module_inst, AOTModule *module, - char *error_buf, uint32 error_buf_size) +tables_instantiate(AOTModuleInstance *module_inst, AOTModule *module, + AOTTableInstance *first_tbl_inst, char *error_buf, + uint32 error_buf_size) { uint32 i, global_index, global_data_offset, base_offset, length; + uint64 total_size; AOTTableInitData *table_seg; - AOTTableInstance *tbl_inst = (AOTTableInstance *)module_inst->tables.ptr; + AOTTableInstance *tbl_inst = first_tbl_inst; + + total_size = (uint64)sizeof(WASMTableInstance *) * module_inst->table_count; + if (total_size > 0 + && !(module_inst->tables = + runtime_malloc(total_size, error_buf, error_buf_size))) { + return false; + } /* * treat import table like a local one until we enable module linking @@ -219,15 +218,22 @@ table_instantiate(AOTModuleInstance *module_inst, AOTModule *module, if (i < module->import_table_count) { AOTImportTable *import_table = module->import_tables + i; tbl_inst->cur_size = import_table->table_init_size; - tbl_inst->max_size = aot_get_imp_tbl_data_slots(import_table); + tbl_inst->max_size = + aot_get_imp_tbl_data_slots(import_table, false); } else { AOTTable *table = module->tables + (i - module->import_table_count); tbl_inst->cur_size = table->table_init_size; - tbl_inst->max_size = aot_get_tbl_data_slots(table); + tbl_inst->max_size = aot_get_tbl_data_slots(table, false); } - tbl_inst = aot_next_tbl_inst(tbl_inst); + /* Set all elements to -1 to mark them as uninitialized elements */ + memset(tbl_inst->elems, 0xff, sizeof(uint32) * tbl_inst->max_size); + + module_inst->tables[i] = tbl_inst; + tbl_inst = (AOTTableInstance *)((uint8 *)tbl_inst + + offsetof(AOTTableInstance, elems) + + sizeof(uint32) * tbl_inst->max_size); } /* fill table with element segment content */ @@ -241,7 +247,7 @@ table_instantiate(AOTModuleInstance *module_inst, AOTModule *module, bh_assert(table_seg->table_index < module_inst->table_count); - tbl_inst = aot_get_table_inst(module_inst, table_seg->table_index); + tbl_inst = module_inst->tables[table_seg->table_index]; bh_assert(tbl_inst); #if WASM_ENABLE_REF_TYPES != 0 @@ -274,8 +280,8 @@ table_instantiate(AOTModuleInstance *module_inst, AOTModule *module, module->globals[global_index - module->import_global_count] .data_offset; - base_offset = *(uint32 *)((uint8 *)module_inst->global_data.ptr - + global_data_offset); + base_offset = + *(uint32 *)(module_inst->global_data + global_data_offset); } else base_offset = (uint32)table_seg->offset.u.i32; @@ -310,7 +316,7 @@ table_instantiate(AOTModuleInstance *module_inst, AOTModule *module, * Check function index in the current module inst for now. * will check the linked table inst owner in future */ - bh_memcpy_s((uint32 *)tbl_inst->data + base_offset, + bh_memcpy_s(tbl_inst->elems + base_offset, (tbl_inst->max_size - base_offset) * sizeof(uint32), table_seg->func_indexes, length * sizeof(uint32)); } @@ -325,12 +331,12 @@ memories_deinstantiate(AOTModuleInstance *module_inst) AOTMemoryInstance *memory_inst; for (i = 0; i < module_inst->memory_count; i++) { - memory_inst = ((AOTMemoryInstance **)module_inst->memories.ptr)[i]; + 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->aot_module.ptr); + (WASMModuleCommon *)module_inst->module); bh_assert(ref_count >= 0); /* if the reference count is not zero, @@ -339,27 +345,26 @@ memories_deinstantiate(AOTModuleInstance *module_inst) continue; } #endif - if (memory_inst->heap_handle.ptr) { - mem_allocator_destroy(memory_inst->heap_handle.ptr); - wasm_runtime_free(memory_inst->heap_handle.ptr); + if (memory_inst->heap_handle) { + mem_allocator_destroy(memory_inst->heap_handle); + wasm_runtime_free(memory_inst->heap_handle); } - if (memory_inst->memory_data.ptr) { + if (memory_inst->memory_data) { #ifndef OS_ENABLE_HW_BOUND_CHECK - wasm_runtime_free(memory_inst->memory_data.ptr); + wasm_runtime_free(memory_inst->memory_data); #else #ifdef BH_PLATFORM_WINDOWS - os_mem_decommit(memory_inst->memory_data.ptr, + os_mem_decommit(memory_inst->memory_data, memory_inst->num_bytes_per_page * memory_inst->cur_page_count); #endif - os_munmap((uint8 *)memory_inst->memory_data.ptr, - 8 * (uint64)BH_GB); + os_munmap(memory_inst->memory_data, 8 * (uint64)BH_GB); #endif } } } - wasm_runtime_free(module_inst->memories.ptr); + wasm_runtime_free(module_inst->memories); } static AOTMemoryInstance * @@ -461,7 +466,7 @@ memory_instantiate(AOTModuleInstance *module_inst, AOTModule *module, /* Adjust __heap_base global value */ global_idx = module->aux_heap_base_global_index - module->import_global_count; - global_addr = (uint8 *)module_inst->global_data.ptr + global_addr = module_inst->global_data + module->globals[global_idx].data_offset; *(uint32 *)global_addr = aux_heap_base; LOG_VERBOSE("Reset __heap_base global to %u", aux_heap_base); @@ -557,12 +562,12 @@ memory_instantiate(AOTModuleInstance *module_inst, AOTModule *module, memory_inst->memory_data_size = (uint32)total_size; /* Init memory info */ - memory_inst->memory_data.ptr = p; - memory_inst->memory_data_end.ptr = p + (uint32)total_size; + memory_inst->memory_data = p; + memory_inst->memory_data_end = p + (uint32)total_size; /* Initialize heap info */ - memory_inst->heap_data.ptr = p + heap_offset; - memory_inst->heap_data_end.ptr = p + heap_offset + heap_size; + memory_inst->heap_data = p + heap_offset; + memory_inst->heap_data_end = p + heap_offset + heap_size; if (heap_size > 0) { uint32 heap_struct_size = mem_allocator_get_heap_struct_size(); @@ -571,10 +576,10 @@ memory_instantiate(AOTModuleInstance *module_inst, AOTModule *module, goto fail1; } - memory_inst->heap_handle.ptr = heap_handle; + memory_inst->heap_handle = heap_handle; if (!mem_allocator_create_with_struct_and_pool( - heap_handle, heap_struct_size, memory_inst->heap_data.ptr, + heap_handle, heap_struct_size, memory_inst->heap_data, heap_size)) { set_error_buf(error_buf, error_buf_size, "init app heap failed"); goto fail2; @@ -614,31 +619,31 @@ memory_instantiate(AOTModuleInstance *module_inst, AOTModule *module, #if WASM_ENABLE_SHARED_MEMORY != 0 fail3: if (heap_size > 0) - mem_allocator_destroy(memory_inst->heap_handle.ptr); + mem_allocator_destroy(memory_inst->heap_handle); #endif fail2: if (heap_size > 0) - wasm_runtime_free(memory_inst->heap_handle.ptr); + wasm_runtime_free(memory_inst->heap_handle); fail1: #ifndef OS_ENABLE_HW_BOUND_CHECK - if (memory_inst->memory_data.ptr) - wasm_runtime_free(memory_inst->memory_data.ptr); + if (memory_inst->memory_data) + wasm_runtime_free(memory_inst->memory_data); #else #ifdef BH_PLATFORM_WINDOWS - if (memory_inst->memory_data.ptr) + if (memory_inst->memory_data) os_mem_decommit(p, total_size); #endif os_munmap(mapped_mem, map_size); #endif - memory_inst->memory_data.ptr = NULL; + memory_inst->memory_data = NULL; return NULL; } static AOTMemoryInstance * aot_get_default_memory(AOTModuleInstance *module_inst) { - if (module_inst->memories.ptr) - return ((AOTMemoryInstance **)module_inst->memories.ptr)[0]; + if (module_inst->memories) + return module_inst->memories[0]; else return NULL; } @@ -654,8 +659,8 @@ memories_instantiate(AOTModuleInstance *module_inst, AOTModule *module, uint64 total_size; module_inst->memory_count = memory_count; - total_size = sizeof(AOTPointer) * (uint64)memory_count; - if (!(module_inst->memories.ptr = + total_size = sizeof(AOTMemoryInstance *) * (uint64)memory_count; + if (!(module_inst->memories = runtime_malloc(total_size, error_buf, error_buf_size))) { return false; } @@ -669,7 +674,7 @@ memories_instantiate(AOTModuleInstance *module_inst, AOTModule *module, return false; } - ((AOTMemoryInstance **)module_inst->memories.ptr)[i] = memory_inst; + module_inst->memories[i] = memory_inst; } /* Get default memory instance */ @@ -707,15 +712,15 @@ memories_instantiate(AOTModuleInstance *module_inst, AOTModule *module, module->globals[global_index - module->import_global_count] .data_offset; - base_offset = *(uint32 *)((uint8 *)module_inst->global_data.ptr - + global_data_offset); + base_offset = + *(uint32 *)(module_inst->global_data + global_data_offset); } else { base_offset = (uint32)data_seg->offset.u.i32; } /* Copy memory data */ - bh_assert(memory_inst->memory_data.ptr + bh_assert(memory_inst->memory_data || memory_inst->memory_data_size == 0); /* Check memory data */ @@ -748,8 +753,8 @@ memories_instantiate(AOTModuleInstance *module_inst, AOTModule *module, return false; } - if (memory_inst->memory_data.ptr) { - bh_memcpy_s((uint8 *)memory_inst->memory_data.ptr + base_offset, + if (memory_inst->memory_data) { + bh_memcpy_s((uint8 *)memory_inst->memory_data + base_offset, memory_inst->memory_data_size - base_offset, data_seg->bytes, length); } @@ -771,13 +776,13 @@ init_func_ptrs(AOTModuleInstance *module_inst, AOTModule *module, return true; /* Allocate memory */ - if (!(module_inst->func_ptrs.ptr = + if (!(module_inst->func_ptrs = runtime_malloc(total_size, error_buf, error_buf_size))) { return false; } /* Set import function pointers */ - func_ptrs = (void **)module_inst->func_ptrs.ptr; + func_ptrs = (void **)module_inst->func_ptrs; for (i = 0; i < module->import_func_count; i++, func_ptrs++) { *func_ptrs = (void *)module->import_funcs[i].func_ptr_linked; if (!*func_ptrs) { @@ -807,13 +812,13 @@ init_func_type_indexes(AOTModuleInstance *module_inst, AOTModule *module, return true; /* Allocate memory */ - if (!(module_inst->func_type_indexes.ptr = + if (!(module_inst->func_type_indexes = runtime_malloc(total_size, error_buf, error_buf_size))) { return false; } /* Set import function type indexes */ - func_type_index = (uint32 *)module_inst->func_type_indexes.ptr; + func_type_index = module_inst->func_type_indexes; for (i = 0; i < module->import_func_count; i++, func_type_index++) *func_type_index = module->import_funcs[i].func_type_index; @@ -835,10 +840,10 @@ create_export_funcs(AOTModuleInstance *module_inst, AOTModule *module, /* Allocate memory */ size = sizeof(AOTFunctionInstance) * (uint64)module_inst->export_func_count; - if (!(module_inst->export_funcs.ptr = export_func = - runtime_malloc(size, error_buf, error_buf_size))) { + if (!(export_func = runtime_malloc(size, error_buf, error_buf_size))) { return false; } + module_inst->export_functions = (void *)export_func; for (i = 0; i < module->export_count; i++) { if (exports[i].kind == EXPORT_KIND_FUNC) { @@ -883,10 +888,10 @@ create_exports(AOTModuleInstance *module_inst, AOTModule *module, module_inst->export_global_count++; break; case EXPORT_KIND_TABLE: - module_inst->export_tab_count++; + module_inst->export_table_count++; break; case EXPORT_KIND_MEMORY: - module_inst->export_mem_count++; + module_inst->export_memory_count++; break; default: return false; @@ -896,86 +901,194 @@ create_exports(AOTModuleInstance *module_inst, AOTModule *module, return create_export_funcs(module_inst, module, error_buf, error_buf_size); } -static bool -clear_wasi_proc_exit_exception(AOTModuleInstance *module_inst) +static AOTFunctionInstance * +lookup_post_instantiate_func(AOTModuleInstance *module_inst, + const char *func_name) { + AOTFunctionInstance *func; + AOTFuncType *func_type; + + if (!(func = aot_lookup_function(module_inst, func_name, NULL))) + /* Not found */ + return NULL; + + func_type = func->u.func.func_type; + if (!(func_type->param_count == 0 && func_type->result_count == 0)) + /* Not a valid function type, ignore it */ + return NULL; + + return func; +} + +static bool +execute_post_instantiate_functions(AOTModuleInstance *module_inst, + bool is_sub_inst, WASMExecEnv *exec_env_main) +{ + AOTModule *module = (AOTModule *)module_inst->module; + AOTFunctionInstance *initialize_func = NULL; + AOTFunctionInstance *post_inst_func = NULL; + AOTFunctionInstance *call_ctors_func = NULL; + WASMModuleInstanceCommon *module_inst_main = NULL; +#ifdef OS_ENABLE_HW_BOUND_CHECK + WASMExecEnv *exec_env_tls = wasm_runtime_get_exec_env_tls(); +#endif + WASMExecEnv *exec_env = NULL, *exec_env_created = NULL; + bool ret = false; + #if WASM_ENABLE_LIBC_WASI != 0 - const char *exception = aot_get_exception(module_inst); - if (exception && !strcmp(exception, "Exception: wasi proc exit")) { - /* The "wasi proc exit" exception is thrown by native lib to - let wasm app exit, which is a normal behavior, we clear - the exception here. */ - aot_set_exception(module_inst, NULL); - return true; + /* + * WASI reactor instances may assume that _initialize will be called by + * the environment at most once, and that none of their other exports + * are accessed before that call. + */ + if (!is_sub_inst && module->import_wasi_api) { + initialize_func = + lookup_post_instantiate_func(module_inst, "_initialize"); } - return false; -#else - return false; #endif -} -static bool -execute_post_inst_function(AOTModuleInstance *module_inst) -{ - AOTFunctionInstance *post_inst_func = - aot_lookup_function(module_inst, "__post_instantiate", "()"); + /* Execute possible "__post_instantiate" function if wasm app is + compiled by emsdk's early version */ + if (!is_sub_inst) { + post_inst_func = + lookup_post_instantiate_func(module_inst, "__post_instantiate"); + } - if (!post_inst_func) - /* Not found */ +#if WASM_ENABLE_BULK_MEMORY != 0 + /* Only execute the memory init function for main instance since + the data segments will be dropped once initialized */ + if (!is_sub_inst +#if WASM_ENABLE_LIBC_WASI != 0 + && !module->import_wasi_api +#endif + ) { + call_ctors_func = + lookup_post_instantiate_func(module_inst, "__wasm_call_ctors"); + } +#endif + + if (!module->start_function && !initialize_func && !post_inst_func + && !call_ctors_func) { + /* No post instantiation functions to call */ return true; + } - return aot_create_exec_env_and_call_function(module_inst, post_inst_func, 0, - NULL); -} + if (is_sub_inst) { + bh_assert(exec_env_main); +#ifdef OS_ENABLE_HW_BOUND_CHECK + bh_assert(exec_env_tls == exec_env_main); + (void)exec_env_tls; +#endif + exec_env = exec_env_main; -static bool -execute_start_function(AOTModuleInstance *module_inst) -{ - AOTModule *module = (AOTModule *)module_inst->aot_module.ptr; - WASMExecEnv *exec_env; - typedef void (*F)(WASMExecEnv *); - union { - F f; - void *v; - } u; - - if (!module->start_function) - return true; + /* Temporarily replace parent exec_env's module inst to current + module inst to avoid checking failure when calling the + wasm functions, and ensure that the exec_env's module inst + is the correct one. */ + module_inst_main = exec_env_main->module_inst; + exec_env->module_inst = (WASMModuleInstanceCommon *)module_inst; + } + else { + /* Try using the existing exec_env */ +#ifdef OS_ENABLE_HW_BOUND_CHECK + exec_env = exec_env_tls; +#endif +#if WASM_ENABLE_THREAD_MGR != 0 + if (!exec_env) + exec_env = wasm_clusters_search_exec_env( + (WASMModuleInstanceCommon *)module_inst); +#endif + if (!exec_env) { + if (!(exec_env = exec_env_created = wasm_exec_env_create( + (WASMModuleInstanceCommon *)module_inst, + module_inst->default_wasm_stack_size))) { + aot_set_exception(module_inst, "allocate memory failed"); + return false; + } + } + else { + /* Temporarily replace exec_env's module inst with current + module inst to ensure that the exec_env's module inst + is the correct one. */ + module_inst_main = exec_env->module_inst; + exec_env->module_inst = (WASMModuleInstanceCommon *)module_inst; + } + } + + /* Execute start function for both main insance and sub instance */ + if (module->start_function) { + AOTFunctionInstance start_func = { 0 }; + uint32 func_type_idx; + + start_func.func_name = ""; + start_func.func_index = module->start_func_index; + start_func.is_import_func = false; + func_type_idx = module->func_type_indexes[module->start_func_index + - module->import_func_count]; + start_func.u.func.func_type = module->func_types[func_type_idx]; + start_func.u.func.func_ptr = module->start_function; + if (!aot_call_function(exec_env, &start_func, 0, NULL)) { + goto fail; + } + } - if (!(exec_env = - wasm_exec_env_create((WASMModuleInstanceCommon *)module_inst, - module_inst->default_wasm_stack_size))) { - aot_set_exception(module_inst, "allocate memory failed"); - return false; + if (initialize_func + && !aot_call_function(exec_env, initialize_func, 0, NULL)) { + goto fail; } - u.v = module->start_function; - u.f(exec_env); + if (post_inst_func + && !aot_call_function(exec_env, post_inst_func, 0, NULL)) { + goto fail; + } + + if (call_ctors_func + && !aot_call_function(exec_env, call_ctors_func, 0, NULL)) { + goto fail; + } + + ret = true; - wasm_exec_env_destroy(exec_env); - (void)clear_wasi_proc_exit_exception(module_inst); - return !aot_get_exception(module_inst); +fail: + if (is_sub_inst) { + /* Restore the parent exec_env's module inst */ + exec_env_main->module_inst = module_inst_main; + } + else { + if (module_inst_main) + /* Restore the existing exec_env's module inst */ + exec_env->module_inst = module_inst_main; + if (exec_env_created) + wasm_exec_env_destroy(exec_env_created); + } + + return ret; } -#if WASM_ENABLE_BULK_MEMORY != 0 static bool -execute_memory_init_function(AOTModuleInstance *module_inst) +check_linked_symbol(AOTModule *module, char *error_buf, uint32 error_buf_size) { - AOTFunctionInstance *memory_init_func = - aot_lookup_function(module_inst, "__wasm_call_ctors", "()"); + uint32 i; - if (!memory_init_func) - /* Not found */ - return true; + /* init_func_ptrs() will go through import functions */ - return aot_create_exec_env_and_call_function(module_inst, memory_init_func, - 0, NULL); + for (i = 0; i < module->import_global_count; i++) { + AOTImportGlobal *global = module->import_globals + i; + if (!global->is_linked) { + set_error_buf_v(error_buf, error_buf_size, + "failed to link import global (%s, %s)", + global->module_name, global->global_name); + return false; + } + } + + return true; } -#endif AOTModuleInstance * -aot_instantiate(AOTModule *module, bool is_sub_inst, uint32 stack_size, - uint32 heap_size, char *error_buf, uint32 error_buf_size) +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) { AOTModuleInstance *module_inst; const uint32 module_inst_struct_size = @@ -984,7 +1097,7 @@ aot_instantiate(AOTModule *module, bool is_sub_inst, uint32 stack_size, (uint64)module->memory_count * sizeof(AOTMemoryInstance); uint64 total_size, table_size = 0; uint8 *p; - uint32 i; + uint32 i, extra_info_offset; /* Check heap size */ heap_size = align_uint(heap_size, 8); @@ -998,19 +1111,25 @@ aot_instantiate(AOTModule *module, bool is_sub_inst, uint32 stack_size, * calculate size of table data */ for (i = 0; i != module->import_table_count; ++i) { - table_size += offsetof(AOTTableInstance, data); - table_size += - (uint64)sizeof(uint32) - * (uint64)aot_get_imp_tbl_data_slots(module->import_tables + i); + table_size += offsetof(AOTTableInstance, elems); + table_size += (uint64)sizeof(uint32) + * (uint64)aot_get_imp_tbl_data_slots( + module->import_tables + i, false); } for (i = 0; i != module->table_count; ++i) { - table_size += offsetof(AOTTableInstance, data); - table_size += (uint64)sizeof(uint32) - * (uint64)aot_get_tbl_data_slots(module->tables + i); + table_size += offsetof(AOTTableInstance, elems); + table_size += + (uint64)sizeof(uint32) + * (uint64)aot_get_tbl_data_slots(module->tables + i, false); } total_size += table_size; + /* The offset of AOTModuleInstanceExtra, make it 8-byte aligned */ + total_size = (total_size + 7LL) & ~7LL; + extra_info_offset = (uint32)total_size; + total_size += sizeof(AOTModuleInstanceExtra); + /* Allocate module instance, global data, table data and heap data */ if (!(module_inst = runtime_malloc(total_size, error_buf, error_buf_size))) { @@ -1018,23 +1137,23 @@ aot_instantiate(AOTModule *module, bool is_sub_inst, uint32 stack_size, } module_inst->module_type = Wasm_Module_AoT; - module_inst->aot_module.ptr = module; + module_inst->module = (void *)module; + module_inst->e = + (WASMModuleInstanceExtra *)((uint8 *)module_inst + extra_info_offset); /* Initialize global info */ p = (uint8 *)module_inst + module_inst_struct_size + module_inst_mem_inst_size; - module_inst->global_data.ptr = p; + module_inst->global_data = p; module_inst->global_data_size = module->global_data_size; if (!global_instantiate(module_inst, module, error_buf, error_buf_size)) goto fail; /* Initialize table info */ p += module->global_data_size; - module_inst->tables.ptr = p; module_inst->table_count = module->table_count + module->import_table_count; - /* Set all elements to -1 to mark them as uninitialized elements */ - memset(module_inst->tables.ptr, 0xff, (uint32)table_size); - if (!table_instantiate(module_inst, module, error_buf, error_buf_size)) + if (!tables_instantiate(module_inst, module, (AOTTableInstance *)p, + error_buf, error_buf_size)) goto fail; /* Initialize memory space */ @@ -1050,6 +1169,9 @@ aot_instantiate(AOTModule *module, bool is_sub_inst, uint32 stack_size, if (!init_func_type_indexes(module_inst, module, error_buf, error_buf_size)) goto fail; + if (!check_linked_symbol(module, error_buf, error_buf_size)) + goto fail; + if (!create_exports(module_inst, module, error_buf, error_buf_size)) goto fail; @@ -1070,6 +1192,17 @@ aot_instantiate(AOTModule *module, bool is_sub_inst, uint32 stack_size, } #endif +#if WASM_ENABLE_WASI_NN != 0 + if (!is_sub_inst) { + if (!(((AOTModuleInstanceExtra *)module_inst->e)->wasi_nn_ctx = + wasi_nn_initialize())) { + set_error_buf(error_buf, error_buf_size, + "wasi nn initialization failed"); + goto fail; + } + } +#endif + /* Initialize the thread related data */ if (stack_size == 0) stack_size = DEFAULT_WASM_STACK_SIZE; @@ -1082,45 +1215,25 @@ aot_instantiate(AOTModule *module, bool is_sub_inst, uint32 stack_size, #if WASM_ENABLE_PERF_PROFILING != 0 total_size = (uint64)sizeof(AOTFuncPerfProfInfo) * (module->import_func_count + module->func_count); - if (!(module_inst->func_perf_profilings.ptr = + if (!(module_inst->func_perf_profilings = runtime_malloc(total_size, error_buf, error_buf_size))) { goto fail; } #endif #if WASM_ENABLE_DUMP_CALL_STACK != 0 - if (!(module_inst->frames.ptr = + if (!(module_inst->frames = runtime_malloc(sizeof(Vector), error_buf, error_buf_size))) { goto fail; } #endif - /* Execute __post_instantiate function and start function*/ - if (!execute_post_inst_function(module_inst) - || !execute_start_function(module_inst)) { + if (!execute_post_instantiate_functions(module_inst, is_sub_inst, + exec_env_main)) { set_error_buf(error_buf, error_buf_size, module_inst->cur_exception); goto fail; } -#if WASM_ENABLE_BULK_MEMORY != 0 -#if WASM_ENABLE_LIBC_WASI != 0 - if (!module->import_wasi_api) { -#endif - /* Only execute the memory init function for main instance because - the data segments will be dropped once initialized. - */ - if (!is_sub_inst) { - if (!execute_memory_init_function(module_inst)) { - set_error_buf(error_buf, error_buf_size, - module_inst->cur_exception); - goto fail; - } - } -#if WASM_ENABLE_LIBC_WASI != 0 - } -#endif -#endif - #if WASM_ENABLE_MEMORY_TRACING != 0 wasm_runtime_dump_module_inst_mem_consumption( (WASMModuleInstanceCommon *)module_inst); @@ -1133,21 +1246,18 @@ aot_instantiate(AOTModule *module, bool is_sub_inst, uint32 stack_size, return NULL; } -bool -aot_create_exec_env_singleton(AOTModuleInstance *module_inst) -{ - WASMExecEnv *exec_env = - wasm_exec_env_create((WASMModuleInstanceCommon *)module_inst, - module_inst->default_wasm_stack_size); - if (exec_env) - module_inst->exec_env_singleton.ptr = exec_env; - - return exec_env ? true : false; -} - void aot_deinstantiate(AOTModuleInstance *module_inst, bool is_sub_inst) { + if (module_inst->exec_env_singleton) { + /* wasm_exec_env_destroy will call + wasm_cluster_wait_for_all_except_self to wait for other + threads, so as to destroy their exec_envs and module + instances first, and avoid accessing the shared resources + of current module instance after it is deinstantiated. */ + 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, @@ -1159,33 +1269,45 @@ aot_deinstantiate(AOTModuleInstance *module_inst, bool is_sub_inst) #endif #if WASM_ENABLE_PERF_PROFILING != 0 - if (module_inst->func_perf_profilings.ptr) - wasm_runtime_free(module_inst->func_perf_profilings.ptr); + if (module_inst->func_perf_profilings) + wasm_runtime_free(module_inst->func_perf_profilings); #endif #if WASM_ENABLE_DUMP_CALL_STACK != 0 - if (module_inst->frames.ptr) { - bh_vector_destroy(module_inst->frames.ptr); - wasm_runtime_free(module_inst->frames.ptr); - module_inst->frames.ptr = NULL; + if (module_inst->frames) { + bh_vector_destroy(module_inst->frames); + wasm_runtime_free(module_inst->frames); + module_inst->frames = NULL; } #endif - if (module_inst->memories.ptr) + if (module_inst->tables) + wasm_runtime_free(module_inst->tables); + + if (module_inst->memories) memories_deinstantiate(module_inst); - if (module_inst->export_funcs.ptr) - wasm_runtime_free(module_inst->export_funcs.ptr); + if (module_inst->export_functions) + wasm_runtime_free(module_inst->export_functions); - if (module_inst->func_ptrs.ptr) - wasm_runtime_free(module_inst->func_ptrs.ptr); + if (module_inst->func_ptrs) + wasm_runtime_free(module_inst->func_ptrs); - if (module_inst->func_type_indexes.ptr) - wasm_runtime_free(module_inst->func_type_indexes.ptr); + if (module_inst->func_type_indexes) + wasm_runtime_free(module_inst->func_type_indexes); - if (module_inst->exec_env_singleton.ptr) - wasm_exec_env_destroy( - (WASMExecEnv *)module_inst->exec_env_singleton.ptr); + if (((AOTModuleInstanceExtra *)module_inst->e)->c_api_func_imports) + wasm_runtime_free( + ((AOTModuleInstanceExtra *)module_inst->e)->c_api_func_imports); + +#if WASM_ENABLE_WASI_NN != 0 + if (!is_sub_inst) { + WASINNContext *wasi_nn_ctx = + ((AOTModuleInstanceExtra *)module_inst->e)->wasi_nn_ctx; + if (wasi_nn_ctx) + wasi_nn_destroy(wasi_nn_ctx); + } +#endif wasm_runtime_free(module_inst); } @@ -1196,7 +1318,7 @@ aot_lookup_function(const AOTModuleInstance *module_inst, const char *name, { uint32 i; AOTFunctionInstance *export_funcs = - (AOTFunctionInstance *)module_inst->export_funcs.ptr; + (AOTFunctionInstance *)module_inst->export_functions; for (i = 0; i < module_inst->export_func_count; i++) if (!strcmp(export_funcs[i].func_name, name)) @@ -1207,115 +1329,6 @@ aot_lookup_function(const AOTModuleInstance *module_inst, const char *name, #ifdef OS_ENABLE_HW_BOUND_CHECK -#ifndef BH_PLATFORM_WINDOWS -void -aot_signal_handler(WASMSignalInfo *sig_info) -{ - WASMExecEnv *exec_env_tls = sig_info->exec_env_tls; - void *sig_addr = sig_info->sig_addr; - AOTModuleInstance *module_inst; - AOTMemoryInstance *memory_inst; - WASMJmpBuf *jmpbuf_node; - uint8 *mapped_mem_start_addr = NULL; - uint8 *mapped_mem_end_addr = NULL; - uint8 *stack_min_addr; - uint32 page_size; - uint32 guard_page_count = STACK_OVERFLOW_CHECK_GUARD_PAGE_COUNT; - - /* Check whether current thread is running aot function */ - if (exec_env_tls && exec_env_tls->handle == os_self_thread() - && (jmpbuf_node = exec_env_tls->jmpbuf_stack_top)) { - /* Get mapped mem info of current instance */ - module_inst = (AOTModuleInstance *)exec_env_tls->module_inst; - /* Get the default memory instance */ - memory_inst = aot_get_default_memory(module_inst); - if (memory_inst) { - mapped_mem_start_addr = (uint8 *)memory_inst->memory_data.ptr; - mapped_mem_end_addr = - (uint8 *)memory_inst->memory_data.ptr + 8 * (uint64)BH_GB; - } - - /* Get stack info of current thread */ - page_size = os_getpagesize(); - stack_min_addr = os_thread_get_stack_boundary(); - - if (memory_inst - && (mapped_mem_start_addr <= (uint8 *)sig_addr - && (uint8 *)sig_addr < mapped_mem_end_addr)) { - /* The address which causes segmentation fault is inside - the memory instance's guard regions */ - aot_set_exception_with_id(module_inst, - EXCE_OUT_OF_BOUNDS_MEMORY_ACCESS); - os_longjmp(jmpbuf_node->jmpbuf, 1); - } - else if (stack_min_addr - page_size <= (uint8 *)sig_addr - && (uint8 *)sig_addr - < stack_min_addr + page_size * guard_page_count) { - /* The address which causes segmentation fault is inside - native thread's guard page */ - aot_set_exception_with_id(module_inst, EXCE_NATIVE_STACK_OVERFLOW); - os_longjmp(jmpbuf_node->jmpbuf, 1); - } - } -} -#else /* else of BH_PLATFORM_WINDOWS */ -LONG -aot_exception_handler(WASMSignalInfo *sig_info) -{ - WASMExecEnv *exec_env_tls = sig_info->exec_env_tls; - EXCEPTION_POINTERS *exce_info = sig_info->exce_info; - PEXCEPTION_RECORD ExceptionRecord = exce_info->ExceptionRecord; - uint8 *sig_addr = (uint8 *)ExceptionRecord->ExceptionInformation[1]; - AOTModuleInstance *module_inst; - AOTMemoryInstance *memory_inst; - WASMJmpBuf *jmpbuf_node; - uint8 *mapped_mem_start_addr = NULL; - uint8 *mapped_mem_end_addr = NULL; - uint32 page_size = os_getpagesize(); - - if (exec_env_tls && exec_env_tls->handle == os_self_thread() - && (jmpbuf_node = exec_env_tls->jmpbuf_stack_top)) { - module_inst = (AOTModuleInstance *)exec_env_tls->module_inst; - if (ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) { - /* Get the default memory instance */ - memory_inst = aot_get_default_memory(module_inst); - if (memory_inst) { - mapped_mem_start_addr = (uint8 *)memory_inst->memory_data.ptr; - mapped_mem_end_addr = - (uint8 *)memory_inst->memory_data.ptr + 8 * (uint64)BH_GB; - if (mapped_mem_start_addr <= (uint8 *)sig_addr - && (uint8 *)sig_addr < mapped_mem_end_addr) { - /* The address which causes segmentation fault is inside - aot instance's guard regions. - Set exception and let the aot func continue to run, when - the aot func returns, the caller will check whether the - exception is thrown and return to runtime. */ - aot_set_exception_with_id(module_inst, - EXCE_OUT_OF_BOUNDS_MEMORY_ACCESS); - /* Skip current instruction */ - exce_info->ContextRecord->Rip++; - return EXCEPTION_CONTINUE_EXECUTION; - } - } - } - else if (ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW) { - /* Set stack overflow exception and let the aot func continue - to run, when the aot func returns, the caller will check - whether the exception is thrown and return to runtime, and - the damaged stack will be recovered by _resetstkoflw(). */ - aot_set_exception_with_id(module_inst, EXCE_NATIVE_STACK_OVERFLOW); - return EXCEPTION_CONTINUE_EXECUTION; - } - } - - os_printf("Unhandled exception thrown: exception code: 0x%lx, " - "exception address: %p, exception information: %p\n", - ExceptionRecord->ExceptionCode, ExceptionRecord->ExceptionAddress, - sig_addr); - return EXCEPTION_CONTINUE_SEARCH; -} -#endif /* end of BH_PLATFORM_WINDOWS */ - static bool invoke_native_with_hw_bound_check(WASMExecEnv *exec_env, void *func_ptr, const WASMType *func_type, @@ -1331,14 +1344,16 @@ invoke_native_with_hw_bound_check(WASMExecEnv *exec_env, void *func_ptr, uint16 result_count = func_type->result_count; const uint8 *types = func_type->types; #ifdef BH_PLATFORM_WINDOWS - const char *exce; int result; + bool has_exception; + char exception[EXCEPTION_BUF_LEN]; #endif bool ret; /* Check native stack overflow firstly to ensure we have enough native stack to run the following codes before actually calling the aot function in invokeNative function. */ + RECORD_STACK_USAGE(exec_env, (uint8 *)&module_inst); if ((uint8 *)&module_inst < exec_env->native_stack_boundary + page_size * (guard_page_count + 1)) { aot_set_exception_with_id(module_inst, EXCE_NATIVE_STACK_OVERFLOW); @@ -1365,14 +1380,14 @@ invoke_native_with_hw_bound_check(WASMExecEnv *exec_env, void *func_ptr, void (*NativeFunc)(WASMExecEnv *, uint32) = (void (*)(WASMExecEnv *, uint32))func_ptr; NativeFunc(exec_env, argv[0]); - ret = aot_get_exception(module_inst) ? false : true; + ret = aot_copy_exception(module_inst, NULL) ? false : true; } else if (result_count == 1 && types[param_count] == VALUE_TYPE_I32) { uint32 (*NativeFunc)(WASMExecEnv *, uint32) = (uint32(*)(WASMExecEnv *, uint32))func_ptr; argv_ret[0] = NativeFunc(exec_env, argv[0]); - ret = aot_get_exception(module_inst) ? false : true; + ret = aot_copy_exception(module_inst, NULL) ? false : true; } else { ret = wasm_runtime_invoke_native(exec_env, func_ptr, func_type, @@ -1386,8 +1401,8 @@ invoke_native_with_hw_bound_check(WASMExecEnv *exec_env, void *func_ptr, argv_ret); } #ifdef BH_PLATFORM_WINDOWS - if ((exce = aot_get_exception(module_inst)) - && strstr(exce, "native stack overflow")) { + has_exception = aot_copy_exception(module_inst, exception); + if (has_exception && strstr(exception, "native stack overflow")) { /* After a stack overflow, the stack was left in a damaged state, let the CRT repair it */ result = _resetstkoflw(); @@ -1438,16 +1453,8 @@ aot_call_function(WASMExecEnv *exec_env, AOTFunctionInstance *function, } argc = func_type->param_cell_num; -#if WASM_ENABLE_LAZY_JIT != 0 - if (!function->u.func.func_ptr) { - AOTModule *aot_module = (AOTModule *)module_inst->aot_module.ptr; - if (!(function->u.func.func_ptr = - aot_lookup_orcjit_func(aot_module->comp_ctx->orc_lazyjit, - module_inst, function->func_index))) { - return false; - } - } -#endif + /* func pointer was looked up previously */ + bh_assert(function->u.func.func_ptr != NULL); /* set thread handle and stack boundary */ wasm_exec_env_set_thread_info(exec_env); @@ -1498,13 +1505,6 @@ aot_call_function(WASMExecEnv *exec_env, AOTFunctionInstance *function, ret = invoke_native_internal(exec_env, function->u.func.func_ptr, func_type, NULL, NULL, argv1, argc, argv); - if (!ret || aot_get_exception(module_inst)) { - if (clear_wasi_proc_exit_exception(module_inst)) - ret = true; - else - ret = false; - } - #if WASM_ENABLE_DUMP_CALL_STACK != 0 if (!ret) { if (aot_create_call_stack(exec_env)) { @@ -1564,11 +1564,8 @@ aot_call_function(WASMExecEnv *exec_env, AOTFunctionInstance *function, ret = invoke_native_internal(exec_env, function->u.func.func_ptr, func_type, NULL, NULL, argv, argc, argv); - if (clear_wasi_proc_exit_exception(module_inst)) - ret = true; - #if WASM_ENABLE_DUMP_CALL_STACK != 0 - if (aot_get_exception(module_inst)) { + if (aot_copy_exception(module_inst, NULL)) { if (aot_create_call_stack(exec_env)) { aot_dump_call_stack(exec_env, true, NULL, 0); } @@ -1579,128 +1576,42 @@ aot_call_function(WASMExecEnv *exec_env, AOTFunctionInstance *function, aot_free_frame(exec_env); #endif - return ret && !aot_get_exception(module_inst) ? true : false; - } -} - -bool -aot_create_exec_env_and_call_function(AOTModuleInstance *module_inst, - AOTFunctionInstance *func, unsigned argc, - uint32 argv[]) -{ - WASMExecEnv *exec_env = NULL, *existing_exec_env = NULL; - bool ret; - -#if defined(OS_ENABLE_HW_BOUND_CHECK) - existing_exec_env = exec_env = wasm_runtime_get_exec_env_tls(); -#elif WASM_ENABLE_THREAD_MGR != 0 - existing_exec_env = exec_env = - wasm_clusters_search_exec_env((WASMModuleInstanceCommon *)module_inst); -#endif - - if (!existing_exec_env) { - if (!(exec_env = - wasm_exec_env_create((WASMModuleInstanceCommon *)module_inst, - module_inst->default_wasm_stack_size))) { - aot_set_exception(module_inst, "allocate memory failed"); - return false; - } + return ret && !aot_copy_exception(module_inst, NULL) ? true : false; } - - ret = aot_call_function(exec_env, func, argc, argv); - - /* don't destroy the exec_env if it isn't created in this function */ - if (!existing_exec_env) - wasm_exec_env_destroy(exec_env); - - return ret; } void aot_set_exception(AOTModuleInstance *module_inst, const char *exception) { - if (exception) - snprintf(module_inst->cur_exception, sizeof(module_inst->cur_exception), - "Exception: %s", exception); - else - module_inst->cur_exception[0] = '\0'; + wasm_set_exception(module_inst, exception); } void aot_set_exception_with_id(AOTModuleInstance *module_inst, uint32 id) { - switch (id) { - case EXCE_UNREACHABLE: - aot_set_exception(module_inst, "unreachable"); - break; - case EXCE_OUT_OF_MEMORY: - aot_set_exception(module_inst, "allocate memory failed"); - break; - case EXCE_OUT_OF_BOUNDS_MEMORY_ACCESS: - aot_set_exception(module_inst, "out of bounds memory access"); - break; - case EXCE_INTEGER_OVERFLOW: - aot_set_exception(module_inst, "integer overflow"); - break; - case EXCE_INTEGER_DIVIDE_BY_ZERO: - aot_set_exception(module_inst, "integer divide by zero"); - break; - case EXCE_INVALID_CONVERSION_TO_INTEGER: - aot_set_exception(module_inst, "invalid conversion to integer"); - break; - case EXCE_INVALID_FUNCTION_TYPE_INDEX: - aot_set_exception(module_inst, "indirect call type mismatch"); - break; - case EXCE_INVALID_FUNCTION_INDEX: - aot_set_exception(module_inst, "invalid function index"); - break; - case EXCE_UNDEFINED_ELEMENT: - aot_set_exception(module_inst, "undefined element"); - break; - case EXCE_UNINITIALIZED_ELEMENT: - aot_set_exception(module_inst, "uninitialized element"); - break; - case EXCE_CALL_UNLINKED_IMPORT_FUNC: - aot_set_exception(module_inst, - "failed to call unlinked import function"); - break; - case EXCE_NATIVE_STACK_OVERFLOW: - aot_set_exception(module_inst, "native stack overflow"); - break; - case EXCE_UNALIGNED_ATOMIC: - aot_set_exception(module_inst, "unaligned atomic"); - break; - case EXCE_AUX_STACK_OVERFLOW: - aot_set_exception(module_inst, "wasm auxiliary stack overflow"); - break; - case EXCE_AUX_STACK_UNDERFLOW: - aot_set_exception(module_inst, "wasm auxiliary stack underflow"); - break; - case EXCE_OUT_OF_BOUNDS_TABLE_ACCESS: - aot_set_exception(module_inst, "out of bounds table access"); - break; - default: - break; - } + if (id != EXCE_ALREADY_THROWN) + wasm_set_exception_with_id(module_inst, id); +#ifdef OS_ENABLE_HW_BOUND_CHECK + wasm_runtime_access_exce_check_guard_page(); +#endif } const char * aot_get_exception(AOTModuleInstance *module_inst) { - if (module_inst->cur_exception[0] == '\0') - return NULL; - else - return module_inst->cur_exception; + return wasm_get_exception(module_inst); } -void -aot_clear_exception(AOTModuleInstance *module_inst) +bool +aot_copy_exception(AOTModuleInstance *module_inst, char *exception_buf) { - module_inst->cur_exception[0] = '\0'; + /* The field offsets of cur_exception in AOTModuleInstance and + WASMModuleInstance are the same */ + return wasm_copy_exception(module_inst, exception_buf); } static bool -execute_malloc_function(AOTModuleInstance *module_inst, +execute_malloc_function(AOTModuleInstance *module_inst, WASMExecEnv *exec_env, AOTFunctionInstance *malloc_func, AOTFunctionInstance *retain_func, uint32 size, uint32 *p_result) @@ -1708,6 +1619,8 @@ execute_malloc_function(AOTModuleInstance *module_inst, #ifdef OS_ENABLE_HW_BOUND_CHECK WASMExecEnv *exec_env_tls = wasm_runtime_get_exec_env_tls(); #endif + WASMExecEnv *exec_env_created = NULL; + WASMModuleInstanceCommon *module_inst_old = NULL; uint32 argv[2], argc; bool ret; @@ -1718,63 +1631,128 @@ execute_malloc_function(AOTModuleInstance *module_inst, argc = 2; } + if (exec_env) { #ifdef OS_ENABLE_HW_BOUND_CHECK - if (exec_env_tls != NULL) { - bh_assert(exec_env_tls->module_inst - == (WASMModuleInstanceCommon *)module_inst); - ret = aot_call_function(exec_env_tls, malloc_func, argc, argv); - - if (retain_func && ret) { - ret = aot_call_function(exec_env_tls, retain_func, 1, argv); + if (exec_env_tls) { + bh_assert(exec_env_tls == exec_env); } +#endif + bh_assert(exec_env->module_inst + == (WASMModuleInstanceCommon *)module_inst); } - else + else { + /* Try using the existing exec_env */ +#ifdef OS_ENABLE_HW_BOUND_CHECK + exec_env = exec_env_tls; #endif - { - ret = aot_create_exec_env_and_call_function(module_inst, malloc_func, - argc, argv); - - if (retain_func && ret) { - ret = aot_create_exec_env_and_call_function(module_inst, - retain_func, 1, argv); +#if WASM_ENABLE_THREAD_MGR != 0 + if (!exec_env) + exec_env = wasm_clusters_search_exec_env( + (WASMModuleInstanceCommon *)module_inst); +#endif + if (!exec_env) { + if (!(exec_env = exec_env_created = wasm_exec_env_create( + (WASMModuleInstanceCommon *)module_inst, + module_inst->default_wasm_stack_size))) { + wasm_set_exception(module_inst, "allocate memory failed"); + return false; + } + } + else { + /* Temporarily replace exec_env's module inst with current + module inst to ensure that the exec_env's module inst + is the correct one. */ + module_inst_old = exec_env->module_inst; + exec_env->module_inst = (WASMModuleInstanceCommon *)module_inst; } } + ret = aot_call_function(exec_env, malloc_func, argc, argv); + + if (retain_func && ret) + ret = aot_call_function(exec_env, retain_func, 1, argv); + + if (module_inst_old) + /* Restore the existing exec_env's module inst */ + exec_env->module_inst = module_inst_old; + + if (exec_env_created) + wasm_exec_env_destroy(exec_env_created); + if (ret) *p_result = argv[0]; return ret; } static bool -execute_free_function(AOTModuleInstance *module_inst, +execute_free_function(AOTModuleInstance *module_inst, WASMExecEnv *exec_env, AOTFunctionInstance *free_func, uint32 offset) { #ifdef OS_ENABLE_HW_BOUND_CHECK WASMExecEnv *exec_env_tls = wasm_runtime_get_exec_env_tls(); #endif + WASMExecEnv *exec_env_created = NULL; + WASMModuleInstanceCommon *module_inst_old = NULL; uint32 argv[2]; + bool ret; argv[0] = offset; + + if (exec_env) { #ifdef OS_ENABLE_HW_BOUND_CHECK - if (exec_env_tls != NULL) { - bh_assert(exec_env_tls->module_inst + if (exec_env_tls) { + bh_assert(exec_env_tls == exec_env); + } +#endif + bh_assert(exec_env->module_inst == (WASMModuleInstanceCommon *)module_inst); - return aot_call_function(exec_env_tls, free_func, 1, argv); } - else + else { + /* Try using the existing exec_env */ +#ifdef OS_ENABLE_HW_BOUND_CHECK + exec_env = exec_env_tls; #endif - { - return aot_create_exec_env_and_call_function(module_inst, free_func, 1, - argv); +#if WASM_ENABLE_THREAD_MGR != 0 + if (!exec_env) + exec_env = wasm_clusters_search_exec_env( + (WASMModuleInstanceCommon *)module_inst); +#endif + if (!exec_env) { + if (!(exec_env = exec_env_created = wasm_exec_env_create( + (WASMModuleInstanceCommon *)module_inst, + module_inst->default_wasm_stack_size))) { + wasm_set_exception(module_inst, "allocate memory failed"); + return false; + } + } + else { + /* Temporarily replace exec_env's module inst with current + module inst to ensure that the exec_env's module inst + is the correct one. */ + module_inst_old = exec_env->module_inst; + exec_env->module_inst = (WASMModuleInstanceCommon *)module_inst; + } } + + ret = aot_call_function(exec_env, free_func, 1, argv); + + if (module_inst_old) + /* Restore the existing exec_env's module inst */ + exec_env->module_inst = module_inst_old; + + if (exec_env_created) + wasm_exec_env_destroy(exec_env_created); + + return ret; } uint32 -aot_module_malloc(AOTModuleInstance *module_inst, uint32 size, - void **p_native_addr) +aot_module_malloc_internal(AOTModuleInstance *module_inst, + WASMExecEnv *exec_env, uint32 size, + void **p_native_addr) { AOTMemoryInstance *memory_inst = aot_get_default_memory(module_inst); - AOTModule *module = (AOTModule *)module_inst->aot_module.ptr; + AOTModule *module = (AOTModule *)module_inst->module; uint8 *addr = NULL; uint32 offset = 0; @@ -1783,8 +1761,8 @@ aot_module_malloc(AOTModuleInstance *module_inst, uint32 size, return 0; } - if (memory_inst->heap_handle.ptr) { - addr = mem_allocator_malloc(memory_inst->heap_handle.ptr, size); + if (memory_inst->heap_handle) { + addr = mem_allocator_malloc(memory_inst->heap_handle, size); } else if (module->malloc_func_index != (uint32)-1 && module->free_func_index != (uint32)-1) { @@ -1808,16 +1786,16 @@ aot_module_malloc(AOTModuleInstance *module_inst, uint32 size, aot_lookup_function(module_inst, malloc_func_name, malloc_func_sig); if (!malloc_func - || !execute_malloc_function(module_inst, malloc_func, retain_func, - size, &offset)) { + || !execute_malloc_function(module_inst, exec_env, malloc_func, + retain_func, size, &offset)) { return 0; } - addr = offset ? (uint8 *)memory_inst->memory_data.ptr + offset : NULL; + addr = offset ? (uint8 *)memory_inst->memory_data + offset : NULL; } if (!addr) { - if (memory_inst->heap_handle.ptr - && mem_allocator_is_heap_corrupted(memory_inst->heap_handle.ptr)) { + if (memory_inst->heap_handle + && mem_allocator_is_heap_corrupted(memory_inst->heap_handle)) { wasm_runtime_show_app_heap_corrupted_prompt(); aot_set_exception(module_inst, "app heap corrupted"); } @@ -1828,12 +1806,13 @@ aot_module_malloc(AOTModuleInstance *module_inst, uint32 size, } if (p_native_addr) *p_native_addr = addr; - return (uint32)(addr - (uint8 *)memory_inst->memory_data.ptr); + return (uint32)(addr - memory_inst->memory_data); } uint32 -aot_module_realloc(AOTModuleInstance *module_inst, uint32 ptr, uint32 size, - void **p_native_addr) +aot_module_realloc_internal(AOTModuleInstance *module_inst, + WASMExecEnv *exec_env, uint32 ptr, uint32 size, + void **p_native_addr) { AOTMemoryInstance *memory_inst = aot_get_default_memory(module_inst); uint8 *addr = NULL; @@ -1843,17 +1822,18 @@ aot_module_realloc(AOTModuleInstance *module_inst, uint32 ptr, uint32 size, return 0; } - if (memory_inst->heap_handle.ptr) { + if (memory_inst->heap_handle) { addr = mem_allocator_realloc( - memory_inst->heap_handle.ptr, - ptr ? (uint8 *)memory_inst->memory_data.ptr + ptr : NULL, size); + memory_inst->heap_handle, + ptr ? memory_inst->memory_data + ptr : NULL, size); } /* Only support realloc in WAMR's app heap */ + (void)exec_env; if (!addr) { - if (memory_inst->heap_handle.ptr - && mem_allocator_is_heap_corrupted(memory_inst->heap_handle.ptr)) { + if (memory_inst->heap_handle + && mem_allocator_is_heap_corrupted(memory_inst->heap_handle)) { aot_set_exception(module_inst, "app heap corrupted"); } else { @@ -1864,30 +1844,30 @@ aot_module_realloc(AOTModuleInstance *module_inst, uint32 ptr, uint32 size, if (p_native_addr) *p_native_addr = addr; - return (uint32)(addr - (uint8 *)memory_inst->memory_data.ptr); + return (uint32)(addr - memory_inst->memory_data); } void -aot_module_free(AOTModuleInstance *module_inst, uint32 ptr) +aot_module_free_internal(AOTModuleInstance *module_inst, WASMExecEnv *exec_env, + uint32 ptr) { AOTMemoryInstance *memory_inst = aot_get_default_memory(module_inst); - AOTModule *module = (AOTModule *)module_inst->aot_module.ptr; + AOTModule *module = (AOTModule *)module_inst->module; if (!memory_inst) { return; } if (ptr) { - uint8 *addr = (uint8 *)memory_inst->memory_data.ptr + ptr; - if (memory_inst->heap_handle.ptr - && (uint8 *)memory_inst->heap_data.ptr < addr - && addr < (uint8 *)memory_inst->heap_data_end.ptr) { - mem_allocator_free(memory_inst->heap_handle.ptr, addr); + uint8 *addr = memory_inst->memory_data + ptr; + if (memory_inst->heap_handle && memory_inst->heap_data < addr + && addr < memory_inst->heap_data_end) { + mem_allocator_free(memory_inst->heap_handle, addr); } else if (module->malloc_func_index != (uint32)-1 && module->free_func_index != (uint32)-1 - && (uint8 *)memory_inst->memory_data.ptr <= addr - && addr < (uint8 *)memory_inst->memory_data_end.ptr) { + && memory_inst->memory_data <= addr + && addr < memory_inst->memory_data_end) { AOTFunctionInstance *free_func; char *free_func_name; @@ -1903,345 +1883,53 @@ aot_module_free(AOTModuleInstance *module_inst, uint32 ptr) free_func = aot_lookup_function(module_inst, "__unpin", "(i)i"); if (free_func) - execute_free_function(module_inst, free_func, ptr); + execute_free_function(module_inst, exec_env, free_func, ptr); } } } uint32 -aot_module_dup_data(AOTModuleInstance *module_inst, const char *src, - uint32 size) -{ - char *buffer; - uint32 buffer_offset = - aot_module_malloc(module_inst, size, (void **)&buffer); - - if (buffer_offset != 0) { - buffer = aot_addr_app_to_native(module_inst, buffer_offset); - bh_memcpy_s(buffer, size, src, size); - } - return buffer_offset; -} - -bool -aot_validate_app_addr(AOTModuleInstance *module_inst, uint32 app_offset, - uint32 size) -{ - AOTMemoryInstance *memory_inst = aot_get_default_memory(module_inst); - - if (!memory_inst) { - goto fail; - } - - /* integer overflow check */ - if (app_offset > UINT32_MAX - size) { - goto fail; - } - - if (app_offset + size <= memory_inst->memory_data_size) { - return true; - } -fail: - aot_set_exception(module_inst, "out of bounds memory access"); - return false; -} - -bool -aot_validate_native_addr(AOTModuleInstance *module_inst, void *native_ptr, - uint32 size) -{ - AOTMemoryInstance *memory_inst = aot_get_default_memory(module_inst); - uint8 *addr = (uint8 *)native_ptr; - - if (!memory_inst) { - goto fail; - } - - /* integer overflow check */ - if ((uintptr_t)addr > UINTPTR_MAX - size) { - goto fail; - } - - if ((uint8 *)memory_inst->memory_data.ptr <= addr - && addr + size <= (uint8 *)memory_inst->memory_data_end.ptr) - return true; -fail: - aot_set_exception(module_inst, "out of bounds memory access"); - return false; -} - -void * -aot_addr_app_to_native(AOTModuleInstance *module_inst, uint32 app_offset) +aot_module_malloc(AOTModuleInstance *module_inst, uint32 size, + void **p_native_addr) { - AOTMemoryInstance *memory_inst = aot_get_default_memory(module_inst); - uint8 *addr; - - if (!memory_inst) { - return NULL; - } - - addr = (uint8 *)memory_inst->memory_data.ptr + app_offset; - - if ((uint8 *)memory_inst->memory_data.ptr <= addr - && addr < (uint8 *)memory_inst->memory_data_end.ptr) - return addr; - return NULL; + return aot_module_malloc_internal(module_inst, NULL, size, p_native_addr); } uint32 -aot_addr_native_to_app(AOTModuleInstance *module_inst, void *native_ptr) +aot_module_realloc(AOTModuleInstance *module_inst, uint32 ptr, uint32 size, + void **p_native_addr) { - AOTMemoryInstance *memory_inst = aot_get_default_memory(module_inst); - uint8 *addr = (uint8 *)native_ptr; - - if (!memory_inst) { - return 0; - } - - if ((uint8 *)memory_inst->memory_data.ptr <= addr - && addr < (uint8 *)memory_inst->memory_data_end.ptr) - return (uint32)(addr - (uint8 *)memory_inst->memory_data.ptr); - return 0; + return aot_module_realloc_internal(module_inst, NULL, ptr, size, + p_native_addr); } -bool -aot_get_app_addr_range(AOTModuleInstance *module_inst, uint32 app_offset, - uint32 *p_app_start_offset, uint32 *p_app_end_offset) +void +aot_module_free(AOTModuleInstance *module_inst, uint32 ptr) { - AOTMemoryInstance *memory_inst = aot_get_default_memory(module_inst); - uint32 memory_data_size; - - if (!memory_inst) { - return false; - } - - memory_data_size = memory_inst->memory_data_size; - - if (app_offset < memory_data_size) { - if (p_app_start_offset) - *p_app_start_offset = 0; - if (p_app_end_offset) - *p_app_end_offset = memory_data_size; - return true; - } - return false; + aot_module_free_internal(module_inst, NULL, ptr); } -bool -aot_get_native_addr_range(AOTModuleInstance *module_inst, uint8 *native_ptr, - uint8 **p_native_start_addr, - uint8 **p_native_end_addr) +uint32 +aot_module_dup_data(AOTModuleInstance *module_inst, const char *src, + uint32 size) { - AOTMemoryInstance *memory_inst = aot_get_default_memory(module_inst); - uint8 *addr = (uint8 *)native_ptr; - - if (!memory_inst) { - return false; - } + char *buffer; + uint32 buffer_offset = + aot_module_malloc(module_inst, size, (void **)&buffer); - if ((uint8 *)memory_inst->memory_data.ptr <= addr - && addr < (uint8 *)memory_inst->memory_data_end.ptr) { - if (p_native_start_addr) - *p_native_start_addr = (uint8 *)memory_inst->memory_data.ptr; - if (p_native_end_addr) - *p_native_end_addr = (uint8 *)memory_inst->memory_data_end.ptr; - return true; + if (buffer_offset != 0) { + buffer = wasm_runtime_addr_app_to_native( + (WASMModuleInstanceCommon *)module_inst, buffer_offset); + bh_memcpy_s(buffer, size, src, size); } - return false; + return buffer_offset; } -#ifndef OS_ENABLE_HW_BOUND_CHECK -bool -aot_enlarge_memory(AOTModuleInstance *module_inst, uint32 inc_page_count) -{ - AOTMemoryInstance *memory = aot_get_default_memory(module_inst); - uint8 *memory_data_old, *memory_data_new, *heap_data_old; - uint32 num_bytes_per_page, heap_size, total_size_old; - uint32 cur_page_count, max_page_count, total_page_count; - uint64 total_size_new; - bool ret = true; - - if (!memory) - return false; - - heap_data_old = (uint8 *)memory->heap_data.ptr; - heap_size = (uint32)((uint8 *)memory->heap_data_end.ptr - - (uint8 *)memory->heap_data.ptr); - - memory_data_old = (uint8 *)memory->memory_data.ptr; - total_size_old = - (uint32)((uint8 *)memory->memory_data_end.ptr - memory_data_old); - - num_bytes_per_page = memory->num_bytes_per_page; - cur_page_count = memory->cur_page_count; - max_page_count = memory->max_page_count; - total_page_count = inc_page_count + cur_page_count; - total_size_new = num_bytes_per_page * (uint64)total_page_count; - - if (inc_page_count <= 0) - /* No need to enlarge memory */ - return true; - - if (total_page_count < cur_page_count /* integer overflow */ - || total_page_count > max_page_count) { - return false; - } - - bh_assert(total_size_new <= 4 * (uint64)BH_GB); - if (total_size_new > UINT32_MAX) { - /* Resize to 1 page with size 4G-1 */ - num_bytes_per_page = UINT32_MAX; - total_page_count = max_page_count = 1; - total_size_new = UINT32_MAX; - } - -#if WASM_ENABLE_SHARED_MEMORY != 0 - if (memory->is_shared) { - memory->num_bytes_per_page = num_bytes_per_page; - memory->cur_page_count = total_page_count; - memory->max_page_count = max_page_count; - /* No need to update memory->memory_data_size as it is - initialized with the maximum memory data size for - shared memory */ - return true; - } -#endif - - if (heap_size > 0) { - if (mem_allocator_is_heap_corrupted(memory->heap_handle.ptr)) { - wasm_runtime_show_app_heap_corrupted_prompt(); - return false; - } - } - - if (!(memory_data_new = - wasm_runtime_realloc(memory_data_old, (uint32)total_size_new))) { - if (!(memory_data_new = wasm_runtime_malloc((uint32)total_size_new))) { - return false; - } - if (memory_data_old) { - bh_memcpy_s(memory_data_new, (uint32)total_size_new, - memory_data_old, total_size_old); - wasm_runtime_free(memory_data_old); - } - } - - memset(memory_data_new + total_size_old, 0, - (uint32)total_size_new - total_size_old); - - if (heap_size > 0) { - if (mem_allocator_migrate(memory->heap_handle.ptr, - (char *)heap_data_old - + (memory_data_new - memory_data_old), - heap_size) - != 0) { - /* Don't return here as memory->memory_data is obsolete and - must be updated to be correctly used later. */ - ret = false; - } - } - - memory->heap_data.ptr = memory_data_new + (heap_data_old - memory_data_old); - memory->heap_data_end.ptr = (uint8 *)memory->heap_data.ptr + heap_size; - - memory->num_bytes_per_page = num_bytes_per_page; - memory->cur_page_count = total_page_count; - memory->max_page_count = max_page_count; - - memory->memory_data.ptr = memory_data_new; - memory->memory_data_end.ptr = memory_data_new + (uint32)total_size_new; - memory->memory_data_size = (uint32)total_size_new; - -#if UINTPTR_MAX == UINT64_MAX - memory->mem_bound_check_1byte.u64 = total_size_new - 1; - memory->mem_bound_check_2bytes.u64 = total_size_new - 2; - memory->mem_bound_check_4bytes.u64 = total_size_new - 4; - memory->mem_bound_check_8bytes.u64 = total_size_new - 8; - memory->mem_bound_check_16bytes.u64 = total_size_new - 16; -#else - memory->mem_bound_check_1byte.u32[0] = (uint32)total_size_new - 1; - memory->mem_bound_check_2bytes.u32[0] = (uint32)total_size_new - 2; - memory->mem_bound_check_4bytes.u32[0] = (uint32)total_size_new - 4; - memory->mem_bound_check_8bytes.u32[0] = (uint32)total_size_new - 8; - memory->mem_bound_check_16bytes.u32[0] = (uint32)total_size_new - 16; -#endif - - return ret; -} -#else /* else of OS_ENABLE_HW_BOUND_CHECK */ bool aot_enlarge_memory(AOTModuleInstance *module_inst, uint32 inc_page_count) { - AOTMemoryInstance *memory = aot_get_default_memory(module_inst); - uint32 num_bytes_per_page, total_size_old; - uint32 cur_page_count, max_page_count, total_page_count; - uint64 total_size_new; - - if (!memory) - return false; - - num_bytes_per_page = memory->num_bytes_per_page; - cur_page_count = memory->cur_page_count; - max_page_count = memory->max_page_count; - total_size_old = num_bytes_per_page * cur_page_count; - total_page_count = inc_page_count + cur_page_count; - total_size_new = num_bytes_per_page * (uint64)total_page_count; - - if (inc_page_count <= 0) - /* No need to enlarge memory */ - return true; - - if (total_page_count < cur_page_count /* integer overflow */ - || total_page_count > max_page_count) { - return false; - } - - bh_assert(total_size_new <= 4 * (uint64)BH_GB); - if (total_size_new > UINT32_MAX) { - /* Resize to 1 page with size 4G-1 */ - num_bytes_per_page = UINT32_MAX; - total_page_count = max_page_count = 1; - total_size_new = UINT32_MAX; - } - -#ifdef BH_PLATFORM_WINDOWS - if (!os_mem_commit(memory->memory_data_end.ptr, - (uint32)total_size_new - total_size_old, - MMAP_PROT_READ | MMAP_PROT_WRITE)) { - return false; - } -#endif - - if (os_mprotect(memory->memory_data_end.ptr, - (uint32)total_size_new - total_size_old, - MMAP_PROT_READ | MMAP_PROT_WRITE) - != 0) { -#ifdef BH_PLATFORM_WINDOWS - os_mem_decommit(memory->memory_data_end.ptr, - (uint32)total_size_new - total_size_old); -#endif - return false; - } - - /* The increased pages are filled with zero by the OS when os_mmap, - no need to memset it again here */ - - memory->num_bytes_per_page = num_bytes_per_page; - memory->cur_page_count = total_page_count; - memory->max_page_count = max_page_count; - memory->memory_data_size = (uint32)total_size_new; - memory->memory_data_end.ptr = - (uint8 *)memory->memory_data.ptr + (uint32)total_size_new; - - memory->mem_bound_check_1byte.u64 = total_size_new - 1; - memory->mem_bound_check_2bytes.u64 = total_size_new - 2; - memory->mem_bound_check_4bytes.u64 = total_size_new - 4; - memory->mem_bound_check_8bytes.u64 = total_size_new - 8; - memory->mem_bound_check_16bytes.u64 = total_size_new - 16; - - return true; + return wasm_enlarge_memory(module_inst, inc_page_count); } -#endif /* end of OS_ENABLE_HW_BOUND_CHECK */ bool aot_invoke_native(WASMExecEnv *exec_env, uint32 func_idx, uint32 argc, @@ -2249,46 +1937,64 @@ aot_invoke_native(WASMExecEnv *exec_env, uint32 func_idx, uint32 argc, { AOTModuleInstance *module_inst = (AOTModuleInstance *)wasm_runtime_get_module_inst(exec_env); - AOTModule *aot_module = (AOTModule *)module_inst->aot_module.ptr; - uint32 *func_type_indexes = (uint32 *)module_inst->func_type_indexes.ptr; + AOTModule *aot_module = (AOTModule *)module_inst->module; + AOTModuleInstanceExtra *module_inst_extra = + (AOTModuleInstanceExtra *)module_inst->e; + CApiFuncImport *c_api_func_import = + module_inst_extra->c_api_func_imports + ? module_inst_extra->c_api_func_imports + func_idx + : NULL; + uint32 *func_type_indexes = module_inst->func_type_indexes; uint32 func_type_idx = func_type_indexes[func_idx]; AOTFuncType *func_type = aot_module->func_types[func_type_idx]; - void **func_ptrs = (void **)module_inst->func_ptrs.ptr; + void **func_ptrs = module_inst->func_ptrs; void *func_ptr = func_ptrs[func_idx]; AOTImportFunc *import_func; const char *signature; void *attachment; char buf[96]; + bool ret = false; bh_assert(func_idx < aot_module->import_func_count); import_func = aot_module->import_funcs + func_idx; + if (import_func->call_conv_wasm_c_api) + func_ptr = + c_api_func_import ? c_api_func_import->func_ptr_linked : NULL; + if (!func_ptr) { snprintf(buf, sizeof(buf), "failed to call unlinked import function (%s, %s)", import_func->module_name, import_func->func_name); aot_set_exception(module_inst, buf); - return false; + goto fail; } attachment = import_func->attachment; if (import_func->call_conv_wasm_c_api) { - return wasm_runtime_invoke_c_api_native( + ret = wasm_runtime_invoke_c_api_native( (WASMModuleInstanceCommon *)module_inst, func_ptr, func_type, argc, - argv, import_func->wasm_c_api_with_env, attachment); + argv, c_api_func_import->with_env_arg, c_api_func_import->env_arg); } else if (!import_func->call_conv_raw) { signature = import_func->signature; - return wasm_runtime_invoke_native(exec_env, func_ptr, func_type, - signature, attachment, argv, argc, - argv); + ret = + wasm_runtime_invoke_native(exec_env, func_ptr, func_type, signature, + attachment, argv, argc, argv); } else { signature = import_func->signature; - return wasm_runtime_invoke_native_raw(exec_env, func_ptr, func_type, - signature, attachment, argv, argc, - argv); + ret = wasm_runtime_invoke_native_raw(exec_env, func_ptr, func_type, + signature, attachment, argv, argc, + argv); } + +fail: +#ifdef OS_ENABLE_HW_BOUND_CHECK + if (!ret) + wasm_runtime_access_exce_check_guard_page(); +#endif + return ret; } bool @@ -2297,11 +2003,11 @@ aot_call_indirect(WASMExecEnv *exec_env, uint32 tbl_idx, uint32 table_elem_idx, { AOTModuleInstance *module_inst = (AOTModuleInstance *)wasm_runtime_get_module_inst(exec_env); - AOTModule *aot_module = (AOTModule *)module_inst->aot_module.ptr; - uint32 *func_type_indexes = (uint32 *)module_inst->func_type_indexes.ptr; + AOTModule *aot_module = (AOTModule *)module_inst->module; + uint32 *func_type_indexes = module_inst->func_type_indexes; AOTTableInstance *tbl_inst; AOTFuncType *func_type; - void **func_ptrs = (void **)module_inst->func_ptrs.ptr, *func_ptr; + void **func_ptrs = module_inst->func_ptrs, *func_ptr; uint32 func_type_idx, func_idx, ext_ret_count; AOTImportFunc *import_func; const char *signature = NULL; @@ -2313,36 +2019,33 @@ aot_call_indirect(WASMExecEnv *exec_env, uint32 tbl_idx, uint32 table_elem_idx, exec_env->native_stack_boundary must have been set, we don't set it again */ + RECORD_STACK_USAGE(exec_env, (uint8 *)&module_inst); if ((uint8 *)&module_inst < exec_env->native_stack_boundary) { aot_set_exception_with_id(module_inst, EXCE_NATIVE_STACK_OVERFLOW); - return false; + goto fail; } - tbl_inst = aot_get_table_inst(module_inst, tbl_idx); + tbl_inst = module_inst->tables[tbl_idx]; bh_assert(tbl_inst); if (table_elem_idx >= tbl_inst->cur_size) { aot_set_exception_with_id(module_inst, EXCE_UNDEFINED_ELEMENT); - return false; + goto fail; } - func_idx = ((uint32 *)tbl_inst->data)[table_elem_idx]; - if (func_idx == (uint32)-1) { + func_idx = tbl_inst->elems[table_elem_idx]; + if (func_idx == NULL_REF) { aot_set_exception_with_id(module_inst, EXCE_UNINITIALIZED_ELEMENT); - return false; + goto fail; } func_type_idx = func_type_indexes[func_idx]; func_type = aot_module->func_types[func_type_idx]; -#if WASM_ENABLE_LAZY_JIT != 0 - if (func_idx >= aot_module->import_func_count && !func_ptrs[func_idx]) { - if (!(func_ptr = aot_lookup_orcjit_func( - aot_module->comp_ctx->orc_lazyjit, module_inst, func_idx))) { - return false; - } + if (func_idx >= aot_module->import_func_count) { + /* func pointer was looked up previously */ + bh_assert(func_ptrs[func_idx] != NULL); } -#endif if (!(func_ptr = func_ptrs[func_idx])) { bh_assert(func_idx < aot_module->import_func_count); @@ -2351,7 +2054,7 @@ aot_call_indirect(WASMExecEnv *exec_env, uint32 tbl_idx, uint32 table_elem_idx, "failed to call unlinked import function (%s, %s)", import_func->module_name, import_func->func_name); aot_set_exception(module_inst, buf); - return false; + goto fail; } if (func_idx < aot_module->import_func_count) { @@ -2360,9 +2063,13 @@ aot_call_indirect(WASMExecEnv *exec_env, uint32 tbl_idx, uint32 table_elem_idx, signature = import_func->signature; if (import_func->call_conv_raw) { attachment = import_func->attachment; - return wasm_runtime_invoke_native_raw(exec_env, func_ptr, func_type, - signature, attachment, argv, - argc, argv); + ret = wasm_runtime_invoke_native_raw(exec_env, func_ptr, func_type, + signature, attachment, argv, + argc, argv); + if (!ret) + goto fail; + + return true; } } @@ -2386,7 +2093,7 @@ aot_call_indirect(WASMExecEnv *exec_env, uint32 tbl_idx, uint32 table_elem_idx, && !(argv1 = runtime_malloc(size, module_inst->cur_exception, sizeof(module_inst->cur_exception)))) { aot_set_exception_with_id(module_inst, EXCE_OUT_OF_MEMORY); - return false; + goto fail; } /* Copy original arguments */ @@ -2405,12 +2112,10 @@ aot_call_indirect(WASMExecEnv *exec_env, uint32 tbl_idx, uint32 table_elem_idx, ret = invoke_native_internal(exec_env, func_ptr, func_type, signature, attachment, argv1, argc, argv); - if (!ret || aot_get_exception(module_inst)) { + if (!ret) { if (argv1 != argv1_buf) wasm_runtime_free(argv1); - if (clear_wasi_proc_exit_exception(module_inst)) - return true; - return false; + goto fail; } /* Get extra result values */ @@ -2449,60 +2154,35 @@ aot_call_indirect(WASMExecEnv *exec_env, uint32 tbl_idx, uint32 table_elem_idx, else { ret = invoke_native_internal(exec_env, func_ptr, func_type, signature, attachment, argv, argc, argv); - if (clear_wasi_proc_exit_exception(module_inst)) - return true; - return ret; + if (!ret) + goto fail; + + return true; } + +fail: +#ifdef OS_ENABLE_HW_BOUND_CHECK + wasm_runtime_access_exce_check_guard_page(); +#endif + return false; } -/** - * Check whether the app address and the buf is inside the linear memory, - * and convert the app address into native address - */ bool aot_check_app_addr_and_convert(AOTModuleInstance *module_inst, bool is_str, uint32 app_buf_addr, uint32 app_buf_size, void **p_native_addr) { - AOTMemoryInstance *memory_inst = aot_get_default_memory(module_inst); - uint8 *native_addr; - - if (!memory_inst) { - goto fail; - } - - native_addr = (uint8 *)memory_inst->memory_data.ptr + app_buf_addr; + bool ret; - /* No need to check the app_offset and buf_size if memory access - boundary check with hardware trap is enabled */ -#ifndef OS_ENABLE_HW_BOUND_CHECK - if (app_buf_addr >= memory_inst->memory_data_size) { - goto fail; - } + ret = wasm_check_app_addr_and_convert(module_inst, is_str, app_buf_addr, + app_buf_size, p_native_addr); - if (!is_str) { - if (app_buf_size > memory_inst->memory_data_size - app_buf_addr) { - goto fail; - } - } - else { - const char *str, *str_end; - - /* The whole string must be in the linear memory */ - str = (const char *)native_addr; - str_end = (const char *)memory_inst->memory_data_end.ptr; - while (str < str_end && *str != '\0') - str++; - if (str == str_end) - goto fail; - } +#ifdef OS_ENABLE_HW_BOUND_CHECK + if (!ret) + wasm_runtime_access_exce_check_guard_page(); #endif - *p_native_addr = (void *)native_addr; - return true; -fail: - aot_set_exception(module_inst, "out of bounds memory access"); - return false; + return ret; } void * @@ -2517,6 +2197,18 @@ aot_memset(void *s, int c, size_t n) return memset(s, c, n); } +double +aot_sqrt(double x) +{ + return sqrt(x); +} + +float +aot_sqrtf(float x) +{ + return sqrtf(x); +} + #if WASM_ENABLE_BULK_MEMORY != 0 bool aot_memory_init(AOTModuleInstance *module_inst, uint32 seg_index, uint32 offset, @@ -2528,20 +2220,12 @@ aot_memory_init(AOTModuleInstance *module_inst, uint32 seg_index, uint32 offset, uint8 *maddr; uint64 seg_len = 0; - aot_module = (AOTModule *)module_inst->aot_module.ptr; - if (aot_module->is_jit_mode) { -#if WASM_ENABLE_JIT != 0 - seg_len = - aot_module->wasm_module->data_segments[seg_index]->data_length; - data = aot_module->wasm_module->data_segments[seg_index]->data; -#endif - } - else { - seg_len = aot_module->mem_init_data_list[seg_index]->byte_count; - data = aot_module->mem_init_data_list[seg_index]->bytes; - } + aot_module = (AOTModule *)module_inst->module; + seg_len = aot_module->mem_init_data_list[seg_index]->byte_count; + data = aot_module->mem_init_data_list[seg_index]->bytes; - if (!aot_validate_app_addr(module_inst, dst, len)) + if (!wasm_runtime_validate_app_addr((WASMModuleInstanceCommon *)module_inst, + dst, len)) return false; if ((uint64)offset + (uint64)len > seg_len) { @@ -2549,7 +2233,8 @@ aot_memory_init(AOTModuleInstance *module_inst, uint32 seg_index, uint32 offset, return false; } - maddr = aot_addr_app_to_native(module_inst, dst); + maddr = wasm_runtime_addr_app_to_native( + (WASMModuleInstanceCommon *)module_inst, dst); bh_memcpy_s(maddr, memory_inst->memory_data_size - dst, data + offset, len); return true; @@ -2558,20 +2243,11 @@ aot_memory_init(AOTModuleInstance *module_inst, uint32 seg_index, uint32 offset, bool aot_data_drop(AOTModuleInstance *module_inst, uint32 seg_index) { - AOTModule *aot_module = (AOTModule *)(module_inst->aot_module.ptr); + AOTModule *aot_module = (AOTModule *)module_inst->module; - if (aot_module->is_jit_mode) { -#if WASM_ENABLE_JIT != 0 - aot_module->wasm_module->data_segments[seg_index]->data_length = 0; - /* Currently we can't free the dropped data segment - as they are stored in wasm bytecode */ -#endif - } - else { - aot_module->mem_init_data_list[seg_index]->byte_count = 0; - /* Currently we can't free the dropped data segment - as the mem_init_data_count is a continuous array */ - } + aot_module->mem_init_data_list[seg_index]->byte_count = 0; + /* Currently we can't free the dropped data segment + as the mem_init_data_count is a continuous array */ return true; } #endif /* WASM_ENABLE_BULK_MEMORY */ @@ -2581,7 +2257,7 @@ bool aot_set_aux_stack(WASMExecEnv *exec_env, uint32 start_offset, uint32 size) { AOTModuleInstance *module_inst = (AOTModuleInstance *)exec_env->module_inst; - AOTModule *module = (AOTModule *)module_inst->aot_module.ptr; + AOTModule *module = (AOTModule *)module_inst->module; uint32 stack_top_idx = module->aux_stack_top_global_index; uint32 data_end = module->aux_data_end; @@ -2597,8 +2273,7 @@ aot_set_aux_stack(WASMExecEnv *exec_env, uint32 start_offset, uint32 size) /* The aux stack top is a wasm global, set the initial value for the global */ uint32 global_offset = module->globals[stack_top_idx].data_offset; - uint8 *global_addr = - (uint8 *)module_inst->global_data.ptr + global_offset; + uint8 *global_addr = module_inst->global_data + global_offset; *(int32 *)global_addr = start_offset; /* The aux stack boundary is a constant value, @@ -2615,7 +2290,7 @@ bool aot_get_aux_stack(WASMExecEnv *exec_env, uint32 *start_offset, uint32 *size) { AOTModuleInstance *module_inst = (AOTModuleInstance *)exec_env->module_inst; - AOTModule *module = (AOTModule *)module_inst->aot_module.ptr; + AOTModule *module = (AOTModule *)module_inst->module; /* The aux stack information is resolved in loader and store in module */ @@ -2738,31 +2413,31 @@ aot_get_module_inst_mem_consumption(const AOTModuleInstance *module_inst, mem_conspn->module_inst_struct_size = sizeof(AOTModuleInstance); mem_conspn->memories_size = - sizeof(AOTPointer) * module_inst->memory_count + sizeof(void *) * module_inst->memory_count + sizeof(AOTMemoryInstance) * module_inst->memory_count; for (i = 0; i < module_inst->memory_count; i++) { - AOTMemoryInstance *mem_inst = - ((AOTMemoryInstance **)module_inst->memories.ptr)[i]; + AOTMemoryInstance *mem_inst = module_inst->memories[i]; mem_conspn->memories_size += mem_inst->num_bytes_per_page * mem_inst->cur_page_count; - mem_conspn->app_heap_size = (uint8 *)mem_inst->heap_data_end.ptr - - (uint8 *)mem_inst->heap_data.ptr; + mem_conspn->app_heap_size = + mem_inst->heap_data_end - mem_inst->heap_data; /* size of app heap structure */ mem_conspn->memories_size += mem_allocator_get_heap_struct_size(); } - tbl_inst = module_inst->tables.ptr; + mem_conspn->tables_size += + sizeof(AOTTableInstance *) * module_inst->table_count; for (i = 0; i < module_inst->table_count; i++) { - mem_conspn->tables_size += offsetof(AOTTableInstance, data); + tbl_inst = module_inst->tables[i]; + mem_conspn->tables_size += offsetof(AOTTableInstance, elems); mem_conspn->tables_size += sizeof(uint32) * tbl_inst->max_size; - tbl_inst = aot_next_tbl_inst(tbl_inst); } /* func_ptrs and func_type_indexes */ mem_conspn->functions_size = (sizeof(void *) + sizeof(uint32)) - * (((AOTModule *)module_inst->aot_module.ptr)->import_func_count - + ((AOTModule *)module_inst->aot_module.ptr)->func_count); + * (((AOTModule *)module_inst->module)->import_func_count + + ((AOTModule *)module_inst->module)->func_count); mem_conspn->globals_size = module_inst->global_data_size; @@ -2783,7 +2458,7 @@ aot_get_module_inst_mem_consumption(const AOTModuleInstance *module_inst, void aot_drop_table_seg(AOTModuleInstance *module_inst, uint32 tbl_seg_idx) { - AOTModule *module = (AOTModule *)module_inst->aot_module.ptr; + AOTModule *module = (AOTModule *)module_inst->module; AOTTableInitData *tbl_seg = module->table_init_data_list[tbl_seg_idx]; tbl_seg->is_dropped = true; } @@ -2795,9 +2470,9 @@ aot_table_init(AOTModuleInstance *module_inst, uint32 tbl_idx, { AOTTableInstance *tbl_inst; AOTTableInitData *tbl_seg; - const AOTModule *module = module_inst->aot_module.ptr; + const AOTModule *module = (AOTModule *)module_inst->module; - tbl_inst = aot_get_table_inst(module_inst, tbl_idx); + tbl_inst = module_inst->tables[tbl_idx]; bh_assert(tbl_inst); tbl_seg = module->table_init_data_list[tbl_seg_idx]; @@ -2823,7 +2498,7 @@ aot_table_init(AOTModuleInstance *module_inst, uint32 tbl_idx, return; } - bh_memcpy_s((uint8 *)tbl_inst + offsetof(AOTTableInstance, data) + bh_memcpy_s((uint8 *)tbl_inst + offsetof(AOTTableInstance, elems) + dst_offset * sizeof(uint32), (tbl_inst->cur_size - dst_offset) * sizeof(uint32), tbl_seg->func_indexes + src_offset, length * sizeof(uint32)); @@ -2836,10 +2511,10 @@ aot_table_copy(AOTModuleInstance *module_inst, uint32 src_tbl_idx, { AOTTableInstance *src_tbl_inst, *dst_tbl_inst; - src_tbl_inst = aot_get_table_inst(module_inst, src_tbl_idx); + src_tbl_inst = module_inst->tables[src_tbl_idx]; bh_assert(src_tbl_inst); - dst_tbl_inst = aot_get_table_inst(module_inst, dst_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 @@ -2851,10 +2526,10 @@ aot_table_copy(AOTModuleInstance *module_inst, uint32 src_tbl_idx, /* if src_offset >= dst_offset, copy from front to back */ /* if src_offset < dst_offset, copy from back to front */ /* merge all together */ - bh_memmove_s((uint8 *)(dst_tbl_inst) + offsetof(AOTTableInstance, data) + bh_memmove_s((uint8 *)dst_tbl_inst + offsetof(AOTTableInstance, elems) + dst_offset * sizeof(uint32), (dst_tbl_inst->cur_size - dst_offset) * sizeof(uint32), - (uint8 *)(src_tbl_inst) + offsetof(AOTTableInstance, data) + (uint8 *)src_tbl_inst + offsetof(AOTTableInstance, elems) + src_offset * sizeof(uint32), length * sizeof(uint32)); } @@ -2865,7 +2540,7 @@ aot_table_fill(AOTModuleInstance *module_inst, uint32 tbl_idx, uint32 length, { AOTTableInstance *tbl_inst; - tbl_inst = aot_get_table_inst(module_inst, tbl_idx); + tbl_inst = module_inst->tables[tbl_idx]; bh_assert(tbl_inst); if (data_offset + length > tbl_inst->cur_size) { @@ -2874,7 +2549,7 @@ aot_table_fill(AOTModuleInstance *module_inst, uint32 tbl_idx, uint32 length, } for (; length != 0; data_offset++, length--) { - tbl_inst->data[data_offset] = val; + tbl_inst->elems[data_offset] = val; } } @@ -2885,7 +2560,7 @@ aot_table_grow(AOTModuleInstance *module_inst, uint32 tbl_idx, uint32 entry_count, i, orig_tbl_sz; AOTTableInstance *tbl_inst; - tbl_inst = aot_get_table_inst(module_inst, tbl_idx); + tbl_inst = module_inst->tables[tbl_idx]; if (!tbl_inst) { return (uint32)-1; } @@ -2907,7 +2582,7 @@ aot_table_grow(AOTModuleInstance *module_inst, uint32 tbl_idx, /* fill in */ for (i = 0; i < inc_entries; ++i) { - tbl_inst->data[tbl_inst->cur_size + i] = init_val; + tbl_inst->elems[tbl_inst->cur_size + i] = init_val; } tbl_inst->cur_size = entry_count; @@ -2947,7 +2622,7 @@ get_func_name_from_index(const AOTModuleInstance *module_inst, uint32 func_index) { const char *func_name = NULL; - AOTModule *module = module_inst->aot_module.ptr; + AOTModule *module = (AOTModule *)module_inst->module; #if WASM_ENABLE_CUSTOM_NAME_SECTION != 0 if ((func_name = @@ -2983,8 +2658,7 @@ aot_alloc_frame(WASMExecEnv *exec_env, uint32 func_index) #if WASM_ENABLE_PERF_PROFILING != 0 AOTModuleInstance *module_inst = (AOTModuleInstance *)exec_env->module_inst; AOTFuncPerfProfInfo *func_perf_prof = - (AOTFuncPerfProfInfo *)module_inst->func_perf_profilings.ptr - + func_index; + module_inst->func_perf_profilings + func_index; #endif if (!frame) { @@ -3038,8 +2712,8 @@ aot_create_call_stack(struct WASMExecEnv *exec_env) } /* release previous stack frames and create new ones */ - if (!bh_vector_destroy(module_inst->frames.ptr) - || !bh_vector_init(module_inst->frames.ptr, n, sizeof(WASMCApiFrame), + if (!bh_vector_destroy(module_inst->frames) + || !bh_vector_init(module_inst->frames, n, sizeof(WASMCApiFrame), false)) { return false; } @@ -3054,8 +2728,8 @@ aot_create_call_stack(struct WASMExecEnv *exec_env) frame.func_name_wp = get_func_name_from_index(module_inst, cur_frame->func_index); - if (!bh_vector_append(module_inst->frames.ptr, &frame)) { - bh_vector_destroy(module_inst->frames.ptr); + if (!bh_vector_append(module_inst->frames, &frame)) { + bh_vector_destroy(module_inst->frames); return false; } @@ -3083,11 +2757,11 @@ aot_dump_call_stack(WASMExecEnv *exec_env, bool print, char *buf, uint32 len) * will be truncated */ char line_buf[256]; - if (!module_inst->frames.ptr) { + if (!module_inst->frames) { return 0; } - total_frames = (uint32)bh_vector_size(module_inst->frames.ptr); + total_frames = (uint32)bh_vector_size(module_inst->frames); if (total_frames == 0) { return 0; } @@ -3099,7 +2773,7 @@ aot_dump_call_stack(WASMExecEnv *exec_env, bool print, char *buf, uint32 len) WASMCApiFrame frame = { 0 }; uint32 line_length, i; - if (!bh_vector_get(module_inst->frames.ptr, n, &frame)) { + if (!bh_vector_get(module_inst->frames, n, &frame)) { return 0; } @@ -3138,8 +2812,8 @@ void aot_dump_perf_profiling(const AOTModuleInstance *module_inst) { AOTFuncPerfProfInfo *perf_prof = - (AOTFuncPerfProfInfo *)module_inst->func_perf_profilings.ptr; - AOTModule *module = (AOTModule *)module_inst->aot_module.ptr; + (AOTFuncPerfProfInfo *)module_inst->func_perf_profilings; + AOTModule *module = (AOTModule *)module_inst->module; uint32 total_func_count = module->import_func_count + module->func_count, i; const char *func_name; diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/aot/aot_runtime.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/aot/aot_runtime.h similarity index 68% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/aot/aot_runtime.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/aot/aot_runtime.h index 14e037e7851..bcd06534e6e 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/aot/aot_runtime.h +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/aot/aot_runtime.h @@ -10,34 +10,15 @@ #include "../common/wasm_runtime_common.h" #include "../interpreter/wasm_runtime.h" #include "../compilation/aot.h" -#if WASM_ENABLE_JIT != 0 -#include "../compilation/aot_llvm.h" + +#if WASM_ENABLE_WASI_NN != 0 +#include "../libraries/wasi-nn/src/wasi_nn_private.h" #endif #ifdef __cplusplus extern "C" { #endif -typedef enum AOTExceptionID { - EXCE_UNREACHABLE = 0, - EXCE_OUT_OF_MEMORY, - EXCE_OUT_OF_BOUNDS_MEMORY_ACCESS, - EXCE_INTEGER_OVERFLOW, - EXCE_INTEGER_DIVIDE_BY_ZERO, - EXCE_INVALID_CONVERSION_TO_INTEGER, - EXCE_INVALID_FUNCTION_TYPE_INDEX, - EXCE_INVALID_FUNCTION_INDEX, - EXCE_UNDEFINED_ELEMENT, - EXCE_UNINITIALIZED_ELEMENT, - EXCE_CALL_UNLINKED_IMPORT_FUNC, - EXCE_NATIVE_STACK_OVERFLOW, - EXCE_UNALIGNED_ATOMIC, - EXCE_AUX_STACK_OVERFLOW, - EXCE_AUX_STACK_UNDERFLOW, - EXCE_OUT_OF_BOUNDS_TABLE_ACCESS, - EXCE_NUM, -} AOTExceptionID; - typedef enum AOTSectionType { AOT_SECTION_TYPE_TARGET_INFO = 0, AOT_SECTION_TYPE_INIT_DATA = 1, @@ -96,6 +77,13 @@ typedef struct AOTFunctionInstance { } u; } AOTFunctionInstance; +typedef struct AOTModuleInstanceExtra { + CApiFuncImport *c_api_func_imports; +#if WASM_ENABLE_WASI_NN != 0 + WASINNContext *wasi_nn_ctx; +#endif +} AOTModuleInstanceExtra; + #if defined(OS_ENABLE_HW_BOUND_CHECK) && defined(BH_PLATFORM_WINDOWS) /* clang-format off */ typedef struct AOTUnwindInfo { @@ -171,9 +159,9 @@ typedef struct AOTModule { /* function info */ uint32 func_count; - /* point to AOTed/JITed functions */ + /* func pointers of AOTed (un-imported) functions */ void **func_ptrs; - /* function type indexes */ + /* func type indexes of AOTed (un-imported) functions */ uint32 *func_type_indexes; /* export info */ @@ -182,24 +170,24 @@ typedef struct AOTModule { /* start function index, -1 denotes no start function */ uint32 start_func_index; - /* start function, point to AOTed/JITed function */ + /* start function, point to AOTed function */ void *start_function; uint32 malloc_func_index; uint32 free_func_index; uint32 retain_func_index; - /* AOTed code, NULL for JIT mode */ + /* AOTed code */ void *code; uint32 code_size; - /* literal for AOTed code, NULL for JIT mode */ + /* literal for AOTed code */ uint8 *literal; uint32 literal_size; #if defined(BH_PLATFORM_WINDOWS) /* extra plt data area for __ymm, __xmm and __real constants - in Windows platform, NULL for JIT mode */ + in Windows platform */ uint8 *extra_plt_data; uint32 extra_plt_data_size; uint32 ymm_plt_count; @@ -217,7 +205,7 @@ typedef struct AOTModule { #endif /* data sections in AOT object file, including .data, .rodata - * and .rodata.cstN. NULL for JIT mode. */ + and .rodata.cstN. */ AOTObjectDataSection *data_sections; uint32 data_section_count; @@ -244,18 +232,9 @@ typedef struct AOTModule { /* auxiliary stack size resolved */ uint32 aux_stack_size; - /* is jit mode or not */ - bool is_jit_mode; - /* is indirect mode or not */ bool is_indirect_mode; -#if WASM_ENABLE_JIT != 0 - WASMModule *wasm_module; - AOTCompContext *comp_ctx; - AOTCompData *comp_data; -#endif - #if WASM_ENABLE_LIBC_WASI != 0 WASIArguments wasi_args; bool import_wasi_api; @@ -274,130 +253,9 @@ typedef struct AOTModule { #endif } AOTModule; -typedef union { - uint64 _make_it_8_bytes_; - void *ptr; -} AOTPointer; - -typedef union { - uint64 u64; - uint32 u32[2]; -} MemBound; - -typedef struct AOTMemoryInstance { - uint32 module_type; - /* shared memory flag */ - bool is_shared; - - /* memory space info */ - uint32 num_bytes_per_page; - uint32 cur_page_count; - uint32 max_page_count; - uint32 memory_data_size; - AOTPointer memory_data; - AOTPointer memory_data_end; - - /* heap space info */ - AOTPointer heap_data; - AOTPointer heap_data_end; - AOTPointer heap_handle; - - /* boundary check constants for aot code */ - MemBound mem_bound_check_1byte; - MemBound mem_bound_check_2bytes; - MemBound mem_bound_check_4bytes; - MemBound mem_bound_check_8bytes; - MemBound mem_bound_check_16bytes; -} AOTMemoryInstance; - -typedef struct AOTTableInstance { - uint32 cur_size; - /* - * only grow in the range of [:max_size) - * if the table is growable, max_size equals to its declared maximum size - * otherwise, max_size equals to its declared minimum size - */ - uint32 max_size; - /* - * +------------------------------+ <--- data - * | ref.func[] or ref.extern[] - * +------------------------------+ - */ - uint32 data[1]; -} AOTTableInstance; - -typedef struct AOTModuleInstance { - uint32 module_type; - - /* memories */ - uint32 memory_count; - AOTPointer memories; - - /* global and table info */ - uint32 global_data_size; - /* - * the count of AOTTableInstance. - * it includes imported tables and local tables. - * - * TODO: for now we treate imported table like a local table - */ - uint32 table_count; - /* points to global_data */ - AOTPointer global_data; - /* points to AOTTableInstance[] */ - AOTPointer tables; - - /* function pointer array */ - AOTPointer func_ptrs; - /* function type indexes */ - AOTPointer func_type_indexes; - - /* export info */ - uint32 export_func_count; - uint32 export_global_count; - uint32 export_mem_count; - uint32 export_tab_count; - AOTPointer export_funcs; - AOTPointer export_globals; - AOTPointer export_memories; - AOTPointer export_tables; - - /* The exception buffer for current thread. */ - char cur_exception[128]; - /* The custom data that can be set/get by - * wasm_runtime_set_custom_data/wasm_runtime_get_custom_data */ - AOTPointer custom_data; - /* The AOT module */ - AOTPointer aot_module; - /* WASI context */ - AOTPointer wasi_ctx; - /* function performance profiling info list */ - AOTPointer func_perf_profilings; - /* stack frames, used in call stack dump and perf profiling */ - AOTPointer frames; - - AOTPointer exec_env_singleton; - - uint32 default_wasm_stack_size; - - /* reserved */ - uint32 reserved[9]; - - /* - * +------------------------------+ <-- memories.ptr - * | #0 AOTMemoryInstance - * +------------------------------+ <-- global_data.ptr - * | global data - * +------------------------------+ <-- tables.ptr - * | AOTTableInstance[table_count] - * +------------------------------+ - */ - union { - uint64 _make_it_8_byte_aligned_; - AOTMemoryInstance memory_instances[1]; - uint8 bytes[1]; - } global_table_data; -} AOTModuleInstance; +#define AOTMemoryInstance WASMMemoryInstance +#define AOTTableInstance WASMTableInstance +#define AOTModuleInstance WASMModuleInstance /* Target info, read from ELF header of object file */ typedef struct AOTTargetInfo { @@ -462,21 +320,6 @@ AOTModule * aot_load_from_sections(AOTSection *section_list, char *error_buf, uint32 error_buf_size); -#if WASM_ENABLE_JIT != 0 -/** - * Convert WASM module to AOT module - * - * @param wasm_module the WASM module to convert - * @param error_buf output of the error info - * @param error_buf_size the size of the error string - * - * @return return AOT module loaded, NULL if failed - */ -AOTModule * -aot_convert_wasm_module(WASMModule *wasm_module, char *error_buf, - uint32 error_buf_size); -#endif - /** * Unload a AOT module. * @@ -500,8 +343,9 @@ aot_unload(AOTModule *module); * @return return the instantiated AOT module instance, NULL if failed */ AOTModuleInstance * -aot_instantiate(AOTModule *module, bool is_sub_inst, uint32 stack_size, - uint32 heap_size, char *error_buf, uint32 error_buf_size); +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); /** * Deinstantiate a AOT module instance, destroy the resources. @@ -544,14 +388,6 @@ bool aot_call_function(WASMExecEnv *exec_env, AOTFunctionInstance *function, unsigned argc, uint32 argv[]); -bool -aot_create_exec_env_and_call_function(AOTModuleInstance *module_inst, - AOTFunctionInstance *function, - unsigned argc, uint32 argv[]); - -bool -aot_create_exec_env_singleton(AOTModuleInstance *module_inst); - /** * Set AOT module instance exception with exception string * @@ -576,12 +412,25 @@ const char * aot_get_exception(AOTModuleInstance *module_inst); /** - * Clear exception info of the AOT module instance. - * - * @param module_inst the AOT module instance + * @brief Copy exception in buffer passed as parameter. Thread-safe version of + * `aot_get_exception()` + * @note Buffer size must be no smaller than EXCEPTION_BUF_LEN + * @return true if exception found, false otherwise */ +bool +aot_copy_exception(AOTModuleInstance *module_inst, char *exception_buf); + +uint32 +aot_module_malloc_internal(AOTModuleInstance *module_inst, WASMExecEnv *env, + uint32 size, void **p_native_addr); + +uint32 +aot_module_realloc_internal(AOTModuleInstance *module_inst, WASMExecEnv *env, + uint32 ptr, uint32 size, void **p_native_addr); + void -aot_clear_exception(AOTModuleInstance *module_inst); +aot_module_free_internal(AOTModuleInstance *module_inst, WASMExecEnv *env, + uint32 ptr); uint32 aot_module_malloc(AOTModuleInstance *module_inst, uint32 size, @@ -598,29 +447,6 @@ uint32 aot_module_dup_data(AOTModuleInstance *module_inst, const char *src, uint32 size); -bool -aot_validate_app_addr(AOTModuleInstance *module_inst, uint32 app_offset, - uint32 size); - -bool -aot_validate_native_addr(AOTModuleInstance *module_inst, void *native_ptr, - uint32 size); - -void * -aot_addr_app_to_native(AOTModuleInstance *module_inst, uint32 app_offset); - -uint32 -aot_addr_native_to_app(AOTModuleInstance *module_inst, void *native_ptr); - -bool -aot_get_app_addr_range(AOTModuleInstance *module_inst, uint32 app_offset, - uint32 *p_app_start_offset, uint32 *p_app_end_offset); - -bool -aot_get_native_addr_range(AOTModuleInstance *module_inst, uint8 *native_ptr, - uint8 **p_native_start_addr, - uint8 **p_native_end_addr); - bool aot_enlarge_memory(AOTModuleInstance *module_inst, uint32 inc_page_count); @@ -635,6 +461,10 @@ bool aot_call_indirect(WASMExecEnv *exec_env, uint32 tbl_idx, uint32 table_elem_idx, uint32 argc, uint32 *argv); +/** + * Check whether the app address and the buf is inside the linear memory, + * and convert the app address into native address + */ bool aot_check_app_addr_and_convert(AOTModuleInstance *module_inst, bool is_str, uint32 app_buf_addr, uint32 app_buf_size, @@ -649,6 +479,12 @@ aot_memmove(void *dest, const void *src, size_t n); void * aot_memset(void *s, int c, size_t n); +double +aot_sqrt(double x); + +float +aot_sqrtf(float x); + #if WASM_ENABLE_BULK_MEMORY != 0 bool aot_memory_init(AOTModuleInstance *module_inst, uint32 seg_index, uint32 offset, @@ -666,16 +502,6 @@ bool aot_get_aux_stack(WASMExecEnv *exec_env, uint32 *start_offset, uint32 *size); #endif -#ifdef OS_ENABLE_HW_BOUND_CHECK -#ifndef BH_PLATFORM_WINDOWS -void -aot_signal_handler(WASMSignalInfo *sig_info); -#else -LONG -aot_exception_handler(WASMSignalInfo *sig_info); -#endif -#endif - void aot_get_module_mem_consumption(const AOTModule *module, WASMModuleMemConsumption *mem_conspn); @@ -707,9 +533,6 @@ aot_table_grow(AOTModuleInstance *module_inst, uint32 tbl_idx, uint32 inc_entries, uint32 init_val); #endif -AOTTableInstance * -aot_next_tbl_inst(const AOTTableInstance *tbl_inst); - bool aot_alloc_frame(WASMExecEnv *exec_env, uint32 func_index); diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/aot/arch/aot_reloc_aarch64.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/aot/arch/aot_reloc_aarch64.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/aot/arch/aot_reloc_aarch64.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/aot/arch/aot_reloc_aarch64.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/aot/arch/aot_reloc_arc.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/aot/arch/aot_reloc_arc.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/aot/arch/aot_reloc_arc.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/aot/arch/aot_reloc_arc.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/aot/arch/aot_reloc_arm.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/aot/arch/aot_reloc_arm.c similarity index 98% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/aot/arch/aot_reloc_arm.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/aot/arch/aot_reloc_arm.c index 1389bfb25a8..fbf9be13c86 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/aot/arch/aot_reloc_arm.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/aot/arch/aot_reloc_arm.c @@ -37,6 +37,9 @@ void __aeabi_idivmod(); void __aeabi_l2d(); void __aeabi_l2f(); void __aeabi_ldivmod(); +void __aeabi_memcpy(); +void __aeabi_memmove(); +void __aeabi_memset(); void __aeabi_uidiv(); void __aeabi_uidivmod(); void __aeabi_ul2d(); @@ -120,6 +123,9 @@ static SymbolMap target_sym_map[] = { REG_SYM(__aeabi_l2d), REG_SYM(__aeabi_l2f), REG_SYM(__aeabi_ldivmod), + REG_SYM(__aeabi_memcpy), + REG_SYM(__aeabi_memmove), + REG_SYM(__aeabi_memset), REG_SYM(__aeabi_uidiv), REG_SYM(__aeabi_uidivmod), REG_SYM(__aeabi_ul2d), diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/aot/arch/aot_reloc_mips.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/aot/arch/aot_reloc_mips.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/aot/arch/aot_reloc_mips.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/aot/arch/aot_reloc_mips.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/aot/arch/aot_reloc_riscv.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/aot/arch/aot_reloc_riscv.c similarity index 87% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/aot/arch/aot_reloc_riscv.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/aot/arch/aot_reloc_riscv.c index 7d7002e6544..75fee56fda1 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/aot/arch/aot_reloc_riscv.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/aot/arch/aot_reloc_riscv.c @@ -16,47 +16,113 @@ #define RV_OPCODE_SW 0x23 /* clang-format off */ +void __adddf3(); +void __addsf3(); void __divdi3(); void __divsi3(); +void __divdf3(); +void __divsf3(); +void __eqsf2(); +void __eqdf2(); +void __extendsfdf2(); void __fixdfdi(); +void __fixdfsi(); void __fixsfdi(); +void __fixsfsi(); void __fixunsdfdi(); +void __fixunsdfsi(); void __fixunssfdi(); +void __fixunssfsi(); void __floatdidf(); void __floatdisf(); +void __floatsisf(); +void __floatsidf(); void __floatundidf(); void __floatundisf(); +void __floatunsisf(); +void __floatunsidf(); +void __gedf2(); +void __gesf2(); +void __gtdf2(); +void __gtsf2(); +void __ledf2(); +void __lesf2(); +void __ltdf2(); +void __ltsf2(); void __moddi3(); void __modsi3(); +void __muldf3(); void __muldi3(); +void __mulsf3(); void __mulsi3(); +void __nedf2(); +void __nesf2(); +void __subdf3(); +void __subsf3(); +void __truncdfsf2(); void __udivdi3(); void __udivsi3(); void __umoddi3(); void __umodsi3(); +void __unorddf2(); +void __unordsf2(); /* clang-format on */ static SymbolMap target_sym_map[] = { /* clang-format off */ REG_COMMON_SYMBOLS +#ifndef __riscv_flen + REG_SYM(__adddf3), + REG_SYM(__addsf3), + REG_SYM(__divdf3), + REG_SYM(__divsf3), + REG_SYM(__gedf2), + REG_SYM(__gesf2), + REG_SYM(__gtdf2), + REG_SYM(__gtsf2), + REG_SYM(__ledf2), + REG_SYM(__lesf2), + REG_SYM(__ltdf2), + REG_SYM(__ltsf2), + 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(__fixunsdfdi), REG_SYM(__fixunssfdi), #if __riscv_xlen == 32 REG_SYM(__floatdidf), REG_SYM(__floatdisf), + REG_SYM(__floatsisf), + REG_SYM(__floatsidf), 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(__mulsf3), REG_SYM(__mulsi3), #endif REG_SYM(__udivdi3), diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/aot/arch/aot_reloc_thumb.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/aot/arch/aot_reloc_thumb.c similarity index 86% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/aot/arch/aot_reloc_thumb.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/aot/arch/aot_reloc_thumb.c index 627f334b2df..26614863b97 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/aot/arch/aot_reloc_thumb.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/aot/arch/aot_reloc_thumb.c @@ -8,6 +8,10 @@ #define R_ARM_ABS32 2 /* Direct 32 bit */ #define R_ARM_THM_CALL 10 /* PC relative (Thumb BL and ARMv5 Thumb BLX). */ #define R_ARM_THM_JMP24 30 /* B.W */ +#define R_ARM_THM_MOVW_ABS_NC 47 +#define R_ARM_THM_MOVT_ABS 48 +#define R_ARM_THM_MOVW_PREL_NC 49 +#define R_ARM_THM_MOVT_PREL 50 /* clang-format off */ void __adddf3(); @@ -372,6 +376,48 @@ apply_relocation(AOTModule *module, uint8 *target_section_addr, + (intptr_t)reloc_addend; break; } + case R_ARM_THM_MOVW_ABS_NC: + case R_ARM_THM_MOVT_ABS: + case R_ARM_THM_MOVW_PREL_NC: + case R_ARM_THM_MOVT_PREL: + { + uint16 upper = *(uint16 *)(target_section_addr + reloc_offset); + uint16 lower = *(uint16 *)(target_section_addr + reloc_offset + 2); + int32 offset; + + /* + * MOVT/MOVW instructions encoding in Thumb-2: + * + * i = upper[10] + * imm4 = upper[3:0] + * imm3 = lower[14:12] + * imm8 = lower[7:0] + * + * imm16 = imm4:i:imm3:imm8 + */ + + offset = ((upper & 0x000f) << 12) | ((upper & 0x0400) << 1) + | ((lower & 0x7000) >> 4) | (lower & 0x00ff); + offset = (offset ^ 0x8000) - 0x8000; + + offset += (symbol_addr + reloc_addend); + + if (reloc_type == R_ARM_THM_MOVT_PREL + || reloc_type == R_ARM_THM_MOVW_PREL_NC) + offset -= (int32)(target_section_addr + reloc_offset); + if (reloc_type == R_ARM_THM_MOVT_ABS + || reloc_type == R_ARM_THM_MOVT_PREL) + offset >>= 16; + + upper = (uint16)((upper & 0xfbf0) | ((offset & 0xf000) >> 12) + | ((offset & 0x0800) >> 1)); + lower = (uint16)((lower & 0x8f00) | ((offset & 0x0700) << 4) + | (offset & 0x00ff)); + + *(uint16 *)(target_section_addr + reloc_offset) = upper; + *(uint16 *)(target_section_addr + reloc_offset + 2) = lower; + break; + } default: if (error_buf != NULL) diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/aot/arch/aot_reloc_x86_32.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/aot/arch/aot_reloc_x86_32.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/aot/arch/aot_reloc_x86_32.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/aot/arch/aot_reloc_x86_32.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/aot/arch/aot_reloc_x86_64.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/aot/arch/aot_reloc_x86_64.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/aot/arch/aot_reloc_x86_64.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/aot/arch/aot_reloc_x86_64.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/aot/arch/aot_reloc_xtensa.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/aot/arch/aot_reloc_xtensa.c similarity index 90% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/aot/arch/aot_reloc_xtensa.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/aot/arch/aot_reloc_xtensa.c index b5b262a5a61..3327c396fb5 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/aot/arch/aot_reloc_xtensa.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/aot/arch/aot_reloc_xtensa.c @@ -41,6 +41,9 @@ void __gtdf2(); void __umoddi3(); void __floatdidf(); void __divsf3(); +void __fixdfdi(); +void __floatundidf(); + static SymbolMap target_sym_map[] = { REG_COMMON_SYMBOLS @@ -80,8 +83,8 @@ static SymbolMap target_sym_map[] = { REG_SYM(__umoddi3), REG_SYM(__floatdidf), REG_SYM(__divsf3), - REG_SYM(sqrt), - REG_SYM(sqrtf), + REG_SYM(__fixdfdi), + REG_SYM(__floatundidf), }; /* clang-format on */ @@ -256,17 +259,32 @@ apply_relocation(AOTModule *module, uint8 *target_section_addr, if (relative_offset < -256 * BH_KB || relative_offset > -4) { set_error_buf(error_buf, error_buf_size, "AOT module load failed: " - "target address out of range."); + "target address out of range.\n" + "Try using `wamrc --size-level=0` to generate " + ".literal island."); return false; } imm16 = (int16)(relative_offset >> 2); /* write back the imm16 to the l32r instruction */ + + /* GCC >= 9 complains if we have a pointer that could be + * unaligned. This can happen because the struct is packed. + * These pragma are to suppress the warnings because the + * function put_imm16_to_addr already handles unaligned + * pointers correctly. */ +#if __GNUC__ >= 9 +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Waddress-of-packed-member" +#endif if (is_little_endian()) put_imm16_to_addr(imm16, &l32r_insn->l.imm16); else put_imm16_to_addr(imm16, &l32r_insn->b.imm16); +#if __GNUC__ >= 9 +#pragma GCC diagnostic pop +#endif break; } @@ -276,7 +294,7 @@ apply_relocation(AOTModule *module, uint8 *target_section_addr, snprintf(error_buf, error_buf_size, "Load relocation section failed: " "invalid relocation type %d.", - reloc_type); + (int)reloc_type); return false; } diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/aot/debug/LICENSE_NUTTX b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/aot/debug/LICENSE_NUTTX similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/aot/debug/LICENSE_NUTTX rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/aot/debug/LICENSE_NUTTX diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/aot/debug/NOTICE_NUTTX b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/aot/debug/NOTICE_NUTTX similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/aot/debug/NOTICE_NUTTX rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/aot/debug/NOTICE_NUTTX diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/aot/debug/elf.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/aot/debug/elf.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/aot/debug/elf.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/aot/debug/elf.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/aot/debug/elf32.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/aot/debug/elf32.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/aot/debug/elf32.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/aot/debug/elf32.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/aot/debug/elf64.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/aot/debug/elf64.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/aot/debug/elf64.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/aot/debug/elf64.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/aot/debug/elf_parser.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/aot/debug/elf_parser.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/aot/debug/elf_parser.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/aot/debug/elf_parser.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/aot/debug/elf_parser.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/aot/debug/elf_parser.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/aot/debug/elf_parser.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/aot/debug/elf_parser.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/aot/debug/jit_debug.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/aot/debug/jit_debug.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/aot/debug/jit_debug.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/aot/debug/jit_debug.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/aot/debug/jit_debug.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/aot/debug/jit_debug.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/aot/debug/jit_debug.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/aot/debug/jit_debug.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/aot/iwasm_aot.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/aot/iwasm_aot.cmake similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/aot/iwasm_aot.cmake rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/aot/iwasm_aot.cmake diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/SConscript b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/SConscript similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/SConscript rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/SConscript diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/arch/invokeNative_aarch64.s b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_aarch64.s similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/arch/invokeNative_aarch64.s rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_aarch64.s diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/arch/invokeNative_aarch64_simd.s b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_aarch64_simd.s similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/arch/invokeNative_aarch64_simd.s rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_aarch64_simd.s diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/arch/invokeNative_arc.s b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_arc.s similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/arch/invokeNative_arc.s rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_arc.s diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/arch/invokeNative_arm.s b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_arm.s similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/arch/invokeNative_arm.s rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_arm.s diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/arch/invokeNative_arm_vfp.s b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_arm_vfp.s similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/arch/invokeNative_arm_vfp.s rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_arm_vfp.s diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/arch/invokeNative_em64.asm b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_em64.asm similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/arch/invokeNative_em64.asm rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_em64.asm diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/arch/invokeNative_em64.s b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_em64.s similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/arch/invokeNative_em64.s rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_em64.s diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/arch/invokeNative_em64_simd.asm b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_em64_simd.asm similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/arch/invokeNative_em64_simd.asm rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_em64_simd.asm diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/arch/invokeNative_em64_simd.s b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_em64_simd.s similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/arch/invokeNative_em64_simd.s rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_em64_simd.s diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/arch/invokeNative_general.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_general.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/arch/invokeNative_general.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_general.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/arch/invokeNative_ia32.asm b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_ia32.asm similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/arch/invokeNative_ia32.asm rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_ia32.asm diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/arch/invokeNative_ia32.s b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_ia32.s similarity index 73% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/arch/invokeNative_ia32.s rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_ia32.s index 0056a53e3ff..de1c1a5e187 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/arch/invokeNative_ia32.s +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_ia32.s @@ -16,9 +16,14 @@ _invokeNative: push %ebp movl %esp, %ebp movl 16(%ebp), %ecx /* ecx = argc */ - movl 12(%ebp), %edx /* edx = argv */ + leal 2(%ecx), %edx /* edx = ecx + 2 (count return address and saved ebp) */ + andl $3, %edx /* edx = edx % 4 */ + jz stack_aligned /* if edx == 0, stack is already 16 bytes aligned */ + leal -16(%esp, %edx, 4), %esp /* esp = esp - 16 + edx * 4 */ +stack_aligned: test %ecx, %ecx jz skip_push_args /* if ecx == 0, skip pushing arguments */ + movl 12(%ebp), %edx /* edx = argv */ leal -4(%edx,%ecx,4), %edx /* edx = edx + ecx * 4 - 4 */ subl %esp, %edx /* edx = edx - esp */ 1: diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_mingw_x64.s b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_mingw_x64.s new file mode 100644 index 00000000000..cefaa28c1cf --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_mingw_x64.s @@ -0,0 +1,57 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +.text +.align 2 +.globl invokeNative +invokeNative: + + # %rcx func_ptr + # %rdx argv + # %r8 n_stacks + + push %rbp + mov %rsp, %rbp + + mov %rcx, %r10 # func_ptr + mov %rdx, %rax # argv + mov %r8, %rcx # n_stacks + + # fill all fp args + movsd 0(%rax), %xmm0 + movsd 8(%rax), %xmm1 + movsd 16(%rax), %xmm2 + movsd 24(%rax), %xmm3 + + # check for stack args + cmp $0, %rcx + jz cycle_end + + mov %rsp, %rdx + and $15, %rdx + jz no_abort + int $3 +no_abort: + mov %rcx, %rdx + and $1, %rdx + shl $3, %rdx + sub %rdx, %rsp + + # store stack args + lea 56(%rax, %rcx, 8), %r9 + sub %rsp, %r9 # offset +cycle: + push (%rsp, %r9) + loop cycle + +cycle_end: + mov 32(%rax), %rcx + mov 40(%rax), %rdx + mov 48(%rax), %r8 + mov 56(%rax), %r9 + + sub $32, %rsp # shadow space + + call *%r10 + leave + ret diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_mingw_x64_simd.s b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_mingw_x64_simd.s new file mode 100644 index 00000000000..48ae52480a9 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_mingw_x64_simd.s @@ -0,0 +1,57 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +.text +.align 2 +.globl invokeNative +invokeNative: + + # %rcx func_ptr + # %rdx argv + # %r8 n_stacks + + push %rbp + mov %rsp, %rbp + + mov %rcx, %r10 # func_ptr + mov %rdx, %rax # argv + mov %r8, %rcx # n_stacks + + # fill all fp args + movdqu 0(%rax), %xmm0 + movdqu 16(%rax), %xmm1 + movdqu 32(%rax), %xmm2 + movdqu 48(%rax), %xmm3 + + # check for stack args + cmp $0, %rcx + jz cycle_end + + mov %rsp, %rdx + and $15, %rdx + jz no_abort + int $3 +no_abort: + mov %rcx, %rdx + and $1, %rdx + shl $3, %rdx + sub %rdx, %rsp + + # store stack args + lea 88(%rax, %rcx, 8), %r9 + sub %rsp, %r9 # offset +cycle: + push (%rsp, %r9) + loop cycle + +cycle_end: + mov 64(%rax), %rcx + mov 72(%rax), %rdx + mov 80(%rax), %r8 + mov 88(%rax), %r9 + + sub $32, %rsp # shadow space + + call *%r10 + leave + ret diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/arch/invokeNative_mips.s b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_mips.s similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/arch/invokeNative_mips.s rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_mips.s diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_osx_universal.s b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_osx_universal.s new file mode 100644 index 00000000000..e2ca654fdfc --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_osx_universal.s @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#if defined(__aarch64__) +#if WASM_ENABLE_SIMD == 0 +#include "invokeNative_aarch64.s" +#else +#include "invokeNative_aarch64_simd.s" +#endif +#else +#if WASM_ENABLE_SIMD == 0 +#include "invokeNative_em64.s" +#else +#include "invokeNative_em64_simd.s" +#endif +#endif \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/arch/invokeNative_riscv.S b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_riscv.S similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/arch/invokeNative_riscv.S rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_riscv.S diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/arch/invokeNative_thumb.s b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_thumb.s similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/arch/invokeNative_thumb.s rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_thumb.s diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/arch/invokeNative_thumb_vfp.s b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_thumb_vfp.s similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/arch/invokeNative_thumb_vfp.s rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_thumb_vfp.s diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/arch/invokeNative_xtensa.s b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_xtensa.s similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/arch/invokeNative_xtensa.s rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/arch/invokeNative_xtensa.s diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/iwasm_common.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/iwasm_common.cmake similarity index 78% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/iwasm_common.cmake rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/iwasm_common.cmake index de0826e2ca0..15895b8e5ef 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/iwasm_common.cmake +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/iwasm_common.cmake @@ -14,6 +14,17 @@ if (WAMR_DISABLE_APP_ENTRY EQUAL 1) list(REMOVE_ITEM c_source_all "${IWASM_COMMON_DIR}/wasm_application.c") endif () +if (CMAKE_OSX_ARCHITECTURES) + string(TOLOWER "${CMAKE_OSX_ARCHITECTURES}" OSX_ARCHS) + + list(FIND OSX_ARCHS arm64 OSX_AARCH64) + list(FIND OSX_ARCHS x86_64 OSX_X86_64) + + if (NOT "${OSX_AARCH64}" STREQUAL "-1" AND NOT "${OSX_X86_64}" STREQUAL "-1") + set(OSX_UNIVERSAL_BUILD 1) + endif() +endif() + if (WAMR_BUILD_INVOKE_NATIVE_GENERAL EQUAL 1) # Use invokeNative C version instead of asm code version # if WAMR_BUILD_INVOKE_NATIVE_GENERAL is explicitly set. @@ -24,16 +35,26 @@ if (WAMR_BUILD_INVOKE_NATIVE_GENERAL EQUAL 1) # in arm and mips need to be 8-bytes aligned, and some arguments # of x86_64 are passed by registers but not stack set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_general.c) +elseif (OSX_UNIVERSAL_BUILD EQUAL 1) + set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_osx_universal.s) elseif (WAMR_BUILD_TARGET STREQUAL "X86_64" OR WAMR_BUILD_TARGET STREQUAL "AMD_64") if (NOT WAMR_BUILD_SIMD EQUAL 1) if (WAMR_BUILD_PLATFORM STREQUAL "windows") - set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_em64.asm) + if (NOT MINGW) + set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_em64.asm) + else () + set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_mingw_x64.s) + endif () else () set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_em64.s) endif () else () if (WAMR_BUILD_PLATFORM STREQUAL "windows") - set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_em64_simd.asm) + if (NOT MINGW) + set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_em64_simd.asm) + else () + set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_mingw_x64_simd.s) + endif () else() set (source_all ${c_source_all} ${IWASM_COMMON_DIR}/arch/invokeNative_em64_simd.s) endif() diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/wasm_application.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_application.c similarity index 95% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/wasm_application.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_application.c index 8a19de8ee57..2ed217e7a96 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/wasm_application.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_application.c @@ -195,6 +195,7 @@ execute_main(WASMModuleInstanceCommon *module_inst, int32 argc, char *argv[]) if (argv_buf_offset) wasm_runtime_module_free(module_inst, argv_buf_offset); + return ret; } @@ -203,22 +204,12 @@ wasm_application_execute_main(WASMModuleInstanceCommon *module_inst, int32 argc, char *argv[]) { bool ret; -#if WASM_ENABLE_THREAD_MGR != 0 - WASMCluster *cluster; -#endif -#if WASM_ENABLE_THREAD_MGR != 0 || WASM_ENABLE_MEMORY_PROFILING != 0 +#if (WASM_ENABLE_MEMORY_PROFILING != 0) || (WASM_ENABLE_DUMP_CALL_STACK != 0) WASMExecEnv *exec_env; #endif ret = execute_main(module_inst, argc, argv); -#if WASM_ENABLE_THREAD_MGR != 0 - exec_env = wasm_runtime_get_exec_env_singleton(module_inst); - if (exec_env && (cluster = wasm_exec_env_get_cluster(exec_env))) { - wasm_cluster_wait_for_all_except_self(cluster, exec_env); - } -#endif - #if WASM_ENABLE_MEMORY_PROFILING != 0 exec_env = wasm_runtime_get_exec_env_singleton(module_inst); if (exec_env) { @@ -230,7 +221,18 @@ wasm_application_execute_main(WASMModuleInstanceCommon *module_inst, int32 argc, wasm_runtime_dump_perf_profiling(module_inst); #endif - return (ret && !wasm_runtime_get_exception(module_inst)) ? true : false; + if (ret) + ret = wasm_runtime_get_exception(module_inst) == NULL; + +#if WASM_ENABLE_DUMP_CALL_STACK != 0 + if (!ret) { + exec_env = wasm_runtime_get_exec_env_singleton(module_inst); + if (exec_env) + wasm_runtime_dump_call_stack(exec_env); + } +#endif + + return ret; } /** @@ -555,7 +557,7 @@ execute_func(WASMModuleInstanceCommon *module_inst, const char *name, case VALUE_TYPE_FUNCREF: { if (argv1[k] != NULL_REF) - os_printf("%u:ref.func", argv1[k]); + os_printf("%" PRIu32 ":ref.func", argv1[k]); else os_printf("func:ref.null"); k++; @@ -622,22 +624,12 @@ wasm_application_execute_func(WASMModuleInstanceCommon *module_inst, const char *name, int32 argc, char *argv[]) { bool ret; -#if WASM_ENABLE_THREAD_MGR != 0 - WASMCluster *cluster; -#endif -#if WASM_ENABLE_THREAD_MGR != 0 || WASM_ENABLE_MEMORY_PROFILING != 0 +#if WASM_ENABLE_MEMORY_PROFILING != 0 WASMExecEnv *exec_env; #endif ret = execute_func(module_inst, name, argc, argv); -#if WASM_ENABLE_THREAD_MGR != 0 - exec_env = wasm_runtime_get_exec_env_singleton(module_inst); - if (exec_env && (cluster = wasm_exec_env_get_cluster(exec_env))) { - wasm_cluster_wait_for_all_except_self(cluster, exec_env); - } -#endif - #if WASM_ENABLE_MEMORY_PROFILING != 0 exec_env = wasm_runtime_get_exec_env_singleton(module_inst); if (exec_env) { diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/wasm_c_api.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_c_api.c similarity index 81% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/wasm_c_api.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_c_api.c index 52b6464acdc..7b8cf477974 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/wasm_c_api.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_c_api.c @@ -3,20 +3,58 @@ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception */ +#include "bh_log.h" #include "wasm_c_api_internal.h" + +#include "bh_assert.h" +#include "wasm_export.h" #include "wasm_memory.h" -#include "wasm_runtime_common.h" #if WASM_ENABLE_INTERP != 0 #include "wasm_runtime.h" #endif #if WASM_ENABLE_AOT != 0 #include "aot_runtime.h" +#if WASM_ENABLE_JIT != 0 && WASM_ENABLE_LAZY_JIT == 0 +#include "aot.h" +#include "aot_llvm.h" +#endif /*WASM_ENABLE_JIT != 0 && WASM_ENABLE_LAZY_JIT == 0*/ +#endif /*WASM_ENABLE_AOT != 0*/ + +#if WASM_ENABLE_WASM_CACHE != 0 +#include +#endif +#if WASM_ENABLE_THREAD_MGR != 0 +#include "thread_manager.h" #endif +/* + * Thread Model: + * - Only one wasm_engine_t in one process + * - One wasm_store_t is only accessed by one thread. wasm_store_t can't be + * shared in threads + * - wasm_module_t can be shared in threads + * - wasm_instance_t can not be shared in threads + */ + #define ASSERT_NOT_IMPLEMENTED() bh_assert(!"not implemented") #define UNREACHABLE() bh_assert(!"unreachable") -typedef struct wasm_module_ex_t wasm_module_ex_t; +typedef struct wasm_module_ex_t { + struct WASMModuleCommon *module_comm_rt; + wasm_byte_vec_t *binary; + korp_mutex lock; + uint32 ref_count; +#if WASM_ENABLE_WASM_CACHE != 0 + char hash[SHA256_DIGEST_LENGTH]; +#endif +} wasm_module_ex_t; + +#ifndef os_thread_local_attribute +typedef struct thread_local_stores { + korp_tid tid; + unsigned stores_num; +} thread_local_stores; +#endif static void wasm_module_delete_internal(wasm_module_t *); @@ -240,6 +278,16 @@ WASM_DEFINE_VEC_OWN(module, wasm_module_delete_internal) WASM_DEFINE_VEC_OWN(store, wasm_store_delete) WASM_DEFINE_VEC_OWN(valtype, wasm_valtype_delete) +#ifndef NDEBUG +#if WASM_ENABLE_MEMORY_PROFILING != 0 +#define WASM_C_DUMP_PROC_MEM() LOG_PROC_MEM() +#else +#define WASM_C_DUMP_PROC_MEM() (void)0 +#endif +#else +#define WASM_C_DUMP_PROC_MEM() (void)0 +#endif + /* Runtime Environment */ own wasm_config_t * wasm_config_new(void) @@ -257,7 +305,23 @@ static void wasm_engine_delete_internal(wasm_engine_t *engine) { if (engine) { - DEINIT_VEC(engine->stores, wasm_store_vec_delete); + /* clean all created wasm_module_t and their locks */ + unsigned i; + + for (i = 0; i < engine->modules.num_elems; i++) { + wasm_module_ex_t *module; + if (bh_vector_get(&engine->modules, i, &module)) { + os_mutex_destroy(&module->lock); + wasm_runtime_free(module); + } + } + + bh_vector_destroy(&engine->modules); + +#ifndef os_thread_local_attribute + bh_vector_destroy(&engine->stores_by_tid); +#endif + wasm_runtime_free(engine); } @@ -272,6 +336,14 @@ wasm_engine_new_internal(mem_alloc_type_t type, const MemAllocOption *opts) RuntimeInitArgs init_args = { 0 }; init_args.mem_alloc_type = type; +#ifndef NDEBUG + bh_log_set_verbose_level(BH_LOG_LEVEL_VERBOSE); +#else + bh_log_set_verbose_level(BH_LOG_LEVEL_WARNING); +#endif + + WASM_C_DUMP_PROC_MEM(); + if (type == Alloc_With_Pool) { if (!opts) { return NULL; @@ -291,6 +363,10 @@ wasm_engine_new_internal(mem_alloc_type_t type, const MemAllocOption *opts) opts->allocator.free_func; init_args.mem_alloc_option.allocator.realloc_func = opts->allocator.realloc_func; +#if WASM_MEM_ALLOC_WITH_USER_DATA != 0 + init_args.mem_alloc_option.allocator.user_data = + opts->allocator.user_data; +#endif } else { init_args.mem_alloc_option.pool.heap_buf = NULL; @@ -302,64 +378,247 @@ wasm_engine_new_internal(mem_alloc_type_t type, const MemAllocOption *opts) goto failed; } -#if BH_DEBUG != 0 - bh_log_set_verbose_level(5); -#else - bh_log_set_verbose_level(3); -#endif - /* create wasm_engine_t */ if (!(engine = malloc_internal(sizeof(wasm_engine_t)))) { goto failed; } - /* create wasm_store_vec_t */ - INIT_VEC(engine->stores, wasm_store_vec_new_uninitialized, 1); + if (!bh_vector_init(&engine->modules, DEFAULT_VECTOR_INIT_SIZE, + sizeof(wasm_module_ex_t *), true)) + goto failed; + +#ifndef os_thread_local_attribute + if (!bh_vector_init(&engine->stores_by_tid, DEFAULT_VECTOR_INIT_SIZE, + sizeof(thread_local_stores), true)) + goto failed; +#endif + + engine->ref_count = 1; + + WASM_C_DUMP_PROC_MEM(); RETURN_OBJ(engine, wasm_engine_delete_internal) } /* global engine instance */ -static wasm_engine_t *singleton_engine = NULL; +static wasm_engine_t *singleton_engine; +#ifdef os_thread_local_attribute +/* categorize wasm_store_t as threads*/ +static os_thread_local_attribute unsigned thread_local_stores_num = 0; +#endif +#if defined(OS_THREAD_MUTEX_INITIALIZER) +/** + * lock for the singleton_engine + * Note: if the platform has mutex initializer, we use a global lock to + * lock the operations of the singleton_engine, otherwise when there are + * operations happening simultaneously in multiple threads, developer + * must create the lock by himself, and use it to lock the operations + */ +static korp_mutex engine_lock = OS_THREAD_MUTEX_INITIALIZER; +#endif own wasm_engine_t * -wasm_engine_new() +wasm_engine_new_with_args(mem_alloc_type_t type, const MemAllocOption *opts) { - if (!singleton_engine) { - singleton_engine = - wasm_engine_new_internal(Alloc_With_System_Allocator, NULL); - } - if (singleton_engine) +#if defined(OS_THREAD_MUTEX_INITIALIZER) + os_mutex_lock(&engine_lock); +#endif + + if (!singleton_engine) + singleton_engine = wasm_engine_new_internal(type, opts); + else singleton_engine->ref_count++; + +#if defined(OS_THREAD_MUTEX_INITIALIZER) + os_mutex_unlock(&engine_lock); +#endif + return singleton_engine; } own wasm_engine_t * -wasm_engine_new_with_config(own wasm_config_t *config) +wasm_engine_new() { - (void)config; - return wasm_engine_new(); + return wasm_engine_new_with_args(Alloc_With_System_Allocator, NULL); } own wasm_engine_t * -wasm_engine_new_with_args(mem_alloc_type_t type, const MemAllocOption *opts) +wasm_engine_new_with_config(own wasm_config_t *config) { - if (!singleton_engine) { - singleton_engine = wasm_engine_new_internal(type, opts); - } - if (singleton_engine) - singleton_engine->ref_count++; - return singleton_engine; + (void)config; + return wasm_engine_new_with_args(Alloc_With_System_Allocator, NULL); } -/* BE AWARE: will RESET the singleton */ void wasm_engine_delete(wasm_engine_t *engine) { - if (engine && (--engine->ref_count == 0)) { + if (!engine) + return; + +#if defined(OS_THREAD_MUTEX_INITIALIZER) + os_mutex_lock(&engine_lock); +#endif + + if (!singleton_engine) { +#if defined(OS_THREAD_MUTEX_INITIALIZER) + os_mutex_unlock(&engine_lock); +#endif + return; + } + + bh_assert(engine == singleton_engine); + bh_assert(singleton_engine->ref_count > 0); + + singleton_engine->ref_count--; + if (singleton_engine->ref_count == 0) { wasm_engine_delete_internal(engine); singleton_engine = NULL; } + +#if defined(OS_THREAD_MUTEX_INITIALIZER) + os_mutex_unlock(&engine_lock); +#endif +} + +#ifndef os_thread_local_attribute +static bool +search_thread_local_store_num(Vector *stores_by_tid, korp_tid tid, + thread_local_stores *out_ts, unsigned *out_i) +{ + unsigned i; + + for (i = 0; i < stores_by_tid->num_elems; i++) { + bool ret = bh_vector_get(stores_by_tid, i, out_ts); + bh_assert(ret); + (void)ret; + + if (out_ts->tid == tid) { + *out_i = i; + return true; + } + } + + return false; +} +#endif + +static unsigned +retrive_thread_local_store_num(Vector *stores_by_tid, korp_tid tid) +{ +#ifndef os_thread_local_attribute + unsigned i = 0; + thread_local_stores ts = { 0 }; + unsigned ret = 0; + +#if defined(OS_THREAD_MUTEX_INITIALIZER) + os_mutex_lock(&engine_lock); +#endif + + if (search_thread_local_store_num(stores_by_tid, tid, &ts, &i)) + ret = ts.stores_num; + else + ret = 0; + +#if defined(OS_THREAD_MUTEX_INITIALIZER) + os_mutex_unlock(&engine_lock); +#endif + + return ret; +#else + (void)stores_by_tid; + (void)tid; + + return thread_local_stores_num; +#endif +} + +static bool +increase_thread_local_store_num(Vector *stores_by_tid, korp_tid tid) +{ +#ifndef os_thread_local_attribute + unsigned i = 0; + thread_local_stores ts = { 0 }; + bool ret = false; + +#if defined(OS_THREAD_MUTEX_INITIALIZER) + os_mutex_lock(&engine_lock); +#endif + + if (search_thread_local_store_num(stores_by_tid, tid, &ts, &i)) { + /* just in case if integer overflow */ + if (ts.stores_num + 1 < ts.stores_num) { + ret = false; + } + else { + ts.stores_num++; + ret = bh_vector_set(stores_by_tid, i, &ts); + bh_assert(ret); + } + } + else { + ts.tid = tid; + ts.stores_num = 1; + ret = bh_vector_append(stores_by_tid, &ts); + } + +#if defined(OS_THREAD_MUTEX_INITIALIZER) + os_mutex_unlock(&engine_lock); +#endif + return ret; +#else + (void)stores_by_tid; + (void)tid; + + /* just in case if integer overflow */ + if (thread_local_stores_num + 1 < thread_local_stores_num) + return false; + + thread_local_stores_num++; + return true; +#endif +} + +static bool +decrease_thread_local_store_num(Vector *stores_by_tid, korp_tid tid) +{ +#ifndef os_thread_local_attribute + unsigned i = 0; + thread_local_stores ts = { 0 }; + bool ret = false; + +#if defined(OS_THREAD_MUTEX_INITIALIZER) + os_mutex_lock(&engine_lock); +#endif + + ret = search_thread_local_store_num(stores_by_tid, tid, &ts, &i); + bh_assert(ret); + + /* just in case if integer overflow */ + if (ts.stores_num - 1 > ts.stores_num) { + ret = false; + } + else { + ts.stores_num--; + ret = bh_vector_set(stores_by_tid, i, &ts); + bh_assert(ret); + } + +#if defined(OS_THREAD_MUTEX_INITIALIZER) + os_mutex_unlock(&engine_lock); +#endif + + return ret; +#else + (void)stores_by_tid; + (void)tid; + + /* just in case if integer overflow */ + if (thread_local_stores_num - 1 > thread_local_stores_num) + return false; + + thread_local_stores_num--; + return true; +#endif } wasm_store_t * @@ -367,18 +626,41 @@ wasm_store_new(wasm_engine_t *engine) { wasm_store_t *store = NULL; - if (!engine || singleton_engine != engine) { - return NULL; - } + WASM_C_DUMP_PROC_MEM(); - if (!wasm_runtime_init_thread_env()) { - LOG_ERROR("init thread environment failed"); + if (!engine || singleton_engine != engine) return NULL; + + if (!retrive_thread_local_store_num(&engine->stores_by_tid, + os_self_thread())) { + if (!wasm_runtime_init_thread_env()) { + LOG_ERROR("init thread environment failed"); + return NULL; + } + + if (!increase_thread_local_store_num(&engine->stores_by_tid, + os_self_thread())) { + wasm_runtime_destroy_thread_env(); + return NULL; + } + + if (!(store = malloc_internal(sizeof(wasm_store_t)))) { + decrease_thread_local_store_num(&singleton_engine->stores_by_tid, + os_self_thread()); + wasm_runtime_destroy_thread_env(); + return NULL; + } } + else { + if (!increase_thread_local_store_num(&engine->stores_by_tid, + os_self_thread())) + return NULL; - if (!(store = malloc_internal(sizeof(wasm_store_t)))) { - wasm_runtime_destroy_thread_env(); - return NULL; + if (!(store = malloc_internal(sizeof(wasm_store_t)))) { + decrease_thread_local_store_num(&singleton_engine->stores_by_tid, + os_self_thread()); + return NULL; + } } /* new a vector, and new its data */ @@ -393,11 +675,7 @@ wasm_store_new(wasm_engine_t *engine) goto failed; } - /* append to a store list of engine */ - if (!bh_vector_append((Vector *)singleton_engine->stores, &store)) { - LOG_DEBUG("bh_vector_append failed"); - goto failed; - } + WASM_C_DUMP_PROC_MEM(); return store; failed: @@ -408,31 +686,12 @@ wasm_store_new(wasm_engine_t *engine) void wasm_store_delete(wasm_store_t *store) { - size_t i, store_count; - if (!store) { return; } - /* remove it from the list in the engine */ - store_count = bh_vector_size((Vector *)singleton_engine->stores); - for (i = 0; i != store_count; ++i) { - wasm_store_t *tmp; - - if (!bh_vector_get((Vector *)singleton_engine->stores, (uint32)i, - &tmp)) { - break; - } - - if (tmp == store) { - bh_vector_remove((Vector *)singleton_engine->stores, (uint32)i, - NULL); - break; - } - } - - DEINIT_VEC(store->modules, wasm_module_vec_delete); DEINIT_VEC(store->instances, wasm_instance_vec_delete); + DEINIT_VEC(store->modules, wasm_module_vec_delete); if (store->foreigns) { bh_vector_destroy(store->foreigns); wasm_runtime_free(store->foreigns); @@ -440,7 +699,13 @@ wasm_store_delete(wasm_store_t *store) wasm_runtime_free(store); - wasm_runtime_destroy_thread_env(); + if (decrease_thread_local_store_num(&singleton_engine->stores_by_tid, + os_self_thread())) { + if (!retrive_thread_local_store_num(&singleton_engine->stores_by_tid, + os_self_thread())) { + wasm_runtime_destroy_thread_env(); + } + } } /* Type Representations */ @@ -1196,6 +1461,30 @@ wasm_importtype_type(const wasm_importtype_t *import_type) return import_type->extern_type; } +bool +wasm_importtype_is_linked(const wasm_importtype_t *import_type) +{ + if (!import_type) + return false; + + const wasm_name_t *module_name = wasm_importtype_module(import_type); + const wasm_name_t *field_name = wasm_importtype_name(import_type); + + switch (wasm_externtype_kind(wasm_importtype_type(import_type))) { + case WASM_EXTERN_FUNC: + return wasm_runtime_is_import_func_linked(module_name->data, + field_name->data); + case WASM_EXTERN_GLOBAL: + return wasm_runtime_is_import_global_linked(module_name->data, + field_name->data); + case WASM_EXTERN_MEMORY: + case WASM_EXTERN_TABLE: + default: + break; + } + return false; +} + own wasm_exporttype_t * wasm_exporttype_new(own wasm_byte_vec_t *name, own wasm_externtype_t *extern_type) @@ -1378,6 +1667,7 @@ wasm_val_to_rt_val(WASMModuleInstanceCommon *inst_comm_rt, uint8 val_type_rt, break; } + (void)inst_comm_rt; return ret; } @@ -1599,86 +1889,61 @@ wasm_frame_func_offset(const wasm_frame_t *frame) } static wasm_trap_t * -wasm_trap_new_internal(WASMModuleInstanceCommon *inst_comm_rt, - const char *default_error_info) +wasm_trap_new_internal(wasm_store_t *store, + WASMModuleInstanceCommon *inst_comm_rt, + const char *error_info) { wasm_trap_t *trap; - const char *error_info = NULL; +#if WASM_ENABLE_DUMP_CALL_STACK != 0 wasm_instance_vec_t *instances; wasm_instance_t *frame_instance = NULL; uint32 i; - - if (!singleton_engine || !singleton_engine->stores - || !singleton_engine->stores->num_elems) { - return NULL; - } - -#if WASM_ENABLE_INTERP != 0 - if (inst_comm_rt->module_type == Wasm_Module_Bytecode) { - error_info = wasm_get_exception((WASMModuleInstance *)inst_comm_rt); - } -#endif - -#if WASM_ENABLE_AOT != 0 - if (inst_comm_rt->module_type == Wasm_Module_AoT) { - error_info = aot_get_exception((AOTModuleInstance *)inst_comm_rt); - } #endif - /* - * a wrong combination of module filetype and compilation flags - * also leads to below branch - */ - if (!error_info && !(error_info = default_error_info)) { + if (!singleton_engine) return NULL; - } if (!(trap = malloc_internal(sizeof(wasm_trap_t)))) { return NULL; } - if (!(trap->message = malloc_internal(sizeof(wasm_byte_vec_t)))) { - goto failed; - } + /* fill in message */ + if (error_info && strlen(error_info) > 0) { + if (!(trap->message = malloc_internal(sizeof(wasm_byte_vec_t)))) { + goto failed; + } - wasm_name_new_from_string_nt(trap->message, error_info); - if (strlen(error_info) && !trap->message->data) { - goto failed; + wasm_name_new_from_string_nt(trap->message, error_info); + if (!trap->message->data) { + goto failed; + } } + /* fill in frames */ #if WASM_ENABLE_DUMP_CALL_STACK != 0 -#if WASM_ENABLE_INTERP != 0 - if (inst_comm_rt->module_type == Wasm_Module_Bytecode) { - trap->frames = ((WASMModuleInstance *)inst_comm_rt)->frames; - } -#endif - -#if WASM_ENABLE_AOT != 0 - if (inst_comm_rt->module_type == Wasm_Module_AoT) { - trap->frames = ((AOTModuleInstance *)inst_comm_rt)->frames.ptr; - } -#endif -#endif /* WASM_ENABLE_DUMP_CALL_STACK != 0 */ - - /* allow a NULL frames list */ - if (!trap->frames) { - return trap; - } + trap->frames = ((WASMModuleInstance *)inst_comm_rt)->frames; - if (!(instances = singleton_engine->stores->data[0]->instances)) { - goto failed; - } + if (trap->frames) { + /* fill in instances */ + instances = store->instances; + bh_assert(instances != NULL); - for (i = 0; i < instances->num_elems; i++) { - if (instances->data[i]->inst_comm_rt == inst_comm_rt) { - frame_instance = instances->data[i]; - break; + for (i = 0; i < instances->num_elems; i++) { + if (instances->data[i]->inst_comm_rt == inst_comm_rt) { + frame_instance = instances->data[i]; + break; + } } - } - for (i = 0; i < trap->frames->num_elems; i++) { - (((wasm_frame_t *)trap->frames->data) + i)->instance = frame_instance; + for (i = 0; i < trap->frames->num_elems; i++) { + (((wasm_frame_t *)trap->frames->data) + i)->instance = + frame_instance; + } } +#else + (void)store; + (void)inst_comm_rt; +#endif /* WASM_ENABLE_DUMP_CALL_STACK != 0 */ return trap; failed: @@ -1805,6 +2070,7 @@ wasm_foreign_new_internal(wasm_store_t *store, uint32 foreign_idx_rt, } foreign->ref_cnt++; + (void)inst_comm_rt; return foreign; } @@ -1846,11 +2112,6 @@ wasm_foreign_delete(wasm_foreign_t *foreign) } } -struct wasm_module_ex_t { - struct WASMModuleCommon *module_comm_rt; - wasm_byte_vec_t *binary; -}; - static inline wasm_module_t * module_ext_to_module(wasm_module_ex_t *module_ex) { @@ -1871,25 +2132,77 @@ module_to_module_ext(wasm_module_t *module) #define MODULE_AOT(module_comm) ((AOTModule *)(*module_comm)) #endif -wasm_module_t * -wasm_module_new(wasm_store_t *store, const wasm_byte_vec_t *binary) +#if WASM_ENABLE_WASM_CACHE != 0 +static wasm_module_ex_t * +check_loaded_module(Vector *modules, char *binary_hash) { - char error_buf[128] = { 0 }; - wasm_module_ex_t *module_ex = NULL; - PackageType pkg_type; + unsigned i; + wasm_module_ex_t *module = NULL; - bh_assert(singleton_engine); + for (i = 0; i < modules->num_elems; i++) { + bh_vector_get(modules, i, &module); + if (!module) { + LOG_ERROR("Unexpected failure at %d\n", __LINE__); + return NULL; + } - if (!store || !binary || binary->size > UINT32_MAX) { - LOG_ERROR("%s failed", __FUNCTION__); - return NULL; + if (!module->ref_count) + /* deleted */ + continue; + + if (memcmp(module->hash, binary_hash, SHA256_DIGEST_LENGTH) == 0) + return module; } + return NULL; +} - pkg_type = get_package_type((uint8 *)binary->data, (uint32)binary->size); +static wasm_module_ex_t * +try_reuse_loaded_module(wasm_store_t *store, char *binary_hash) +{ + wasm_module_ex_t *cached = NULL; + wasm_module_ex_t *ret = NULL; - /* whether the combination of compilation flags are compatable with the - * package type */ - { + cached = check_loaded_module(&singleton_engine->modules, binary_hash); + if (!cached) + goto quit; + + os_mutex_lock(&cached->lock); + if (!cached->ref_count) + goto unlock; + + if (!bh_vector_append((Vector *)store->modules, &cached)) + goto unlock; + + cached->ref_count += 1; + ret = cached; + +unlock: + os_mutex_unlock(&cached->lock); +quit: + return ret; +} +#endif /* WASM_ENABLE_WASM_CACHE != 0 */ + +wasm_module_t * +wasm_module_new(wasm_store_t *store, const wasm_byte_vec_t *binary) +{ + char error_buf[128] = { 0 }; + wasm_module_ex_t *module_ex = NULL; +#if WASM_ENABLE_WASM_CACHE != 0 + char binary_hash[SHA256_DIGEST_LENGTH] = { 0 }; +#endif + + bh_assert(singleton_engine); + + if (!store || !binary || binary->size == 0 || binary->size > UINT32_MAX) + goto quit; + + /* whether the combination of compilation flags are compatable with the + * package type */ + { + PackageType pkg_type; + pkg_type = + get_package_type((uint8 *)binary->data, (uint32)binary->size); bool result = false; #if WASM_ENABLE_INTERP != 0 result = (pkg_type == Wasm_Module_Bytecode); @@ -1901,34 +2214,76 @@ wasm_module_new(wasm_store_t *store, const wasm_byte_vec_t *binary) if (!result) { LOG_VERBOSE("current building isn't compatiable with the module," "may need recompile"); + goto quit; } } +#if WASM_ENABLE_WASM_CACHE != 0 + /* if cached */ + SHA256((void *)binary->data, binary->num_elems, (uint8_t *)binary_hash); + module_ex = try_reuse_loaded_module(store, binary_hash); + if (module_ex) + return module_ext_to_module(module_ex); +#endif + + WASM_C_DUMP_PROC_MEM(); + module_ex = malloc_internal(sizeof(wasm_module_ex_t)); - if (!module_ex) { - goto failed; - } + if (!module_ex) + goto quit; - INIT_VEC(module_ex->binary, wasm_byte_vec_new, binary->size, binary->data); + module_ex->binary = malloc_internal(sizeof(wasm_byte_vec_t)); + if (!module_ex->binary) + goto free_module; + + wasm_byte_vec_copy(module_ex->binary, binary); + if (!module_ex->binary->data) + goto free_binary; module_ex->module_comm_rt = wasm_runtime_load( (uint8 *)module_ex->binary->data, (uint32)module_ex->binary->size, error_buf, (uint32)sizeof(error_buf)); if (!(module_ex->module_comm_rt)) { LOG_ERROR(error_buf); - goto failed; + goto free_vec; } - /* add it to a watching list in store */ - if (!bh_vector_append((Vector *)store->modules, &module_ex)) { - goto failed; - } + /* append it to a watching list in store */ + if (!bh_vector_append((Vector *)store->modules, &module_ex)) + goto unload; + + if (os_mutex_init(&module_ex->lock) != BHT_OK) + goto remove_last; + + if (!bh_vector_append(&singleton_engine->modules, &module_ex)) + goto destroy_lock; + +#if WASM_ENABLE_WASM_CACHE != 0 + bh_memcpy_s(module_ex->hash, sizeof(module_ex->hash), binary_hash, + sizeof(binary_hash)); +#endif + + module_ex->ref_count = 1; + + WASM_C_DUMP_PROC_MEM(); return module_ext_to_module(module_ex); -failed: +destroy_lock: + os_mutex_destroy(&module_ex->lock); +remove_last: + bh_vector_remove((Vector *)store->modules, + (uint32)(store->modules->num_elems - 1), NULL); +unload: + wasm_runtime_unload(module_ex->module_comm_rt); +free_vec: + wasm_byte_vec_delete(module_ex->binary); +free_binary: + wasm_runtime_free(module_ex->binary); +free_module: + wasm_runtime_free(module_ex); +quit: LOG_ERROR("%s failed", __FUNCTION__); - wasm_module_delete_internal(module_ext_to_module(module_ex)); return NULL; } @@ -1966,6 +2321,16 @@ wasm_module_delete_internal(wasm_module_t *module) } module_ex = module_to_module_ext(module); + + os_mutex_lock(&module_ex->lock); + + /* N -> N-1 -> 0 -> UINT32_MAX */ + module_ex->ref_count--; + if (module_ex->ref_count > 0) { + os_mutex_unlock(&module_ex->lock); + return; + } + DEINIT_VEC(module_ex->binary, wasm_byte_vec_delete); if (module_ex->module_comm_rt) { @@ -1973,13 +2338,18 @@ wasm_module_delete_internal(wasm_module_t *module) module_ex->module_comm_rt = NULL; } - wasm_runtime_free(module_ex); +#if WASM_ENABLE_WASM_CACHE != 0 + memset(module_ex->hash, 0, sizeof(module_ex->hash)); +#endif + + os_mutex_unlock(&module_ex->lock); } void wasm_module_delete(wasm_module_t *module) { /* the module will be released when releasing the store */ + (void)module; } void @@ -1995,6 +2365,9 @@ wasm_module_imports(const wasm_module_t *module, own wasm_importtype_vec_t *out) return; } + if (((const wasm_module_ex_t *)(module))->ref_count == 0) + return; + #if WASM_ENABLE_INTERP != 0 if ((*module)->module_type == Wasm_Module_Bytecode) { import_func_count = MODULE_INTERP(module)->import_function_count; @@ -2031,6 +2404,7 @@ wasm_module_imports(const wasm_module_t *module, own wasm_importtype_vec_t *out) memset(&module_name, 0, sizeof(wasm_val_vec_t)); memset(&name, 0, sizeof(wasm_val_vec_t)); extern_type = NULL; + import_type = NULL; if (i < import_func_count) { wasm_functype_t *type = NULL; @@ -2189,12 +2563,12 @@ wasm_module_imports(const wasm_module_t *module, own wasm_importtype_vec_t *out) bh_assert(extern_type); - wasm_name_new_from_string(&module_name, module_name_rt); + wasm_name_new_from_string_nt(&module_name, module_name_rt); if (strlen(module_name_rt) && !module_name.data) { goto failed; } - wasm_name_new_from_string(&name, field_name_rt); + wasm_name_new_from_string_nt(&name, field_name_rt); if (strlen(field_name_rt) && !name.data) { goto failed; } @@ -2231,6 +2605,9 @@ wasm_module_exports(const wasm_module_t *module, wasm_exporttype_vec_t *out) return; } + if (((const wasm_module_ex_t *)(module))->ref_count == 0) + return; + #if WASM_ENABLE_INTERP != 0 if ((*module)->module_type == Wasm_Module_Bytecode) { export_count = MODULE_INTERP(module)->export_count; @@ -2271,7 +2648,7 @@ wasm_module_exports(const wasm_module_t *module, wasm_exporttype_vec_t *out) } /* byte* -> wasm_byte_vec_t */ - wasm_name_new_from_string(&name, export->name); + wasm_name_new_from_string_nt(&name, export->name); if (strlen(export->name) && !name.data) { goto failed; } @@ -2379,6 +2756,127 @@ wasm_module_exports(const wasm_module_t *module, wasm_exporttype_vec_t *out) wasm_exporttype_vec_delete(out); } +#if WASM_ENABLE_JIT == 0 || WASM_ENABLE_LAZY_JIT != 0 +void +wasm_module_serialize(wasm_module_t *module, own wasm_byte_vec_t *out) +{ + (void)module; + (void)out; + LOG_ERROR("only supported serialization in JIT with eager compilation"); +} + +own wasm_module_t * +wasm_module_deserialize(wasm_store_t *module, const wasm_byte_vec_t *binary) +{ + (void)module; + (void)binary; + LOG_ERROR("only supported deserialization in JIT with eager compilation"); + return NULL; +} +#else + +extern uint8 * +aot_emit_aot_file_buf(AOTCompContext *comp_ctx, AOTCompData *comp_data, + uint32 *p_aot_file_size); +void +wasm_module_serialize(wasm_module_t *module, own wasm_byte_vec_t *out) +{ + wasm_module_ex_t *module_ex; + AOTCompContext *comp_ctx; + AOTCompData *comp_data; + uint8 *aot_file_buf = NULL; + uint32 aot_file_size = 0; + + if (!module || !out) + return; + + if (((const wasm_module_ex_t *)(module))->ref_count == 0) + return; + + module_ex = module_to_module_ext(module); + comp_ctx = ((WASMModule *)(module_ex->module_comm_rt))->comp_ctx; + comp_data = ((WASMModule *)(module_ex->module_comm_rt))->comp_data; + bh_assert(comp_ctx != NULL && comp_data != NULL); + + aot_file_buf = aot_emit_aot_file_buf(comp_ctx, comp_data, &aot_file_size); + if (!aot_file_buf) + return; + + wasm_byte_vec_new(out, aot_file_size, (wasm_byte_t *)aot_file_buf); + wasm_runtime_free(aot_file_buf); + return; +} + +own wasm_module_t * +wasm_module_deserialize(wasm_store_t *store, const wasm_byte_vec_t *binary) +{ + return wasm_module_new(store, binary); +} +#endif + +wasm_module_t * +wasm_module_obtain(wasm_store_t *store, wasm_shared_module_t *shared_module) +{ + wasm_module_ex_t *module_ex = NULL; + + if (!store || !shared_module) + return NULL; + + module_ex = (wasm_module_ex_t *)shared_module; + + os_mutex_lock(&module_ex->lock); + + /* deleting the module... */ + if (module_ex->ref_count == 0) { + LOG_WARNING("wasm_module_obtain re-enter a module under deleting."); + os_mutex_unlock(&module_ex->lock); + return NULL; + } + + /* add it to a watching list in store */ + if (!bh_vector_append((Vector *)store->modules, &module_ex)) { + os_mutex_unlock(&module_ex->lock); + return NULL; + } + + module_ex->ref_count++; + os_mutex_unlock(&module_ex->lock); + + return (wasm_module_t *)shared_module; +} + +wasm_shared_module_t * +wasm_module_share(wasm_module_t *module) +{ + wasm_module_ex_t *module_ex = NULL; + + if (!module) + return NULL; + + module_ex = (wasm_module_ex_t *)module; + + os_mutex_lock(&module_ex->lock); + + /* deleting the module... */ + if (module_ex->ref_count == 0) { + LOG_WARNING("wasm_module_share re-enter a module under deleting."); + os_mutex_unlock(&module_ex->lock); + return NULL; + } + + module_ex->ref_count++; + + os_mutex_unlock(&module_ex->lock); + + return (wasm_shared_module_t *)module; +} + +void +wasm_shared_module_delete(own wasm_shared_module_t *shared_module) +{ + wasm_module_delete_internal((wasm_module_t *)shared_module); +} + static wasm_func_t * wasm_func_new_basic(wasm_store_t *store, const wasm_functype_t *type, wasm_func_callback_t func_callback) @@ -2482,9 +2980,9 @@ wasm_func_new_internal(wasm_store_t *store, uint16 func_idx_rt, #if WASM_ENABLE_INTERP != 0 if (inst_comm_rt->module_type == Wasm_Module_Bytecode) { bh_assert(func_idx_rt - < ((WASMModuleInstance *)inst_comm_rt)->function_count); + < ((WASMModuleInstance *)inst_comm_rt)->e->function_count); WASMFunctionInstance *func_interp = - ((WASMModuleInstance *)inst_comm_rt)->functions + func_idx_rt; + ((WASMModuleInstance *)inst_comm_rt)->e->functions + func_idx_rt; type_rt = func_interp->is_import_func ? func_interp->u.func_import->func_type : func_interp->u.func->func_type; @@ -2496,7 +2994,7 @@ wasm_func_new_internal(wasm_store_t *store, uint16 func_idx_rt, /* use same index to trace the function type in AOTFuncType **func_types */ AOTModule *module_aot = - ((AOTModuleInstance *)inst_comm_rt)->aot_module.ptr; + (AOTModule *)((AOTModuleInstance *)inst_comm_rt)->module; if (func_idx_rt < module_aot->import_func_count) { type_rt = (module_aot->import_funcs + func_idx_rt)->func_type; } @@ -2536,6 +3034,20 @@ wasm_func_new_internal(wasm_store_t *store, uint16 func_idx_rt, return NULL; } +static wasm_func_t * +wasm_func_new_empty(wasm_store_t *store) +{ + wasm_func_t *func = NULL; + + if (!(func = malloc_internal(sizeof(wasm_func_t)))) + goto failed; + + func->store = store; + func->kind = WASM_EXTERN_FUNC; + + RETURN_OBJ(func, wasm_func_delete) +} + void wasm_func_delete(wasm_func_t *func) { @@ -2605,6 +3117,7 @@ params_to_argv(const wasm_val_vec_t *params, } if (!params || !params->num_elems || !params->size || !params->data) { + LOG_ERROR("the parameter params is invalid"); return false; } @@ -2662,6 +3175,7 @@ argv_to_results(const uint32 *argv, const wasm_valtype_vec_t *result_defs, } if (!results || !results->size || !results->data) { + LOG_ERROR("the parameter results is invalid"); return false; } @@ -2737,7 +3251,8 @@ wasm_func_call(const wasm_func_t *func, const wasm_val_vec_t *params, wasm_name_t message = { 0 }; wasm_trap_t *trap; - wasm_name_new_from_string(&message, "failed to call unlinked function"); + wasm_name_new_from_string_nt(&message, + "failed to call unlinked function"); trap = wasm_trap_new(func->store, &message); wasm_byte_vec_delete(&message); @@ -2748,7 +3263,7 @@ wasm_func_call(const wasm_func_t *func, const wasm_val_vec_t *params, #if WASM_ENABLE_INTERP != 0 if (func->inst_comm_rt->module_type == Wasm_Module_Bytecode) { - func_comm_rt = ((WASMModuleInstance *)func->inst_comm_rt)->functions + func_comm_rt = ((WASMModuleInstance *)func->inst_comm_rt)->e->functions + func->func_idx_rt; } #endif @@ -2758,7 +3273,7 @@ wasm_func_call(const wasm_func_t *func, const wasm_val_vec_t *params, if (!(func_comm_rt = func->func_comm_rt)) { AOTModuleInstance *inst_aot = (AOTModuleInstance *)func->inst_comm_rt; - AOTModule *module_aot = (AOTModule *)inst_aot->aot_module.ptr; + AOTModule *module_aot = (AOTModule *)inst_aot->module; uint32 export_i = 0, export_func_j = 0; for (; export_i < module_aot->export_count; ++export_i) { @@ -2766,7 +3281,7 @@ wasm_func_call(const wasm_func_t *func, const wasm_val_vec_t *params, if (export->kind == EXPORT_KIND_FUNC) { if (export->index == func->func_idx_rt) { func_comm_rt = - (AOTFunctionInstance *)inst_aot->export_funcs.ptr + (AOTFunctionInstance *)inst_aot->export_functions + export_func_j; ((wasm_func_t *)func)->func_comm_rt = func_comm_rt; break; @@ -2788,6 +3303,7 @@ wasm_func_call(const wasm_func_t *func, const wasm_val_vec_t *params, param_count = wasm_func_param_arity(func); result_count = wasm_func_result_arity(func); + alloc_count = (param_count > result_count) ? param_count : result_count; if (alloc_count > (size_t)sizeof(argv_buf) / sizeof(uint64)) { if (!(argv = malloc_internal(sizeof(uint64) * alloc_count))) { @@ -2802,7 +3318,17 @@ wasm_func_call(const wasm_func_t *func, const wasm_val_vec_t *params, goto failed; } - exec_env = wasm_runtime_get_exec_env_singleton(func->inst_comm_rt); +#ifdef OS_ENABLE_HW_BOUND_CHECK + exec_env = wasm_runtime_get_exec_env_tls(); +#endif +#if WASM_ENABLE_THREAD_MGR != 0 + if (!exec_env) { + exec_env = wasm_clusters_search_exec_env(func->inst_comm_rt); + } +#endif + if (!exec_env) { + exec_env = wasm_runtime_get_exec_env_singleton(func->inst_comm_rt); + } if (!exec_env) { goto failed; } @@ -2833,14 +3359,9 @@ wasm_func_call(const wasm_func_t *func, const wasm_val_vec_t *params, if (argv != argv_buf) wasm_runtime_free(argv); - /* trap -> exception -> trap */ - if (wasm_runtime_get_exception(func->inst_comm_rt)) { - return wasm_trap_new_internal(func->inst_comm_rt, NULL); - } - else { - return wasm_trap_new_internal(func->inst_comm_rt, - "wasm_func_call failed"); - } + return wasm_trap_new_internal( + func->store, func->inst_comm_rt, + wasm_runtime_get_exception(func->inst_comm_rt)); } size_t @@ -2901,6 +3422,25 @@ wasm_global_new(wasm_store_t *store, const wasm_globaltype_t *global_type, return NULL; } +static wasm_global_t * +wasm_global_new_empty(wasm_store_t *store) +{ + wasm_global_t *global = NULL; + + global = malloc_internal(sizeof(wasm_global_t)); + if (!global) + goto failed; + + global->store = store; + global->kind = WASM_EXTERN_GLOBAL; + + return global; +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + wasm_global_delete(global); + return NULL; +} + /* almost same with wasm_global_new */ wasm_global_t * wasm_global_copy(const wasm_global_t *src) @@ -2968,7 +3508,7 @@ interp_global_set(const WASMModuleInstance *inst_interp, uint16 global_idx_rt, const wasm_val_t *v) { const WASMGlobalInstance *global_interp = - inst_interp->globals + global_idx_rt; + inst_interp->e->globals + global_idx_rt; uint8 val_type_rt = global_interp->type; #if WASM_ENABLE_MULTI_MODULE != 0 uint8 *data = global_interp->import_global_inst @@ -2987,7 +3527,7 @@ static bool interp_global_get(const WASMModuleInstance *inst_interp, uint16 global_idx_rt, wasm_val_t *out) { - WASMGlobalInstance *global_interp = inst_interp->globals + global_idx_rt; + WASMGlobalInstance *global_interp = inst_interp->e->globals + global_idx_rt; uint8 val_type_rt = global_interp->type; #if WASM_ENABLE_MULTI_MODULE != 0 uint8 *data = global_interp->import_global_inst @@ -3007,7 +3547,7 @@ static bool aot_global_set(const AOTModuleInstance *inst_aot, uint16 global_idx_rt, const wasm_val_t *v) { - AOTModule *module_aot = inst_aot->aot_module.ptr; + AOTModule *module_aot = (AOTModule *)inst_aot->module; uint8 val_type_rt = 0; uint32 data_offset = 0; void *data = NULL; @@ -3025,7 +3565,7 @@ aot_global_set(const AOTModuleInstance *inst_aot, uint16 global_idx_rt, .type; } - data = (void *)((uint8 *)inst_aot->global_data.ptr + data_offset); + data = (void *)(inst_aot->global_data + data_offset); return wasm_val_to_rt_val((WASMModuleInstanceCommon *)inst_aot, val_type_rt, v, data); } @@ -3034,7 +3574,7 @@ static bool aot_global_get(const AOTModuleInstance *inst_aot, uint16 global_idx_rt, wasm_val_t *out) { - AOTModule *module_aot = inst_aot->aot_module.ptr; + AOTModule *module_aot = (AOTModule *)inst_aot->module; uint8 val_type_rt = 0; uint32 data_offset = 0; uint8 *data = NULL; @@ -3052,7 +3592,7 @@ aot_global_get(const AOTModuleInstance *inst_aot, uint16 global_idx_rt, .type; } - data = (uint8 *)inst_aot->global_data.ptr + data_offset; + data = inst_aot->global_data + data_offset; return rt_val_to_wasm_val(data, val_type_rt, out); } #endif @@ -3149,7 +3689,7 @@ wasm_global_new_internal(wasm_store_t *store, uint16 global_idx_rt, #if WASM_ENABLE_INTERP != 0 if (inst_comm_rt->module_type == Wasm_Module_Bytecode) { WASMGlobalInstance *global_interp = - ((WASMModuleInstance *)inst_comm_rt)->globals + global_idx_rt; + ((WASMModuleInstance *)inst_comm_rt)->e->globals + global_idx_rt; val_type_rt = global_interp->type; is_mutable = global_interp->is_mutable; init = true; @@ -3159,7 +3699,7 @@ wasm_global_new_internal(wasm_store_t *store, uint16 global_idx_rt, #if WASM_ENABLE_AOT != 0 if (inst_comm_rt->module_type == Wasm_Module_AoT) { AOTModuleInstance *inst_aot = (AOTModuleInstance *)inst_comm_rt; - AOTModule *module_aot = inst_aot->aot_module.ptr; + AOTModule *module_aot = (AOTModule *)inst_aot->module; init = true; @@ -3257,7 +3797,6 @@ wasm_table_new_internal(wasm_store_t *store, uint16 table_idx_rt, wasm_table_t *table = NULL; uint8 val_type_rt = 0; uint32 init_size = 0, max_size = 0; - bool init_flag = false; bh_assert(singleton_engine); @@ -3272,46 +3811,12 @@ wasm_table_new_internal(wasm_store_t *store, uint16 table_idx_rt, table->store = store; table->kind = WASM_EXTERN_TABLE; -#if WASM_ENABLE_INTERP != 0 - if (inst_comm_rt->module_type == Wasm_Module_Bytecode) { - WASMTableInstance *table_interp = - ((WASMModuleInstance *)inst_comm_rt)->tables[table_idx_rt]; - val_type_rt = table_interp->elem_type; - init_size = table_interp->cur_size; - max_size = table_interp->max_size; - init_flag = true; - } -#endif - -#if WASM_ENABLE_AOT != 0 - if (inst_comm_rt->module_type == Wasm_Module_AoT) { - AOTModuleInstance *inst_aot = (AOTModuleInstance *)inst_comm_rt; - AOTModule *module_aot = (AOTModule *)inst_aot->aot_module.ptr; - - if (table_idx_rt < module_aot->import_table_count) { - AOTImportTable *table_aot = - module_aot->import_tables + table_idx_rt; - val_type_rt = table_aot->elem_type; - init_size = table_aot->table_init_size; - max_size = table_aot->table_max_size; - } - else { - AOTTable *table_aot = - module_aot->tables - + (table_idx_rt - module_aot->import_table_count); - val_type_rt = table_aot->elem_type; - init_size = table_aot->table_init_size; - max_size = table_aot->table_max_size; - } - init_flag = true; - } -#endif - - /* - * a wrong combination of module filetype and compilation flags - * leads to below branch - */ - if (!init_flag) { + if (!wasm_runtime_get_table_inst_elem_type( + inst_comm_rt, table_idx_rt, &val_type_rt, &init_size, &max_size)) { + /* + * a wrong combination of module filetype and compilation flags + * leads to below branch + */ goto failed; } @@ -3400,19 +3905,18 @@ wasm_table_get(const wasm_table_t *table, wasm_table_size_t index) if (index >= table_interp->cur_size) { return NULL; } - ref_idx = ((uint32 *)table_interp->base_addr)[index]; + ref_idx = table_interp->elems[index]; } #endif #if WASM_ENABLE_AOT != 0 if (table->inst_comm_rt->module_type == Wasm_Module_AoT) { AOTModuleInstance *inst_aot = (AOTModuleInstance *)table->inst_comm_rt; - AOTTableInstance *table_aot = - (AOTTableInstance *)inst_aot->tables.ptr + table->table_idx_rt; + AOTTableInstance *table_aot = inst_aot->tables[table->table_idx_rt]; if (index >= table_aot->cur_size) { return NULL; } - ref_idx = table_aot->data[index]; + ref_idx = table_aot->elems[index]; } #endif @@ -3472,24 +3976,23 @@ wasm_table_set(wasm_table_t *table, wasm_table_size_t index, return false; } - p_ref_idx = ((uint32 *)table_interp->base_addr) + index; + p_ref_idx = table_interp->elems + index; function_count = - ((WASMModuleInstance *)table->inst_comm_rt)->function_count; + ((WASMModuleInstance *)table->inst_comm_rt)->e->function_count; } #endif #if WASM_ENABLE_AOT != 0 if (table->inst_comm_rt->module_type == Wasm_Module_AoT) { AOTModuleInstance *inst_aot = (AOTModuleInstance *)table->inst_comm_rt; - AOTModule *module_aot = (AOTModule *)inst_aot->aot_module.ptr; - AOTTableInstance *table_aot = - (AOTTableInstance *)inst_aot->tables.ptr + table->table_idx_rt; + AOTModule *module_aot = (AOTModule *)inst_aot->module; + AOTTableInstance *table_aot = inst_aot->tables[table->table_idx_rt]; if (index >= table_aot->cur_size) { return false; } - p_ref_idx = table_aot->data + index; + p_ref_idx = table_aot->elems + index; function_count = module_aot->func_count; } #endif @@ -3545,7 +4048,7 @@ wasm_table_size(const wasm_table_t *table) #if WASM_ENABLE_AOT != 0 if (table->inst_comm_rt->module_type == Wasm_Module_AoT) { AOTModuleInstance *inst_aot = (AOTModuleInstance *)table->inst_comm_rt; - AOTModule *module_aot = (AOTModule *)inst_aot->aot_module.ptr; + AOTModule *module_aot = (AOTModule *)inst_aot->module; if (table->table_idx_rt < module_aot->import_table_count) { AOTImportTable *table_aot = @@ -3660,7 +4163,7 @@ wasm_memory_new_internal(wasm_store_t *store, uint16 memory_idx_rt, #if WASM_ENABLE_AOT != 0 if (inst_comm_rt->module_type == Wasm_Module_AoT) { AOTModuleInstance *inst_aot = (AOTModuleInstance *)inst_comm_rt; - AOTModule *module_aot = (AOTModule *)(inst_aot->aot_module.ptr); + AOTModule *module_aot = (AOTModule *)inst_aot->module; if (memory_idx_rt < module_aot->import_memory_count) { min_pages = module_aot->import_memories->mem_init_page_count; @@ -3744,8 +4247,8 @@ wasm_memory_data(wasm_memory_t *memory) AOTModuleInstance *module_inst = (AOTModuleInstance *)module_inst_comm; AOTMemoryInstance *memory_inst = ((AOTMemoryInstance **) - module_inst->memories.ptr)[memory->memory_idx_rt]; - return (byte_t *)memory_inst->memory_data.ptr; + module_inst->memories)[memory->memory_idx_rt]; + return (byte_t *)memory_inst->memory_data; } #endif @@ -3772,7 +4275,8 @@ wasm_memory_data_size(const wasm_memory_t *memory) (WASMModuleInstance *)module_inst_comm; WASMMemoryInstance *memory_inst = module_inst->memories[memory->memory_idx_rt]; - return memory_inst->cur_page_count * memory_inst->num_bytes_per_page; + return (size_t)memory_inst->cur_page_count + * memory_inst->num_bytes_per_page; } #endif @@ -3781,8 +4285,9 @@ wasm_memory_data_size(const wasm_memory_t *memory) AOTModuleInstance *module_inst = (AOTModuleInstance *)module_inst_comm; AOTMemoryInstance *memory_inst = ((AOTMemoryInstance **) - module_inst->memories.ptr)[memory->memory_idx_rt]; - return memory_inst->cur_page_count * memory_inst->num_bytes_per_page; + module_inst->memories)[memory->memory_idx_rt]; + return (size_t)memory_inst->cur_page_count + * memory_inst->num_bytes_per_page; } #endif @@ -3818,7 +4323,7 @@ wasm_memory_size(const wasm_memory_t *memory) AOTModuleInstance *module_inst = (AOTModuleInstance *)module_inst_comm; AOTMemoryInstance *memory_inst = ((AOTMemoryInstance **) - module_inst->memories.ptr)[memory->memory_idx_rt]; + module_inst->memories)[memory->memory_idx_rt]; return memory_inst->cur_page_count; } #endif @@ -3853,6 +4358,11 @@ interp_link_func(const wasm_instance_t *inst, const WASMModule *module_interp, imported_func_interp = module_interp->import_functions + func_idx_rt; bh_assert(imported_func_interp); + bh_assert(imported_func_interp->kind == IMPORT_KIND_FUNC); + + /* it is a placeholder and let's skip it*/ + if (!import->type) + return true; /* type comparison */ if (!wasm_functype_same_internal( @@ -3860,17 +4370,18 @@ interp_link_func(const wasm_instance_t *inst, const WASMModule *module_interp, return false; imported_func_interp->u.function.call_conv_wasm_c_api = true; - imported_func_interp->u.function.wasm_c_api_with_env = import->with_env; - if (import->with_env) { + /* only set func_ptr_linked to avoid unlink warning during instantiation, + func_ptr_linked, with_env and env will be stored in module instance's + c_api_func_imports later and used when calling import function */ + if (import->with_env) imported_func_interp->u.function.func_ptr_linked = import->u.cb_env.cb; - imported_func_interp->u.function.attachment = import->u.cb_env.env; - } - else { + else imported_func_interp->u.function.func_ptr_linked = import->u.cb; - imported_func_interp->u.function.attachment = NULL; - } + bh_assert(imported_func_interp->u.function.func_ptr_linked); + import->func_idx_rt = func_idx_rt; + (void)inst; return true; } @@ -3886,12 +4397,19 @@ interp_link_global(const WASMModule *module_interp, uint16 global_idx_rt, imported_global_interp = module_interp->import_globals + global_idx_rt; bh_assert(imported_global_interp); + bh_assert(imported_global_interp->kind == IMPORT_KIND_GLOBAL); + + /* it is a placeholder and let's skip it*/ + if (!import->type) + return true; + /* type comparison */ if (!cmp_val_kind_with_val_type(wasm_valtype_kind(import->type->val_type), imported_global_interp->u.global.type)) return false; /* set init value */ + bh_assert(import->init); switch (wasm_valtype_kind(import->type->val_type)) { case WASM_I32: imported_global_interp->u.global.global_data_linked.i32 = @@ -3918,58 +4436,6 @@ interp_link_global(const WASMModule *module_interp, uint16 global_idx_rt, return true; } -static uint32 -interp_link(const wasm_instance_t *inst, const WASMModule *module_interp, - wasm_extern_t *imports[]) -{ - uint32 i = 0; - uint32 import_func_i = 0; - uint32 import_global_i = 0; - - bh_assert(inst && module_interp && imports); - - for (i = 0; i < module_interp->import_count; ++i) { - wasm_extern_t *import = imports[i]; - WASMImport *import_rt = module_interp->imports + i; - - switch (import_rt->kind) { - case IMPORT_KIND_FUNC: - { - if (!interp_link_func(inst, module_interp, import_func_i, - wasm_extern_as_func(import))) { - LOG_WARNING("link #%d function failed", import_func_i); - goto failed; - } - import_func_i++; - break; - } - case IMPORT_KIND_GLOBAL: - { - if (!interp_link_global(module_interp, import_global_i, - wasm_extern_as_global(import))) { - LOG_WARNING("link #%d global failed", import_global_i); - goto failed; - } - import_global_i++; - break; - } - case IMPORT_KIND_MEMORY: - case IMPORT_KIND_TABLE: - default: - ASSERT_NOT_IMPLEMENTED(); - LOG_WARNING("%s meets unsupported kind: %d", __FUNCTION__, - import_rt->kind); - goto failed; - } - } - - return i; - -failed: - LOG_DEBUG("%s failed", __FUNCTION__); - return (uint32)-1; -} - static bool interp_process_export(wasm_store_t *store, const WASMModuleInstance *inst_interp, @@ -4069,20 +4535,24 @@ aot_link_func(const wasm_instance_t *inst, const AOTModule *module_aot, import_aot_func = module_aot->import_funcs + import_func_idx_rt; bh_assert(import_aot_func); + /* it is a placeholder and let's skip it*/ + if (!import->type) + return true; + /* type comparison */ if (!wasm_functype_same_internal(import->type, import_aot_func->func_type)) return false; import_aot_func->call_conv_wasm_c_api = true; - import_aot_func->wasm_c_api_with_env = import->with_env; - if (import->with_env) { + /* only set func_ptr_linked to avoid unlink warning during instantiation, + func_ptr_linked, with_env and env will be stored in module instance's + c_api_func_imports later and used when calling import function */ + if (import->with_env) import_aot_func->func_ptr_linked = import->u.cb_env.cb; - import_aot_func->attachment = import->u.cb_env.env; - } - else { + else import_aot_func->func_ptr_linked = import->u.cb; - import_aot_func->attachment = NULL; - } + bh_assert(import_aot_func->func_ptr_linked); + import->func_idx_rt = import_func_idx_rt; return true; @@ -4100,6 +4570,10 @@ aot_link_global(const AOTModule *module_aot, uint16 global_idx_rt, import_aot_global = module_aot->import_globals + global_idx_rt; bh_assert(import_aot_global); + /* it is a placeholder and let's skip it*/ + if (!import->type) + return true; + val_type = wasm_globaltype_content(import->type); bh_assert(val_type); @@ -4107,6 +4581,7 @@ aot_link_global(const AOTModule *module_aot, uint16 global_idx_rt, import_aot_global->type)) return false; + bh_assert(import->init); switch (wasm_valtype_kind(val_type)) { case WASM_I32: import_aot_global->global_data_linked.i32 = import->init->of.i32; @@ -4125,68 +4600,13 @@ aot_link_global(const AOTModule *module_aot, uint16 global_idx_rt, } import->global_idx_rt = global_idx_rt; + import_aot_global->is_linked = true; return true; - failed: LOG_DEBUG("%s failed", __FUNCTION__); return false; } -static uint32 -aot_link(const wasm_instance_t *inst, const AOTModule *module_aot, - wasm_extern_t *imports[]) -{ - uint32 i = 0; - uint32 import_func_i = 0; - uint32 import_global_i = 0; - wasm_extern_t *import = NULL; - wasm_func_t *func = NULL; - wasm_global_t *global = NULL; - - bh_assert(inst && module_aot && imports); - - while (import_func_i < module_aot->import_func_count - || import_global_i < module_aot->import_global_count) { - import = imports[i++]; - - bh_assert(import); - - switch (wasm_extern_kind(import)) { - case WASM_EXTERN_FUNC: - bh_assert(import_func_i < module_aot->import_func_count); - func = wasm_extern_as_func((wasm_extern_t *)import); - if (!aot_link_func(inst, module_aot, import_func_i, func)) { - LOG_WARNING("link #%d function failed", import_func_i); - goto failed; - } - import_func_i++; - - break; - case WASM_EXTERN_GLOBAL: - bh_assert(import_global_i < module_aot->import_global_count); - global = wasm_extern_as_global((wasm_extern_t *)import); - if (!aot_link_global(module_aot, import_global_i, global)) { - LOG_WARNING("link #%d global failed", import_global_i); - goto failed; - } - import_global_i++; - - break; - case WASM_EXTERN_MEMORY: - case WASM_EXTERN_TABLE: - default: - ASSERT_NOT_IMPLEMENTED(); - goto failed; - } - } - - return i; - -failed: - LOG_DEBUG("%s failed", __FUNCTION__); - return (uint32)-1; -} - static bool aot_process_export(wasm_store_t *store, const AOTModuleInstance *inst_aot, wasm_extern_vec_t *externals) @@ -4197,7 +4617,7 @@ aot_process_export(wasm_store_t *store, const AOTModuleInstance *inst_aot, bh_assert(store && inst_aot && externals); - module_aot = (AOTModule *)inst_aot->aot_module.ptr; + module_aot = (AOTModule *)inst_aot->module; bh_assert(module_aot); for (i = 0; i < module_aot->export_count; ++i) { @@ -4262,7 +4682,7 @@ aot_process_export(wasm_store_t *store, const AOTModuleInstance *inst_aot, goto failed; } - wasm_name_new_from_string(external->name, export->name); + wasm_name_new_from_string_nt(external->name, export->name); if (strlen(export->name) && !external->name->data) { goto failed; } @@ -4280,100 +4700,223 @@ aot_process_export(wasm_store_t *store, const AOTModuleInstance *inst_aot, } #endif /* WASM_ENABLE_AOT */ +static bool +do_link(const wasm_instance_t *inst, const wasm_module_t *module, + const wasm_extern_vec_t *imports) +{ + uint32 i, import_func_i, import_global_i; + + bh_assert(inst && module); + + /* we have run a module_type check before. */ + + for (i = 0, import_func_i = 0, import_global_i = 0; i < imports->num_elems; + i++) { + wasm_extern_t *import = imports->data[i]; + + if (!import) { + LOG_ERROR("imports[%d] is NULL and it is fatal\n", i); + goto failed; + } + + switch (wasm_extern_kind(import)) { + case WASM_EXTERN_FUNC: + { + bool ret = false; +#if WASM_ENABLE_INTERP != 0 + if ((*module)->module_type == Wasm_Module_Bytecode) { + ret = interp_link_func(inst, MODULE_INTERP(module), + import_func_i, + wasm_extern_as_func(import)); + } +#endif +#if WASM_ENABLE_AOT != 0 + if ((*module)->module_type == Wasm_Module_AoT) { + ret = aot_link_func(inst, MODULE_AOT(module), import_func_i, + wasm_extern_as_func(import)); + } +#endif + if (!ret) { + LOG_WARNING("link function #%d failed", import_func_i); + goto failed; + } + + import_func_i++; + break; + } + case WASM_EXTERN_GLOBAL: + { + bool ret = false; +#if WASM_ENABLE_INTERP != 0 + if ((*module)->module_type == Wasm_Module_Bytecode) { + ret = interp_link_global(MODULE_INTERP(module), + import_global_i, + wasm_extern_as_global(import)); + } +#endif +#if WASM_ENABLE_AOT != 0 + if ((*module)->module_type == Wasm_Module_AoT) { + ret = aot_link_global(MODULE_AOT(module), import_global_i, + wasm_extern_as_global(import)); + } +#endif + if (!ret) { + LOG_WARNING("link global #%d failed", import_global_i); + goto failed; + } + + import_global_i++; + break; + } + case WASM_EXTERN_MEMORY: + case WASM_EXTERN_TABLE: + { + LOG_WARNING("doesn't support import memories and tables for " + "now, ignore them"); + break; + } + default: + { + UNREACHABLE(); + break; + } + } + } + + return true; +failed: + LOG_DEBUG("%s failed", __FUNCTION__); + return false; +} + wasm_instance_t * wasm_instance_new(wasm_store_t *store, const wasm_module_t *module, - const wasm_extern_vec_t *imports, own wasm_trap_t **traps) + const wasm_extern_vec_t *imports, own wasm_trap_t **trap) { - return wasm_instance_new_with_args(store, module, imports, traps, + return wasm_instance_new_with_args(store, module, imports, trap, KILOBYTE(32), KILOBYTE(32)); } wasm_instance_t * wasm_instance_new_with_args(wasm_store_t *store, const wasm_module_t *module, const wasm_extern_vec_t *imports, - own wasm_trap_t **traps, const uint32 stack_size, + own wasm_trap_t **trap, const uint32 stack_size, const uint32 heap_size) { - char error_buf[128] = { 0 }; - uint32 import_count = 0; - bool import_count_verified = false; + char sub_error_buf[128] = { 0 }; + char error_buf[256] = { 0 }; wasm_instance_t *instance = NULL; - uint32 i = 0; - bool processed = false; - (void)traps; + CApiFuncImport *func_import = NULL, **p_func_imports = NULL; + uint32 i = 0, import_func_count = 0; + uint64 total_size; + bool build_exported = false; bh_assert(singleton_engine); - if (!module) { + if (!module) return NULL; - } + + /* + * will do the check at the end of wasm_runtime_instantiate + */ + + WASM_C_DUMP_PROC_MEM(); instance = malloc_internal(sizeof(wasm_instance_t)); if (!instance) { + snprintf(sub_error_buf, sizeof(sub_error_buf), + "Failed to malloc instance"); goto failed; } - /* link module and imports */ - if (imports && imports->num_elems) { -#if WASM_ENABLE_INTERP != 0 - if ((*module)->module_type == Wasm_Module_Bytecode) { - import_count = MODULE_INTERP(module)->import_count; - - if (import_count) { - uint32 actual_link_import_count = - interp_link(instance, MODULE_INTERP(module), - (wasm_extern_t **)imports->data); - /* make sure a complete import list */ - if ((int32)import_count < 0 - || import_count != actual_link_import_count) { - goto failed; - } - } - import_count_verified = true; - } -#endif - -#if WASM_ENABLE_AOT != 0 - if ((*module)->module_type == Wasm_Module_AoT) { - import_count = MODULE_AOT(module)->import_func_count - + MODULE_AOT(module)->import_global_count - + MODULE_AOT(module)->import_memory_count - + MODULE_AOT(module)->import_table_count; - - if (import_count) { - import_count = aot_link(instance, MODULE_AOT(module), - (wasm_extern_t **)imports->data); - if ((int32)import_count < 0) { - goto failed; - } - } - import_count_verified = true; - } -#endif - - /* - * a wrong combination of module filetype and compilation flags - * also leads to below branch - */ - if (!import_count_verified) { + /* executes the instantiate-time linking if provided */ + if (imports) { + if (!do_link(instance, module, imports)) { + snprintf(sub_error_buf, sizeof(sub_error_buf), + "Failed to validate imports"); goto failed; } } + /* + * will do the linking result check at the end of wasm_runtime_instantiate + */ instance->inst_comm_rt = wasm_runtime_instantiate( - *module, stack_size, heap_size, error_buf, sizeof(error_buf)); + *module, stack_size, heap_size, sub_error_buf, sizeof(sub_error_buf)); if (!instance->inst_comm_rt) { - LOG_ERROR(error_buf); goto failed; } if (!wasm_runtime_create_exec_env_singleton(instance->inst_comm_rt)) { + snprintf(sub_error_buf, sizeof(sub_error_buf), + "Failed to create exec env singleton"); goto failed; } + /* create the c-api func import list */ +#if WASM_ENABLE_INTERP != 0 + if (instance->inst_comm_rt->module_type == Wasm_Module_Bytecode) { + WASMModuleInstanceExtra *e = + ((WASMModuleInstance *)instance->inst_comm_rt)->e; + p_func_imports = &(e->c_api_func_imports); + import_func_count = MODULE_INTERP(module)->import_function_count; + } +#endif +#if WASM_ENABLE_AOT != 0 + if (instance->inst_comm_rt->module_type == Wasm_Module_AoT) { + AOTModuleInstanceExtra *e = + (AOTModuleInstanceExtra *)((AOTModuleInstance *) + instance->inst_comm_rt) + ->e; + p_func_imports = &(e->c_api_func_imports); + import_func_count = MODULE_AOT(module)->import_func_count; + } +#endif + bh_assert(p_func_imports); + + total_size = (uint64)sizeof(CApiFuncImport) * import_func_count; + if (total_size > 0 + && !(*p_func_imports = func_import = malloc_internal(total_size))) { + snprintf(sub_error_buf, sizeof(sub_error_buf), + "Failed to create wasm-c-api func imports"); + goto failed; + } + + /* fill in module_inst->e->c_api_func_imports */ + for (i = 0; imports && i < imports->num_elems; i++) { + wasm_func_t *func_host = NULL; + wasm_extern_t *in = imports->data[i]; + bh_assert(in); + + if (wasm_extern_kind(in) != WASM_EXTERN_FUNC) + continue; + + func_host = wasm_extern_as_func(in); + /* it is a placeholder and let's skip it*/ + if (!func_host->type) { + func_import++; + continue; + } + + func_import->with_env_arg = func_host->with_env; + if (func_host->with_env) { + func_import->func_ptr_linked = func_host->u.cb_env.cb; + func_import->env_arg = func_host->u.cb_env.env; + } + else { + func_import->func_ptr_linked = func_host->u.cb; + func_import->env_arg = NULL; + } + bh_assert(func_import->func_ptr_linked); + + func_import++; + } + /* fill with inst */ - for (i = 0; imports && imports->data && i < (uint32)import_count; ++i) { + for (i = 0; imports && imports->data && i < imports->num_elems; ++i) { wasm_extern_t *import = imports->data[i]; + bh_assert(import); + switch (import->kind) { case WASM_EXTERN_FUNC: wasm_extern_as_func(import)->inst_comm_rt = @@ -4392,6 +4935,8 @@ wasm_instance_new_with_args(wasm_store_t *store, const wasm_module_t *module, instance->inst_comm_rt; break; default: + snprintf(sub_error_buf, sizeof(sub_error_buf), + "Unknown import kind"); goto failed; } } @@ -4408,10 +4953,12 @@ wasm_instance_new_with_args(wasm_store_t *store, const wasm_module_t *module, if (!interp_process_export(store, (WASMModuleInstance *)instance->inst_comm_rt, instance->exports)) { + snprintf(sub_error_buf, sizeof(sub_error_buf), + "Interpreter failed to process exports"); goto failed; } - processed = true; + build_exported = true; } #endif @@ -4420,8 +4967,9 @@ wasm_instance_new_with_args(wasm_store_t *store, const wasm_module_t *module, uint32 export_cnt = ((AOTModuleInstance *)instance->inst_comm_rt)->export_func_count + ((AOTModuleInstance *)instance->inst_comm_rt)->export_global_count - + ((AOTModuleInstance *)instance->inst_comm_rt)->export_tab_count - + ((AOTModuleInstance *)instance->inst_comm_rt)->export_mem_count; + + ((AOTModuleInstance *)instance->inst_comm_rt)->export_table_count + + ((AOTModuleInstance *)instance->inst_comm_rt) + ->export_memory_count; INIT_VEC(instance->exports, wasm_extern_vec_new_uninitialized, export_cnt); @@ -4429,10 +4977,12 @@ wasm_instance_new_with_args(wasm_store_t *store, const wasm_module_t *module, if (!aot_process_export(store, (AOTModuleInstance *)instance->inst_comm_rt, instance->exports)) { + snprintf(sub_error_buf, sizeof(sub_error_buf), + "AOT failed to process exports"); goto failed; } - processed = true; + build_exported = true; } #endif @@ -4440,19 +4990,33 @@ wasm_instance_new_with_args(wasm_store_t *store, const wasm_module_t *module, * a wrong combination of module filetype and compilation flags * leads to below branch */ - if (!processed) { + if (!build_exported) { + snprintf(sub_error_buf, sizeof(sub_error_buf), + "Incorrect filetype and compilation flags"); goto failed; } /* add it to a watching list in store */ if (!bh_vector_append((Vector *)store->instances, &instance)) { + snprintf(sub_error_buf, sizeof(sub_error_buf), + "Failed to add to store instances"); goto failed; } + WASM_C_DUMP_PROC_MEM(); + return instance; failed: - LOG_DEBUG("%s failed", __FUNCTION__); + snprintf(error_buf, sizeof(error_buf), "%s failed: %s", __FUNCTION__, + sub_error_buf); + if (trap != NULL) { + wasm_message_t message = { 0 }; + wasm_name_new_from_string_nt(&message, error_buf); + *trap = wasm_trap_new(store, &message); + wasm_byte_vec_delete(&message); + } + LOG_DEBUG(error_buf); wasm_instance_delete_internal(instance); return NULL; } @@ -4648,3 +5212,16 @@ BASIC_FOUR_LIST(WASM_EXTERN_AS_OTHER_CONST) BASIC_FOUR_LIST(WASM_OTHER_AS_EXTERN_CONST) #undef WASM_OTHER_AS_EXTERN_CONST + +wasm_extern_t * +wasm_extern_new_empty(wasm_store_t *store, wasm_externkind_t extern_kind) +{ + if (extern_kind == WASM_EXTERN_FUNC) + return wasm_func_as_extern(wasm_func_new_empty(store)); + + if (extern_kind == WASM_EXTERN_GLOBAL) + return wasm_global_as_extern(wasm_global_new_empty(store)); + + LOG_ERROR("Don't support linking table and memory for now"); + return NULL; +} diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/wasm_c_api_internal.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_c_api_internal.h similarity index 96% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/wasm_c_api_internal.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_c_api_internal.h index 95bc5fac171..6e05eea748c 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/wasm_c_api_internal.h +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_c_api_internal.h @@ -25,12 +25,15 @@ WASM_DECLARE_VEC(store, *) /* Runtime Environment */ struct wasm_engine_t { - /* support one store for now */ - wasm_store_vec_t *stores; - uint32_t ref_count; + uint32 ref_count; + /* list of wasm_module_ex_t */ + Vector modules; + /* list of stores which are classified according to tids */ + Vector stores_by_tid; }; struct wasm_store_t { + /* maybe should remove the list */ wasm_module_vec_t *modules; wasm_instance_vec_t *instances; Vector *foreigns; diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/wasm_exec_env.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_exec_env.c similarity index 84% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/wasm_exec_env.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_exec_env.c index ae05cce7642..622bcd71ee7 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/wasm_exec_env.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_exec_env.c @@ -56,6 +56,12 @@ wasm_exec_env_create_internal(struct WASMModuleInstanceCommon *module_inst, #endif #endif +#ifdef OS_ENABLE_HW_BOUND_CHECK + if (!(exec_env->exce_check_guard_page = + os_mmap(NULL, os_getpagesize(), MMAP_PROT_NONE, MMAP_MAP_NONE))) + goto fail5; +#endif + exec_env->module_inst = module_inst; exec_env->wasm_stack_size = stack_size; exec_env->wasm_stack.s.top_boundary = @@ -65,7 +71,7 @@ wasm_exec_env_create_internal(struct WASMModuleInstanceCommon *module_inst, #if WASM_ENABLE_AOT != 0 if (module_inst->module_type == Wasm_Module_AoT) { AOTModuleInstance *i = (AOTModuleInstance *)module_inst; - AOTModule *m = (AOTModule *)i->aot_module.ptr; + AOTModule *m = (AOTModule *)i->module; exec_env->native_symbol = m->native_symbol_list; } #endif @@ -76,6 +82,12 @@ wasm_exec_env_create_internal(struct WASMModuleInstanceCommon *module_inst, return exec_env; +#ifdef OS_ENABLE_HW_BOUND_CHECK +fail5: +#if WASM_ENABLE_THREAD_MGR != 0 && WASM_ENABLE_DEBUG_INTERP != 0 + wasm_cluster_destroy_exenv_status(exec_env->current_status); +#endif +#endif #if WASM_ENABLE_THREAD_MGR != 0 #if WASM_ENABLE_DEBUG_INTERP != 0 fail4: @@ -96,6 +108,9 @@ wasm_exec_env_create_internal(struct WASMModuleInstanceCommon *module_inst, void wasm_exec_env_destroy_internal(WASMExecEnv *exec_env) { +#ifdef OS_ENABLE_HW_BOUND_CHECK + os_munmap(exec_env->exce_check_guard_page, os_getpagesize()); +#endif #if WASM_ENABLE_THREAD_MGR != 0 os_mutex_destroy(&exec_env->wait_lock); os_cond_destroy(&exec_env->wait_cond); @@ -135,7 +150,7 @@ wasm_exec_env_create(struct WASMModuleInstanceCommon *module_inst, /* Set the aux_stack_boundary and aux_stack_bottom */ if (module_inst->module_type == Wasm_Module_AoT) { AOTModule *module = - (AOTModule *)(((AOTModuleInstance *)module_inst)->aot_module.ptr); + (AOTModule *)((AOTModuleInstance *)module_inst)->module; exec_env->aux_stack_bottom.bottom = module->aux_stack_bottom; exec_env->aux_stack_boundary.boundary = module->aux_stack_bottom - module->aux_stack_size; @@ -157,15 +172,18 @@ void wasm_exec_env_destroy(WASMExecEnv *exec_env) { #if WASM_ENABLE_THREAD_MGR != 0 - /* Terminate all sub-threads */ + /* Wait for all sub-threads */ WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env); if (cluster) { - wasm_cluster_terminate_all_except_self(cluster, exec_env); + wasm_cluster_wait_for_all_except_self(cluster, exec_env); #if WASM_ENABLE_DEBUG_INTERP != 0 /* Must fire exit event after other threads exits, otherwise the stopped thread will be overrided by other threads */ wasm_cluster_thread_exited(exec_env); #endif + /* We have waited for other threads, this is the only alive thread, so + * we don't acquire cluster->lock because the cluster will be destroyed + * inside this function */ wasm_cluster_del_exec_env(cluster, exec_env); } #endif /* end of WASM_ENABLE_THREAD_MGR */ @@ -190,9 +208,17 @@ void wasm_exec_env_set_thread_info(WASMExecEnv *exec_env) { uint8 *stack_boundary = os_thread_get_stack_boundary(); + +#if WASM_ENABLE_THREAD_MGR != 0 + os_mutex_lock(&exec_env->wait_lock); +#endif exec_env->handle = os_self_thread(); exec_env->native_stack_boundary = stack_boundary ? stack_boundary + WASM_STACK_GUARD_SIZE : NULL; + exec_env->native_stack_top_min = (void *)UINTPTR_MAX; +#if WASM_ENABLE_THREAD_MGR != 0 + os_mutex_unlock(&exec_env->wait_lock); +#endif } #if WASM_ENABLE_THREAD_MGR != 0 diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/wasm_exec_env.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_exec_env.h similarity index 89% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/wasm_exec_env.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_exec_env.h index d4d7ce00a11..29b28a15922 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/wasm_exec_env.h +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_exec_env.h @@ -84,6 +84,12 @@ typedef struct WASMExecEnv { void **native_symbol; #endif + /* + * The lowest stack pointer value observed. + * Assumption: native stack grows to the lower address. + */ + uint8 *native_stack_top_min; + #if WASM_ENABLE_FAST_JIT != 0 /** * Cache for @@ -137,6 +143,8 @@ typedef struct WASMExecEnv { #ifdef OS_ENABLE_HW_BOUND_CHECK WASMJmpBuf *jmpbuf_stack_top; + /* One guard page for the exception check */ + uint8 *exce_check_guard_page; #endif #if WASM_ENABLE_MEMORY_PROFILING != 0 @@ -163,6 +171,17 @@ typedef struct WASMExecEnv { } wasm_stack; } WASMExecEnv; +#if WASM_ENABLE_MEMORY_PROFILING != 0 +#define RECORD_STACK_USAGE(e, p) \ + do { \ + if ((e)->native_stack_top_min > (p)) { \ + (e)->native_stack_top_min = (p); \ + } \ + } while (0) +#else +#define RECORD_STACK_USAGE(e, p) (void)0 +#endif + WASMExecEnv * wasm_exec_env_create_internal(struct WASMModuleInstanceCommon *module_inst, uint32 stack_size); @@ -177,6 +196,13 @@ wasm_exec_env_create(struct WASMModuleInstanceCommon *module_inst, void wasm_exec_env_destroy(WASMExecEnv *exec_env); +static inline bool +wasm_exec_env_is_aux_stack_managed_by_runtime(WASMExecEnv *exec_env) +{ + return exec_env->aux_stack_boundary.boundary != 0 + || exec_env->aux_stack_bottom.bottom != 0; +} + /** * Allocate a WASM frame from the WASM stack. * @@ -199,7 +225,8 @@ wasm_exec_env_alloc_wasm_frame(WASMExecEnv *exec_env, unsigned size) the outs area contains const cells, its size may be larger than current frame size, we should check again before putting the function arguments into the outs area. */ - if (addr + size * 2 > exec_env->wasm_stack.s.top_boundary) { + if (size * 2 + > (uint32)(uintptr_t)(exec_env->wasm_stack.s.top_boundary - addr)) { /* WASM stack overflow. */ return NULL; } diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_memory.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_memory.c new file mode 100644 index 00000000000..82676ae271d --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_memory.c @@ -0,0 +1,759 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "wasm_runtime_common.h" +#include "../interpreter/wasm_runtime.h" +#include "bh_platform.h" +#include "mem_alloc.h" + +#if WASM_ENABLE_SHARED_MEMORY != 0 +#include "../common/wasm_shared_memory.h" +#endif + +typedef enum Memory_Mode { + MEMORY_MODE_UNKNOWN = 0, + MEMORY_MODE_POOL, + MEMORY_MODE_ALLOCATOR, + MEMORY_MODE_SYSTEM_ALLOCATOR +} Memory_Mode; + +static Memory_Mode memory_mode = MEMORY_MODE_UNKNOWN; + +static mem_allocator_t pool_allocator = NULL; + +#if WASM_MEM_ALLOC_WITH_USER_DATA != 0 +static void *allocator_user_data = NULL; +static void *(*malloc_func)(void *user_data, unsigned int size) = NULL; +static void *(*realloc_func)(void *user_data, void *ptr, + unsigned int size) = NULL; +static void (*free_func)(void *user_data, void *ptr) = NULL; +#else +static void *(*malloc_func)(unsigned int size) = NULL; +static void *(*realloc_func)(void *ptr, unsigned int size) = NULL; +static void (*free_func)(void *ptr) = NULL; +#endif + +static unsigned int global_pool_size; + +static bool +wasm_memory_init_with_pool(void *mem, unsigned int bytes) +{ + mem_allocator_t _allocator = mem_allocator_create(mem, bytes); + + if (_allocator) { + memory_mode = MEMORY_MODE_POOL; + pool_allocator = _allocator; + global_pool_size = bytes; + return true; + } + LOG_ERROR("Init memory with pool (%p, %u) failed.\n", mem, bytes); + return false; +} + +#if WASM_MEM_ALLOC_WITH_USER_DATA != 0 +static bool +wasm_memory_init_with_allocator(void *_user_data, void *_malloc_func, + void *_realloc_func, void *_free_func) +{ + if (_malloc_func && _free_func && _malloc_func != _free_func) { + memory_mode = MEMORY_MODE_ALLOCATOR; + allocator_user_data = _user_data; + malloc_func = _malloc_func; + realloc_func = _realloc_func; + free_func = _free_func; + return true; + } + LOG_ERROR("Init memory with allocator (%p, %p, %p, %p) failed.\n", + _user_data, _malloc_func, _realloc_func, _free_func); + return false; +} +#else +static bool +wasm_memory_init_with_allocator(void *_malloc_func, void *_realloc_func, + void *_free_func) +{ + if (_malloc_func && _free_func && _malloc_func != _free_func) { + memory_mode = MEMORY_MODE_ALLOCATOR; + malloc_func = _malloc_func; + realloc_func = _realloc_func; + free_func = _free_func; + return true; + } + LOG_ERROR("Init memory with allocator (%p, %p, %p) failed.\n", _malloc_func, + _realloc_func, _free_func); + return false; +} +#endif + +bool +wasm_runtime_memory_init(mem_alloc_type_t mem_alloc_type, + const MemAllocOption *alloc_option) +{ + if (mem_alloc_type == Alloc_With_Pool) { + return wasm_memory_init_with_pool(alloc_option->pool.heap_buf, + alloc_option->pool.heap_size); + } + else if (mem_alloc_type == Alloc_With_Allocator) { +#if WASM_MEM_ALLOC_WITH_USER_DATA != 0 + return wasm_memory_init_with_allocator( + alloc_option->allocator.user_data, + alloc_option->allocator.malloc_func, + alloc_option->allocator.realloc_func, + alloc_option->allocator.free_func); +#else + return wasm_memory_init_with_allocator( + alloc_option->allocator.malloc_func, + alloc_option->allocator.realloc_func, + alloc_option->allocator.free_func); +#endif + } + else if (mem_alloc_type == Alloc_With_System_Allocator) { + memory_mode = MEMORY_MODE_SYSTEM_ALLOCATOR; + return true; + } + else { + return false; + } +} + +void +wasm_runtime_memory_destroy() +{ + if (memory_mode == MEMORY_MODE_POOL) { +#if BH_ENABLE_GC_VERIFY == 0 + (void)mem_allocator_destroy(pool_allocator); +#else + int ret = mem_allocator_destroy(pool_allocator); + if (ret != 0) { + /* Memory leak detected */ + exit(-1); + } +#endif + } + memory_mode = MEMORY_MODE_UNKNOWN; +} + +unsigned +wasm_runtime_memory_pool_size() +{ + if (memory_mode == MEMORY_MODE_POOL) + return global_pool_size; + else + return UINT32_MAX; +} + +static inline void * +wasm_runtime_malloc_internal(unsigned int size) +{ + if (memory_mode == MEMORY_MODE_UNKNOWN) { + LOG_WARNING( + "wasm_runtime_malloc failed: memory hasn't been initialize.\n"); + return NULL; + } + else if (memory_mode == MEMORY_MODE_POOL) { + return mem_allocator_malloc(pool_allocator, size); + } + else if (memory_mode == MEMORY_MODE_ALLOCATOR) { +#if WASM_MEM_ALLOC_WITH_USER_DATA != 0 + return malloc_func(allocator_user_data, size); +#else + return malloc_func(size); +#endif + } + else { + return os_malloc(size); + } +} + +static inline void * +wasm_runtime_realloc_internal(void *ptr, unsigned int size) +{ + if (memory_mode == MEMORY_MODE_UNKNOWN) { + LOG_WARNING( + "wasm_runtime_realloc failed: memory hasn't been initialize.\n"); + return NULL; + } + else if (memory_mode == MEMORY_MODE_POOL) { + return mem_allocator_realloc(pool_allocator, ptr, size); + } + else if (memory_mode == MEMORY_MODE_ALLOCATOR) { + if (realloc_func) +#if WASM_MEM_ALLOC_WITH_USER_DATA != 0 + return realloc_func(allocator_user_data, ptr, size); +#else + return realloc_func(ptr, size); +#endif + else + return NULL; + } + else { + return os_realloc(ptr, size); + } +} + +static inline void +wasm_runtime_free_internal(void *ptr) +{ + if (!ptr) { + LOG_WARNING("warning: wasm_runtime_free with NULL pointer\n"); +#if BH_ENABLE_GC_VERIFY != 0 + exit(-1); +#endif + return; + } + + if (memory_mode == MEMORY_MODE_UNKNOWN) { + LOG_WARNING("warning: wasm_runtime_free failed: " + "memory hasn't been initialize.\n"); + } + else if (memory_mode == MEMORY_MODE_POOL) { + mem_allocator_free(pool_allocator, ptr); + } + else if (memory_mode == MEMORY_MODE_ALLOCATOR) { +#if WASM_MEM_ALLOC_WITH_USER_DATA != 0 + free_func(allocator_user_data, ptr); +#else + free_func(ptr); +#endif + } + else { + os_free(ptr); + } +} + +void * +wasm_runtime_malloc(unsigned int size) +{ + if (size == 0) { + LOG_WARNING("warning: wasm_runtime_malloc with size zero\n"); + /* At lease alloc 1 byte to avoid malloc failed */ + size = 1; +#if BH_ENABLE_GC_VERIFY != 0 + exit(-1); +#endif + } + + return wasm_runtime_malloc_internal(size); +} + +void * +wasm_runtime_realloc(void *ptr, unsigned int size) +{ + return wasm_runtime_realloc_internal(ptr, size); +} + +void +wasm_runtime_free(void *ptr) +{ + wasm_runtime_free_internal(ptr); +} + +bool +wasm_runtime_get_mem_alloc_info(mem_alloc_info_t *mem_alloc_info) +{ + if (memory_mode == MEMORY_MODE_POOL) { + return mem_allocator_get_alloc_info(pool_allocator, mem_alloc_info); + } + return false; +} + +bool +wasm_runtime_validate_app_addr(WASMModuleInstanceCommon *module_inst_comm, + uint32 app_offset, uint32 size) +{ + WASMModuleInstance *module_inst = (WASMModuleInstance *)module_inst_comm; + WASMMemoryInstance *memory_inst; + + bh_assert(module_inst_comm->module_type == Wasm_Module_Bytecode + || module_inst_comm->module_type == Wasm_Module_AoT); + + memory_inst = wasm_get_default_memory(module_inst); + if (!memory_inst) { + goto fail; + } + + /* integer overflow check */ + if (app_offset > UINT32_MAX - size) { + goto fail; + } + + if (app_offset + size <= memory_inst->memory_data_size) { + return true; + } + +fail: + wasm_set_exception(module_inst, "out of bounds memory access"); + return false; +} + +bool +wasm_runtime_validate_app_str_addr(WASMModuleInstanceCommon *module_inst_comm, + uint32 app_str_offset) +{ + WASMModuleInstance *module_inst = (WASMModuleInstance *)module_inst_comm; + uint32 app_end_offset; + char *str, *str_end; + + bh_assert(module_inst_comm->module_type == Wasm_Module_Bytecode + || module_inst_comm->module_type == Wasm_Module_AoT); + + if (!wasm_runtime_get_app_addr_range(module_inst_comm, app_str_offset, NULL, + &app_end_offset)) + goto fail; + + str = wasm_runtime_addr_app_to_native(module_inst_comm, app_str_offset); + str_end = str + (app_end_offset - app_str_offset); + while (str < str_end && *str != '\0') + str++; + if (str == str_end) + goto fail; + + return true; +fail: + wasm_set_exception(module_inst, "out of bounds memory access"); + return false; +} + +bool +wasm_runtime_validate_native_addr(WASMModuleInstanceCommon *module_inst_comm, + void *native_ptr, uint32 size) +{ + WASMModuleInstance *module_inst = (WASMModuleInstance *)module_inst_comm; + WASMMemoryInstance *memory_inst; + uint8 *addr = (uint8 *)native_ptr; + + bh_assert(module_inst_comm->module_type == Wasm_Module_Bytecode + || module_inst_comm->module_type == Wasm_Module_AoT); + + memory_inst = wasm_get_default_memory(module_inst); + if (!memory_inst) { + goto fail; + } + + /* integer overflow check */ + if ((uintptr_t)addr > UINTPTR_MAX - size) { + goto fail; + } + + if (memory_inst->memory_data <= addr + && addr + size <= memory_inst->memory_data_end) { + return true; + } + +fail: + wasm_set_exception(module_inst, "out of bounds memory access"); + return false; +} + +void * +wasm_runtime_addr_app_to_native(WASMModuleInstanceCommon *module_inst_comm, + uint32 app_offset) +{ + WASMModuleInstance *module_inst = (WASMModuleInstance *)module_inst_comm; + WASMMemoryInstance *memory_inst; + uint8 *addr; + + bh_assert(module_inst_comm->module_type == Wasm_Module_Bytecode + || module_inst_comm->module_type == Wasm_Module_AoT); + + memory_inst = wasm_get_default_memory(module_inst); + if (!memory_inst) { + return NULL; + } + + addr = memory_inst->memory_data + app_offset; + + if (memory_inst->memory_data <= addr && addr < memory_inst->memory_data_end) + return addr; + + return NULL; +} + +uint32 +wasm_runtime_addr_native_to_app(WASMModuleInstanceCommon *module_inst_comm, + void *native_ptr) +{ + WASMModuleInstance *module_inst = (WASMModuleInstance *)module_inst_comm; + WASMMemoryInstance *memory_inst; + uint8 *addr = (uint8 *)native_ptr; + + bh_assert(module_inst_comm->module_type == Wasm_Module_Bytecode + || module_inst_comm->module_type == Wasm_Module_AoT); + + memory_inst = wasm_get_default_memory(module_inst); + if (!memory_inst) { + return 0; + } + + if (memory_inst->memory_data <= addr && addr < memory_inst->memory_data_end) + return (uint32)(addr - memory_inst->memory_data); + + return 0; +} + +bool +wasm_runtime_get_app_addr_range(WASMModuleInstanceCommon *module_inst_comm, + uint32 app_offset, uint32 *p_app_start_offset, + uint32 *p_app_end_offset) +{ + WASMModuleInstance *module_inst = (WASMModuleInstance *)module_inst_comm; + WASMMemoryInstance *memory_inst; + uint32 memory_data_size; + + bh_assert(module_inst_comm->module_type == Wasm_Module_Bytecode + || module_inst_comm->module_type == Wasm_Module_AoT); + + memory_inst = wasm_get_default_memory(module_inst); + if (!memory_inst) { + return false; + } + + memory_data_size = memory_inst->memory_data_size; + + if (app_offset < memory_data_size) { + if (p_app_start_offset) + *p_app_start_offset = 0; + if (p_app_end_offset) + *p_app_end_offset = memory_data_size; + return true; + } + + return false; +} + +bool +wasm_runtime_get_native_addr_range(WASMModuleInstanceCommon *module_inst_comm, + uint8 *native_ptr, + uint8 **p_native_start_addr, + uint8 **p_native_end_addr) +{ + WASMModuleInstance *module_inst = (WASMModuleInstance *)module_inst_comm; + WASMMemoryInstance *memory_inst; + uint8 *addr = (uint8 *)native_ptr; + + bh_assert(module_inst_comm->module_type == Wasm_Module_Bytecode + || module_inst_comm->module_type == Wasm_Module_AoT); + + memory_inst = wasm_get_default_memory(module_inst); + if (!memory_inst) { + return false; + } + + if (memory_inst->memory_data <= addr + && addr < memory_inst->memory_data_end) { + if (p_native_start_addr) + *p_native_start_addr = memory_inst->memory_data; + if (p_native_end_addr) + *p_native_end_addr = memory_inst->memory_data_end; + return true; + } + + return false; +} + +bool +wasm_check_app_addr_and_convert(WASMModuleInstance *module_inst, bool is_str, + uint32 app_buf_addr, uint32 app_buf_size, + void **p_native_addr) +{ + WASMMemoryInstance *memory_inst = wasm_get_default_memory(module_inst); + uint8 *native_addr; + + if (!memory_inst) { + goto fail; + } + + native_addr = memory_inst->memory_data + app_buf_addr; + + /* No need to check the app_offset and buf_size if memory access + boundary check with hardware trap is enabled */ +#ifndef OS_ENABLE_HW_BOUND_CHECK + if (app_buf_addr >= memory_inst->memory_data_size) { + goto fail; + } + + if (!is_str) { + if (app_buf_size > memory_inst->memory_data_size - app_buf_addr) { + goto fail; + } + } + else { + const char *str, *str_end; + + /* The whole string must be in the linear memory */ + str = (const char *)native_addr; + str_end = (const char *)memory_inst->memory_data_end; + while (str < str_end && *str != '\0') + str++; + if (str == str_end) + goto fail; + } +#endif + + *p_native_addr = (void *)native_addr; + return true; +fail: + wasm_set_exception(module_inst, "out of bounds memory access"); + return false; +} + +WASMMemoryInstance * +wasm_get_default_memory(WASMModuleInstance *module_inst) +{ + if (module_inst->memories) + return module_inst->memories[0]; + else + return NULL; +} + +#ifndef OS_ENABLE_HW_BOUND_CHECK +bool +wasm_enlarge_memory_internal(WASMModuleInstance *module, uint32 inc_page_count) +{ + WASMMemoryInstance *memory = wasm_get_default_memory(module); + uint8 *memory_data_old, *memory_data_new, *heap_data_old; + uint32 num_bytes_per_page, heap_size, total_size_old; + uint32 cur_page_count, max_page_count, total_page_count; + uint64 total_size_new; + bool ret = true; + + if (!memory) + return false; + + heap_data_old = memory->heap_data; + heap_size = (uint32)(memory->heap_data_end - memory->heap_data); + + memory_data_old = memory->memory_data; + total_size_old = memory->memory_data_size; + + num_bytes_per_page = memory->num_bytes_per_page; + cur_page_count = memory->cur_page_count; + max_page_count = memory->max_page_count; + total_page_count = inc_page_count + cur_page_count; + total_size_new = num_bytes_per_page * (uint64)total_page_count; + + if (inc_page_count <= 0) + /* No need to enlarge memory */ + return true; + + if (total_page_count < cur_page_count /* integer overflow */ + || total_page_count > max_page_count) { + return false; + } + + bh_assert(total_size_new <= 4 * (uint64)BH_GB); + if (total_size_new > UINT32_MAX) { + /* Resize to 1 page with size 4G-1 */ + num_bytes_per_page = UINT32_MAX; + total_page_count = max_page_count = 1; + total_size_new = UINT32_MAX; + } + +#if WASM_ENABLE_SHARED_MEMORY != 0 + if (memory->is_shared) { + memory->num_bytes_per_page = num_bytes_per_page; + memory->cur_page_count = total_page_count; + memory->max_page_count = max_page_count; + /* No need to update memory->memory_data_size as it is + initialized with the maximum memory data size for + shared memory */ + return true; + } +#endif + + if (heap_size > 0) { + if (mem_allocator_is_heap_corrupted(memory->heap_handle)) { + wasm_runtime_show_app_heap_corrupted_prompt(); + return false; + } + } + + if (!(memory_data_new = + wasm_runtime_realloc(memory_data_old, (uint32)total_size_new))) { + if (!(memory_data_new = wasm_runtime_malloc((uint32)total_size_new))) { + return false; + } + if (memory_data_old) { + bh_memcpy_s(memory_data_new, (uint32)total_size_new, + memory_data_old, total_size_old); + wasm_runtime_free(memory_data_old); + } + } + + memset(memory_data_new + total_size_old, 0, + (uint32)total_size_new - total_size_old); + + if (heap_size > 0) { + if (mem_allocator_migrate(memory->heap_handle, + (char *)heap_data_old + + (memory_data_new - memory_data_old), + heap_size) + != 0) { + /* Don't return here as memory->memory_data is obsolete and + must be updated to be correctly used later. */ + ret = false; + } + } + + memory->heap_data = memory_data_new + (heap_data_old - memory_data_old); + memory->heap_data_end = memory->heap_data + heap_size; + + memory->num_bytes_per_page = num_bytes_per_page; + memory->cur_page_count = total_page_count; + memory->max_page_count = max_page_count; + memory->memory_data_size = (uint32)total_size_new; + + memory->memory_data = memory_data_new; + memory->memory_data_end = memory_data_new + (uint32)total_size_new; + +#if WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0 || WASM_ENABLE_AOT != 0 +#if UINTPTR_MAX == UINT64_MAX + memory->mem_bound_check_1byte.u64 = total_size_new - 1; + memory->mem_bound_check_2bytes.u64 = total_size_new - 2; + memory->mem_bound_check_4bytes.u64 = total_size_new - 4; + memory->mem_bound_check_8bytes.u64 = total_size_new - 8; + memory->mem_bound_check_16bytes.u64 = total_size_new - 16; +#else + memory->mem_bound_check_1byte.u32[0] = (uint32)total_size_new - 1; + memory->mem_bound_check_2bytes.u32[0] = (uint32)total_size_new - 2; + memory->mem_bound_check_4bytes.u32[0] = (uint32)total_size_new - 4; + memory->mem_bound_check_8bytes.u32[0] = (uint32)total_size_new - 8; + memory->mem_bound_check_16bytes.u32[0] = (uint32)total_size_new - 16; +#endif +#endif + + return ret; +} +#else +bool +wasm_enlarge_memory_internal(WASMModuleInstance *module, uint32 inc_page_count) +{ + WASMMemoryInstance *memory = wasm_get_default_memory(module); + uint32 num_bytes_per_page, total_size_old; + uint32 cur_page_count, max_page_count, total_page_count; + uint64 total_size_new; + + if (!memory) + return false; + + num_bytes_per_page = memory->num_bytes_per_page; + cur_page_count = memory->cur_page_count; + max_page_count = memory->max_page_count; + total_size_old = num_bytes_per_page * cur_page_count; + total_page_count = inc_page_count + cur_page_count; + total_size_new = num_bytes_per_page * (uint64)total_page_count; + + if (inc_page_count <= 0) + /* No need to enlarge memory */ + return true; + + if (total_page_count < cur_page_count /* integer overflow */ + || total_page_count > max_page_count) { + return false; + } + + bh_assert(total_size_new <= 4 * (uint64)BH_GB); + if (total_size_new > UINT32_MAX) { + /* Resize to 1 page with size 4G-1 */ + num_bytes_per_page = UINT32_MAX; + total_page_count = max_page_count = 1; + total_size_new = UINT32_MAX; + } + +#ifdef BH_PLATFORM_WINDOWS + if (!os_mem_commit(memory->memory_data_end, + (uint32)total_size_new - total_size_old, + MMAP_PROT_READ | MMAP_PROT_WRITE)) { + return false; + } +#endif + + if (os_mprotect(memory->memory_data_end, + (uint32)total_size_new - total_size_old, + MMAP_PROT_READ | MMAP_PROT_WRITE) + != 0) { +#ifdef BH_PLATFORM_WINDOWS + os_mem_decommit(memory->memory_data_end, + (uint32)total_size_new - total_size_old); +#endif + return false; + } + + /* The increased pages are filled with zero by the OS when os_mmap, + no need to memset it again here */ + + memory->num_bytes_per_page = num_bytes_per_page; + memory->cur_page_count = total_page_count; + memory->max_page_count = max_page_count; + memory->memory_data_size = (uint32)total_size_new; + memory->memory_data_end = memory->memory_data + (uint32)total_size_new; + +#if WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0 || WASM_ENABLE_AOT != 0 + memory->mem_bound_check_1byte.u64 = total_size_new - 1; + memory->mem_bound_check_2bytes.u64 = total_size_new - 2; + memory->mem_bound_check_4bytes.u64 = total_size_new - 4; + memory->mem_bound_check_8bytes.u64 = total_size_new - 8; + memory->mem_bound_check_16bytes.u64 = total_size_new - 16; +#endif + + return true; +} +#endif /* end of OS_ENABLE_HW_BOUND_CHECK */ + +bool +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); +#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); +#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 \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/wasm_memory.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_memory.h similarity index 61% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/wasm_memory.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_memory.h index b5f3f78c781..1324742fe34 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/wasm_memory.h +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_memory.h @@ -8,6 +8,7 @@ #include "bh_common.h" #include "../include/wasm_export.h" +#include "../interpreter/wasm_runtime.h" #ifdef __cplusplus extern "C" { @@ -23,6 +24,16 @@ 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 diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/wasm_native.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_native.c similarity index 85% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/wasm_native.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_native.c index eb19b619602..1acaed6eee5 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/wasm_native.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_native.c @@ -53,6 +53,17 @@ uint32 get_lib_pthread_export_apis(NativeSymbol **p_lib_pthread_apis); #endif +#if WASM_ENABLE_LIB_WASI_THREADS != 0 +bool +lib_wasi_threads_init(void); + +void +lib_wasi_threads_destroy(void); + +uint32 +get_lib_wasi_threads_export_apis(NativeSymbol **p_lib_wasi_threads_apis); +#endif + uint32 get_libc_emcc_export_apis(NativeSymbol **p_libc_emcc_apis); @@ -239,6 +250,10 @@ lookup_symbol(NativeSymbol *native_symbols, uint32 n_native_symbols, return NULL; } +/** + * allow func_type and all outputs, like p_signature, p_attachment and + * p_call_conv_raw to be NULL + */ void * wasm_native_resolve_symbol(const char *module_name, const char *field_name, const WASMType *func_type, const char **p_signature, @@ -264,10 +279,13 @@ wasm_native_resolve_symbol(const char *module_name, const char *field_name, node = node_next; } + if (!p_signature || !p_attachment || !p_call_conv_raw) + return func_ptr; + if (func_ptr) { if (signature && signature[0] != '\0') { /* signature is not empty, check its format */ - if (!check_symbol_signature(func_type, signature)) { + if (!func_type || !check_symbol_signature(func_type, signature)) { #if WASM_ENABLE_WAMR_COMPILER == 0 /* Output warning except running aot compiler */ LOG_WARNING("failed to check signature '%s' and resolve " @@ -356,11 +374,37 @@ wasm_native_register_natives_raw(const char *module_name, true); } +bool +wasm_native_unregister_natives(const char *module_name, + NativeSymbol *native_symbols) +{ + NativeSymbolsNode **prevp; + NativeSymbolsNode *node; + + prevp = &g_native_symbols_list; + while ((node = *prevp) != NULL) { + if (node->native_symbols == native_symbols + && !strcmp(node->module_name, module_name)) { + *prevp = node->next; + wasm_runtime_free(node); + return true; + } + prevp = &node->next; + } + return false; +} + bool wasm_native_init() { +#if WASM_ENABLE_SPEC_TEST != 0 || WASM_ENABLE_LIBC_BUILTIN != 0 \ + || WASM_ENABLE_BASE_LIB != 0 || WASM_ENABLE_LIBC_EMCC != 0 \ + || WASM_ENABLE_LIB_RATS != 0 || WASM_ENABLE_WASI_NN != 0 \ + || WASM_ENABLE_APP_FRAMEWORK != 0 || WASM_ENABLE_LIBC_WASI != 0 \ + || WASM_ENABLE_LIB_PTHREAD != 0 || WASM_ENABLE_LIB_WASI_THREADS != 0 NativeSymbol *native_symbols; uint32 n_native_symbols; +#endif #if WASM_ENABLE_LIBC_BUILTIN != 0 n_native_symbols = get_libc_builtin_export_apis(&native_symbols); @@ -412,6 +456,17 @@ wasm_native_init() goto fail; #endif +#if WASM_ENABLE_LIB_WASI_THREADS != 0 + if (!lib_wasi_threads_init()) + goto fail; + + n_native_symbols = get_lib_wasi_threads_export_apis(&native_symbols); + if (n_native_symbols > 0 + && !wasm_native_register_natives("wasi", native_symbols, + n_native_symbols)) + goto fail; +#endif + #if WASM_ENABLE_LIBC_EMCC != 0 n_native_symbols = get_libc_emcc_export_apis(&native_symbols); if (n_native_symbols > 0 @@ -432,13 +487,19 @@ wasm_native_init() n_native_symbols = get_wasi_nn_export_apis(&native_symbols); if (!wasm_native_register_natives("wasi_nn", native_symbols, n_native_symbols)) - return false; + goto fail; #endif return true; +#if WASM_ENABLE_SPEC_TEST != 0 || WASM_ENABLE_LIBC_BUILTIN != 0 \ + || WASM_ENABLE_BASE_LIB != 0 || WASM_ENABLE_LIBC_EMCC != 0 \ + || WASM_ENABLE_LIB_RATS != 0 || WASM_ENABLE_WASI_NN != 0 \ + || WASM_ENABLE_APP_FRAMEWORK != 0 || WASM_ENABLE_LIBC_WASI != 0 \ + || WASM_ENABLE_LIB_PTHREAD != 0 || WASM_ENABLE_LIB_WASI_THREADS != 0 fail: wasm_native_destroy(); return false; +#endif } void @@ -450,6 +511,10 @@ wasm_native_destroy() lib_pthread_destroy(); #endif +#if WASM_ENABLE_LIB_WASI_THREADS != 0 + lib_wasi_threads_destroy(); +#endif + node = g_native_symbols_list; while (node) { node_next = node->next; diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/wasm_native.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_native.h similarity index 94% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/wasm_native.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_native.h index 2777b38b2b2..4f6645d25d8 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/wasm_native.h +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_native.h @@ -64,6 +64,10 @@ wasm_native_register_natives_raw(const char *module_name, NativeSymbol *native_symbols, uint32 n_native_symbols); +bool +wasm_native_unregister_natives(const char *module_name, + NativeSymbol *native_symbols); + bool wasm_native_init(); diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/wasm_runtime_common.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_runtime_common.c similarity index 84% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/wasm_runtime_common.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_runtime_common.c index 409ea0ffecc..452a2661b93 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/wasm_runtime_common.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_runtime_common.c @@ -7,6 +7,7 @@ #include "bh_common.h" #include "bh_assert.h" #include "bh_log.h" +#include "wasm_native.h" #include "wasm_runtime_common.h" #include "wasm_memory.h" #if WASM_ENABLE_INTERP != 0 @@ -30,6 +31,9 @@ #if WASM_ENABLE_FAST_JIT != 0 #include "../fast-jit/jit_compiler.h" #endif +#if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0 +#include "../compilation/aot_llvm.h" +#endif #include "../common/wasm_c_api_internal.h" #include "../../version.h" @@ -125,6 +129,12 @@ runtime_malloc(uint64 size, WASMModuleInstanceCommon *module_inst, static JitCompOptions jit_options = { 0 }; #endif +#if WASM_ENABLE_JIT != 0 +static LLVMJITOptions llvm_jit_options = { 3, 3 }; +#endif + +static RunningMode runtime_running_mode = Mode_Default; + #ifdef OS_ENABLE_HW_BOUND_CHECK /* The exec_env of thread local storage, set before calling function and used in signal handler, as we cannot get it from the argument @@ -135,43 +145,142 @@ static os_thread_local_attribute WASMExecEnv *exec_env_tls = NULL; static void runtime_signal_handler(void *sig_addr) { - WASMModuleInstanceCommon *module_inst; - WASMSignalInfo sig_info; + WASMModuleInstance *module_inst; + WASMMemoryInstance *memory_inst; + WASMJmpBuf *jmpbuf_node; + uint8 *mapped_mem_start_addr = NULL; + uint8 *mapped_mem_end_addr = NULL; + uint32 page_size = os_getpagesize(); +#if WASM_DISABLE_STACK_HW_BOUND_CHECK == 0 + uint8 *stack_min_addr; + uint32 guard_page_count = STACK_OVERFLOW_CHECK_GUARD_PAGE_COUNT; +#endif + + /* Check whether current thread is running wasm function */ + if (exec_env_tls && exec_env_tls->handle == os_self_thread() + && (jmpbuf_node = exec_env_tls->jmpbuf_stack_top)) { + /* Get mapped mem info of current instance */ + module_inst = (WASMModuleInstance *)exec_env_tls->module_inst; + /* Get the default memory instance */ + memory_inst = wasm_get_default_memory(module_inst); + if (memory_inst) { + mapped_mem_start_addr = memory_inst->memory_data; + mapped_mem_end_addr = memory_inst->memory_data + 8 * (uint64)BH_GB; + } - sig_info.exec_env_tls = exec_env_tls; - sig_info.sig_addr = sig_addr; - if (exec_env_tls) { - module_inst = exec_env_tls->module_inst; -#if WASM_ENABLE_INTERP != 0 - if (module_inst->module_type == Wasm_Module_Bytecode) - wasm_signal_handler(&sig_info); +#if WASM_DISABLE_STACK_HW_BOUND_CHECK == 0 + /* Get stack info of current thread */ + stack_min_addr = os_thread_get_stack_boundary(); #endif -#if WASM_ENABLE_AOT != 0 - if (module_inst->module_type == Wasm_Module_AoT) - aot_signal_handler(&sig_info); + + if (memory_inst + && (mapped_mem_start_addr <= (uint8 *)sig_addr + && (uint8 *)sig_addr < mapped_mem_end_addr)) { + /* The address which causes segmentation fault is inside + the memory instance's guard regions */ + wasm_set_exception(module_inst, "out of bounds memory access"); + os_longjmp(jmpbuf_node->jmpbuf, 1); + } +#if WASM_DISABLE_STACK_HW_BOUND_CHECK == 0 + else if (stack_min_addr - page_size <= (uint8 *)sig_addr + && (uint8 *)sig_addr + < stack_min_addr + page_size * guard_page_count) { + /* The address which causes segmentation fault is inside + native thread's guard page */ + wasm_set_exception(module_inst, "native stack overflow"); + os_longjmp(jmpbuf_node->jmpbuf, 1); + } #endif + else if (exec_env_tls->exce_check_guard_page <= (uint8 *)sig_addr + && (uint8 *)sig_addr + < exec_env_tls->exce_check_guard_page + page_size) { + bh_assert(wasm_copy_exception(module_inst, NULL)); + os_longjmp(jmpbuf_node->jmpbuf, 1); + } } } #else static LONG runtime_exception_handler(EXCEPTION_POINTERS *exce_info) { - WASMModuleInstanceCommon *module_inst; - WASMSignalInfo sig_info; + PEXCEPTION_RECORD ExceptionRecord = exce_info->ExceptionRecord; + uint8 *sig_addr = (uint8 *)ExceptionRecord->ExceptionInformation[1]; + WASMModuleInstance *module_inst; + WASMMemoryInstance *memory_inst; + WASMJmpBuf *jmpbuf_node; + uint8 *mapped_mem_start_addr = NULL; + uint8 *mapped_mem_end_addr = NULL; + uint32 page_size = os_getpagesize(); + + if (exec_env_tls && exec_env_tls->handle == os_self_thread() + && (jmpbuf_node = exec_env_tls->jmpbuf_stack_top)) { + module_inst = (WASMModuleInstance *)exec_env_tls->module_inst; + if (ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) { + /* Get the default memory instance */ + memory_inst = wasm_get_default_memory(module_inst); + if (memory_inst) { + mapped_mem_start_addr = memory_inst->memory_data; + mapped_mem_end_addr = + memory_inst->memory_data + 8 * (uint64)BH_GB; + } - sig_info.exec_env_tls = exec_env_tls; - sig_info.exce_info = exce_info; - if (exec_env_tls) { - module_inst = exec_env_tls->module_inst; -#if WASM_ENABLE_INTERP != 0 - if (module_inst->module_type == Wasm_Module_Bytecode) - return wasm_exception_handler(&sig_info); -#endif -#if WASM_ENABLE_AOT != 0 - if (module_inst->module_type == Wasm_Module_AoT) - return aot_exception_handler(&sig_info); + if (memory_inst && mapped_mem_start_addr <= (uint8 *)sig_addr + && (uint8 *)sig_addr < mapped_mem_end_addr) { + /* The address which causes segmentation fault is inside + the memory instance's guard regions. + Set exception and let the wasm func continue to run, when + the wasm func returns, the caller will check whether the + exception is thrown and return to runtime. */ + wasm_set_exception(module_inst, "out of bounds memory access"); + if (module_inst->module_type == Wasm_Module_Bytecode) { + /* Continue to search next exception handler for + interpreter mode as it can be caught by + `__try { .. } __except { .. }` sentences in + wasm_runtime.c */ + return EXCEPTION_CONTINUE_SEARCH; + } + else { + /* Skip current instruction and continue to run for + AOT mode. TODO: implement unwind support for AOT + code in Windows platform */ + exce_info->ContextRecord->Rip++; + return EXCEPTION_CONTINUE_EXECUTION; + } + } + else if (exec_env_tls->exce_check_guard_page <= (uint8 *)sig_addr + && (uint8 *)sig_addr + < exec_env_tls->exce_check_guard_page + page_size) { + bh_assert(wasm_copy_exception(module_inst, NULL)); + if (module_inst->module_type == Wasm_Module_Bytecode) { + return EXCEPTION_CONTINUE_SEARCH; + } + else { + exce_info->ContextRecord->Rip++; + return EXCEPTION_CONTINUE_EXECUTION; + } + } + } +#if WASM_DISABLE_STACK_HW_BOUND_CHECK == 0 + else if (ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW) { + /* Set stack overflow exception and let the wasm func continue + to run, when the wasm func returns, the caller will check + whether the exception is thrown and return to runtime, and + the damaged stack will be recovered by _resetstkoflw(). */ + wasm_set_exception(module_inst, "native stack overflow"); + if (module_inst->module_type == Wasm_Module_Bytecode) { + return EXCEPTION_CONTINUE_SEARCH; + } + else { + return EXCEPTION_CONTINUE_EXECUTION; + } + } #endif } + + os_printf("Unhandled exception thrown: exception code: 0x%lx, " + "exception address: %p, exception information: %p\n", + ExceptionRecord->ExceptionCode, ExceptionRecord->ExceptionAddress, + sig_addr); return EXCEPTION_CONTINUE_SEARCH; } #endif /* end of BH_PLATFORM_WINDOWS */ @@ -273,8 +382,20 @@ wasm_runtime_env_init() } #endif +#if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0 + if (!aot_compiler_init()) { + goto fail10; + } +#endif + return true; +#if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0 +fail10: +#if WASM_ENABLE_FAST_JIT != 0 + jit_compiler_destroy(); +#endif +#endif #if WASM_ENABLE_FAST_JIT != 0 fail9: #if WASM_ENABLE_REF_TYPES != 0 @@ -364,6 +485,17 @@ wasm_runtime_destroy() os_mutex_destroy(®istered_module_list_lock); #endif +#if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0 + /* Destroy LLVM-JIT compiler after destroying the modules + * loaded by multi-module feature, since these modules may + * create backend threads to compile the wasm functions, + * which may access the LLVM resources. We wait until they + * finish the compilation to avoid accessing the destroyed + * resources in the compilation threads. + */ + aot_compiler_destroy(); +#endif + #if WASM_ENABLE_FAST_JIT != 0 /* Destroy Fast-JIT compiler after destroying the modules * loaded by multi-module feature, since the Fast JIT's @@ -389,6 +521,20 @@ wasm_runtime_destroy() wasm_runtime_memory_destroy(); } +RunningMode +wasm_runtime_get_default_running_mode(void) +{ + return runtime_running_mode; +} + +#if WASM_ENABLE_JIT != 0 +LLVMJITOptions +wasm_runtime_get_llvm_jit_options(void) +{ + return llvm_jit_options; +} +#endif + bool wasm_runtime_full_init(RuntimeInitArgs *init_args) { @@ -396,10 +542,20 @@ wasm_runtime_full_init(RuntimeInitArgs *init_args) &init_args->mem_alloc_option)) return false; + if (!wasm_runtime_set_default_running_mode(init_args->running_mode)) { + wasm_runtime_memory_destroy(); + return false; + } + #if WASM_ENABLE_FAST_JIT != 0 jit_options.code_cache_size = init_args->fast_jit_code_cache_size; #endif +#if WASM_ENABLE_JIT != 0 + llvm_jit_options.size_level = init_args->llvm_jit_size_level; + llvm_jit_options.opt_level = init_args->llvm_jit_opt_level; +#endif + if (!wasm_runtime_env_init()) { wasm_runtime_memory_destroy(); return false; @@ -429,9 +585,54 @@ wasm_runtime_full_init(RuntimeInitArgs *init_args) return true; } +bool +wasm_runtime_is_running_mode_supported(RunningMode running_mode) +{ + if (running_mode == Mode_Default) { + return true; + } + else if (running_mode == Mode_Interp) { +#if WASM_ENABLE_INTERP != 0 + return true; +#endif + } + else if (running_mode == Mode_Fast_JIT) { +#if WASM_ENABLE_FAST_JIT != 0 + return true; +#endif + } + else if (running_mode == Mode_LLVM_JIT) { +#if WASM_ENABLE_JIT != 0 + return true; +#endif + } + else if (running_mode == Mode_Multi_Tier_JIT) { +#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \ + && WASM_ENABLE_LAZY_JIT != 0 + return true; +#endif + } + + return false; +} + +bool +wasm_runtime_set_default_running_mode(RunningMode running_mode) +{ + if (wasm_runtime_is_running_mode_supported(running_mode)) { + runtime_running_mode = running_mode; + return true; + } + return false; +} + PackageType get_package_type(const uint8 *buf, uint32 size) { +#if (WASM_ENABLE_WORD_ALIGN_READ != 0) + uint32 buf32 = *(uint32 *)buf; + buf = (const uint8 *)&buf32; +#endif if (buf && size >= 4) { if (buf[0] == '\0' && buf[1] == 'a' && buf[2] == 's' && buf[3] == 'm') return Wasm_Module_Bytecode; @@ -912,22 +1113,7 @@ wasm_runtime_load(uint8 *buf, uint32 size, char *error_buf, WASMModuleCommon *module_common = NULL; if (get_package_type(buf, size) == Wasm_Module_Bytecode) { -#if WASM_ENABLE_AOT != 0 && WASM_ENABLE_JIT != 0 - AOTModule *aot_module; - WASMModule *module = wasm_load(buf, size, error_buf, error_buf_size); - if (!module) - return NULL; - - if (!(aot_module = - aot_convert_wasm_module(module, error_buf, error_buf_size))) { - wasm_unload(module); - return NULL; - } - - module_common = (WASMModuleCommon *)aot_module; - return register_module_with_null_name(module_common, error_buf, - error_buf_size); -#elif WASM_ENABLE_INTERP != 0 +#if WASM_ENABLE_INTERP != 0 module_common = (WASMModuleCommon *)wasm_load(buf, size, error_buf, error_buf_size); return register_module_with_null_name(module_common, error_buf, @@ -1010,20 +1196,21 @@ wasm_runtime_unload(WASMModuleCommon *module) WASMModuleInstanceCommon * wasm_runtime_instantiate_internal(WASMModuleCommon *module, bool is_sub_inst, - uint32 stack_size, uint32 heap_size, - char *error_buf, uint32 error_buf_size) + WASMExecEnv *exec_env_main, uint32 stack_size, + uint32 heap_size, char *error_buf, + uint32 error_buf_size) { #if WASM_ENABLE_INTERP != 0 if (module->module_type == Wasm_Module_Bytecode) return (WASMModuleInstanceCommon *)wasm_instantiate( - (WASMModule *)module, is_sub_inst, stack_size, heap_size, error_buf, - error_buf_size); + (WASMModule *)module, is_sub_inst, 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, stack_size, heap_size, error_buf, - error_buf_size); + (AOTModule *)module, is_sub_inst, 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"); @@ -1036,7 +1223,7 @@ wasm_runtime_instantiate(WASMModuleCommon *module, uint32 stack_size, uint32 error_buf_size) { return wasm_runtime_instantiate_internal( - module, false, stack_size, heap_size, error_buf, error_buf_size); + module, false, NULL, stack_size, heap_size, error_buf, error_buf_size); } void @@ -1057,12 +1244,53 @@ wasm_runtime_deinstantiate_internal(WASMModuleInstanceCommon *module_inst, #endif } +bool +wasm_runtime_set_running_mode(wasm_module_inst_t module_inst, + RunningMode running_mode) +{ +#if WASM_ENABLE_AOT != 0 + if (module_inst->module_type == Wasm_Module_AoT) + return true; +#endif + +#if WASM_ENABLE_INTERP != 0 + if (module_inst->module_type == Wasm_Module_Bytecode) { + WASMModuleInstance *module_inst_interp = + (WASMModuleInstance *)module_inst; + + return wasm_set_running_mode(module_inst_interp, running_mode); + } +#endif + + return false; +} + +RunningMode +wasm_runtime_get_running_mode(wasm_module_inst_t module_inst) +{ +#if WASM_ENABLE_INTERP != 0 + if (module_inst->module_type == Wasm_Module_Bytecode) { + WASMModuleInstance *module_inst_interp = + (WASMModuleInstance *)module_inst; + return module_inst_interp->e->running_mode; + } +#endif + + return Mode_Default; +} + void wasm_runtime_deinstantiate(WASMModuleInstanceCommon *module_inst) { wasm_runtime_deinstantiate_internal(module_inst, false); } +WASMModuleCommon * +wasm_runtime_get_module(WASMModuleInstanceCommon *module_inst) +{ + return (WASMModuleCommon *)((WASMModuleInstance *)module_inst)->module; +} + WASMExecEnv * wasm_runtime_create_exec_env(WASMModuleInstanceCommon *module_inst, uint32 stack_size) @@ -1235,19 +1463,18 @@ wasm_runtime_dump_mem_consumption(WASMExecEnv *exec_env) &module_inst_mem_consps); wasm_get_module_mem_consumption(wasm_module, &module_mem_consps); if (wasm_module_inst->module->aux_stack_top_global_index != (uint32)-1) - max_aux_stack_used = wasm_module_inst->max_aux_stack_used; + max_aux_stack_used = wasm_module_inst->e->max_aux_stack_used; } #endif #if WASM_ENABLE_AOT != 0 if (module_inst_common->module_type == Wasm_Module_AoT) { AOTModuleInstance *aot_module_inst = (AOTModuleInstance *)module_inst_common; - AOTModule *aot_module = (AOTModule *)aot_module_inst->aot_module.ptr; + AOTModule *aot_module = (AOTModule *)aot_module_inst->module; module_common = (WASMModuleCommon *)aot_module; - if (aot_module_inst->memories.ptr) { - AOTMemoryInstance **memories = - (AOTMemoryInstance **)aot_module_inst->memories.ptr; - heap_handle = memories[0]->heap_handle.ptr; + if (aot_module_inst->memories) { + AOTMemoryInstance **memories = aot_module_inst->memories; + heap_handle = memories[0]->heap_handle; } aot_get_module_inst_mem_consumption(aot_module_inst, &module_inst_mem_consps); @@ -1280,6 +1507,22 @@ wasm_runtime_dump_mem_consumption(WASMExecEnv *exec_env) else os_printf("Total aux stack used: no enough info to profile\n"); + /* + * Report the native stack usage estimation. + * + * Unlike the aux stack above, we report the amount unused + * because we don't know the stack "bottom". + * + * Note that this is just about what the runtime itself observed. + * It doesn't cover host func implementations, signal handlers, etc. + */ + if (exec_env->native_stack_top_min != (void *)UINTPTR_MAX) + os_printf("Native stack left: %zd\n", + exec_env->native_stack_top_min + - exec_env->native_stack_boundary); + else + os_printf("Native stack left: no enough info to profile\n"); + os_printf("Total app heap used: %u\n", app_heap_peak_size); } #endif /* end of (WASM_ENABLE_MEMORY_PROFILING != 0) \ @@ -1333,6 +1576,17 @@ wasm_runtime_get_user_data(WASMExecEnv *exec_env) return exec_env->user_data; } +#ifdef OS_ENABLE_HW_BOUND_CHECK +void +wasm_runtime_access_exce_check_guard_page() +{ + if (exec_env_tls && exec_env_tls->handle == os_self_thread()) { + uint32 page_size = os_getpagesize(); + memset(exec_env_tls->exce_check_guard_page, 0, page_size); + } +} +#endif + WASMType * wasm_runtime_get_function_type(const WASMFunctionInstanceCommon *function, uint32 module_type) @@ -1613,6 +1867,33 @@ wasm_runtime_finalize_call_function(WASMExecEnv *exec_env, } #endif +static bool +clear_wasi_proc_exit_exception(WASMModuleInstanceCommon *module_inst_comm) +{ +#if WASM_ENABLE_LIBC_WASI != 0 + bool has_exception; + char exception[EXCEPTION_BUF_LEN]; + WASMModuleInstance *module_inst = (WASMModuleInstance *)module_inst_comm; + + bh_assert(module_inst_comm->module_type == Wasm_Module_Bytecode + || module_inst_comm->module_type == Wasm_Module_AoT); + + has_exception = wasm_copy_exception(module_inst, exception); + if (has_exception && !strcmp(exception, "Exception: wasi proc exit")) { + /* The "wasi proc exit" exception is thrown by native lib to + let wasm app exit, which is a normal behavior, we clear + the exception here. And just clear the exception of current + thread, don't call `wasm_set_exception(module_inst, NULL)` + which will clear the exception of all threads. */ + module_inst->cur_exception[0] = '\0'; + return true; + } + return false; +#else + return false; +#endif +} + bool wasm_runtime_call_wasm(WASMExecEnv *exec_env, WASMFunctionInstanceCommon *function, uint32 argc, @@ -1653,10 +1934,15 @@ wasm_runtime_call_wasm(WASMExecEnv *exec_env, param_argc, new_argv); #endif if (!ret) { - if (new_argv != argv) { - wasm_runtime_free(new_argv); + if (clear_wasi_proc_exit_exception(exec_env->module_inst)) { + ret = true; + } + else { + if (new_argv != argv) { + wasm_runtime_free(new_argv); + } + return false; } - return false; } #if WASM_ENABLE_REF_TYPES != 0 @@ -1982,99 +2268,196 @@ wasm_runtime_call_wasm_v(WASMExecEnv *exec_env, } bool -wasm_runtime_create_exec_env_singleton(WASMModuleInstanceCommon *module_inst) +wasm_runtime_create_exec_env_singleton( + WASMModuleInstanceCommon *module_inst_comm) { -#if WASM_ENABLE_INTERP != 0 - if (module_inst->module_type == Wasm_Module_Bytecode) - return wasm_create_exec_env_singleton( - (WASMModuleInstance *)module_inst); -#endif -#if WASM_ENABLE_AOT != 0 - if (module_inst->module_type == Wasm_Module_AoT) - return aot_create_exec_env_singleton((AOTModuleInstance *)module_inst); -#endif - return false; + WASMModuleInstance *module_inst = (WASMModuleInstance *)module_inst_comm; + WASMExecEnv *exec_env = NULL; + + bh_assert(module_inst_comm->module_type == Wasm_Module_Bytecode + || module_inst_comm->module_type == Wasm_Module_AoT); + + if (module_inst->exec_env_singleton) { + return true; + } + + exec_env = wasm_exec_env_create(module_inst_comm, + module_inst->default_wasm_stack_size); + if (exec_env) + module_inst->exec_env_singleton = exec_env; + + return exec_env ? true : false; } WASMExecEnv * -wasm_runtime_get_exec_env_singleton(WASMModuleInstanceCommon *module_inst) +wasm_runtime_get_exec_env_singleton(WASMModuleInstanceCommon *module_inst_comm) { -#if WASM_ENABLE_INTERP != 0 - if (module_inst->module_type == Wasm_Module_Bytecode) { - if (!((WASMModuleInstance *)module_inst)->exec_env_singleton) { - wasm_create_exec_env_singleton((WASMModuleInstance *)module_inst); - } - return ((WASMModuleInstance *)module_inst)->exec_env_singleton; - } -#endif -#if WASM_ENABLE_AOT != 0 - if (module_inst->module_type == Wasm_Module_AoT) { - if (!((AOTModuleInstance *)module_inst)->exec_env_singleton.ptr) { - aot_create_exec_env_singleton((AOTModuleInstance *)module_inst); - } - return (WASMExecEnv *)((AOTModuleInstance *)module_inst) - ->exec_env_singleton.ptr; + WASMModuleInstance *module_inst = (WASMModuleInstance *)module_inst_comm; + + bh_assert(module_inst_comm->module_type == Wasm_Module_Bytecode + || module_inst_comm->module_type == Wasm_Module_AoT); + + if (!module_inst->exec_env_singleton) { + wasm_runtime_create_exec_env_singleton(module_inst_comm); } -#endif - return NULL; + return module_inst->exec_env_singleton; } void -wasm_runtime_set_exception(WASMModuleInstanceCommon *module_inst, - const char *exception) +wasm_set_exception(WASMModuleInstance *module_inst, const char *exception) { -#if WASM_ENABLE_INTERP != 0 - if (module_inst->module_type == Wasm_Module_Bytecode) { - wasm_set_exception((WASMModuleInstance *)module_inst, exception); - return; + 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); +#endif + if (exception) { + snprintf(module_inst->cur_exception, sizeof(module_inst->cur_exception), + "Exception: %s", exception); + } + else { + module_inst->cur_exception[0] = '\0'; } +#if WASM_ENABLE_SHARED_MEMORY != 0 + if (node) + os_mutex_unlock(&node->shared_mem_lock); #endif -#if WASM_ENABLE_AOT != 0 - if (module_inst->module_type == Wasm_Module_AoT) { - aot_set_exception((AOTModuleInstance *)module_inst, exception); - return; + +#if WASM_ENABLE_THREAD_MGR != 0 + exec_env = + wasm_clusters_search_exec_env((WASMModuleInstanceCommon *)module_inst); + if (exec_env) { + wasm_cluster_spread_exception(exec_env, exception ? false : true); } +#else + (void)exec_env; #endif } +/* clang-format off */ +static const char *exception_msgs[] = { + "unreachable", /* EXCE_UNREACHABLE */ + "allocate memory failed", /* EXCE_OUT_OF_MEMORY */ + "out of bounds memory access", /* EXCE_OUT_OF_BOUNDS_MEMORY_ACCESS */ + "integer overflow", /* EXCE_INTEGER_OVERFLOW */ + "integer divide by zero", /* EXCE_INTEGER_DIVIDE_BY_ZERO */ + "invalid conversion to integer", /* EXCE_INVALID_CONVERSION_TO_INTEGER */ + "indirect call type mismatch", /* EXCE_INVALID_FUNCTION_TYPE_INDEX */ + "invalid function index", /* EXCE_INVALID_FUNCTION_INDEX */ + "undefined element", /* EXCE_UNDEFINED_ELEMENT */ + "uninitialized element", /* EXCE_UNINITIALIZED_ELEMENT */ + "failed to call unlinked import function", /* EXCE_CALL_UNLINKED_IMPORT_FUNC */ + "native stack overflow", /* EXCE_NATIVE_STACK_OVERFLOW */ + "unaligned atomic", /* EXCE_UNALIGNED_ATOMIC */ + "wasm auxiliary stack overflow", /* EXCE_AUX_STACK_OVERFLOW */ + "wasm auxiliary stack underflow", /* EXCE_AUX_STACK_UNDERFLOW */ + "out of bounds table access", /* EXCE_OUT_OF_BOUNDS_TABLE_ACCESS */ + "wasm operand stack overflow", /* EXCE_OPERAND_STACK_OVERFLOW */ + "failed to compile fast jit function", /* EXCE_FAILED_TO_COMPILE_FAST_JIT_FUNC */ + "", /* EXCE_ALREADY_THROWN */ +}; +/* clang-format on */ + +void +wasm_set_exception_with_id(WASMModuleInstance *module_inst, uint32 id) +{ + if (id < EXCE_NUM) + wasm_set_exception(module_inst, exception_msgs[id]); + else + wasm_set_exception(module_inst, "unknown exception"); +} + const char * -wasm_runtime_get_exception(WASMModuleInstanceCommon *module_inst) +wasm_get_exception(WASMModuleInstance *module_inst) { -#if WASM_ENABLE_INTERP != 0 - if (module_inst->module_type == Wasm_Module_Bytecode) { - return wasm_get_exception((WASMModuleInstance *)module_inst); - } -#endif -#if WASM_ENABLE_AOT != 0 - if (module_inst->module_type == Wasm_Module_AoT) { - return aot_get_exception((AOTModuleInstance *)module_inst); + if (module_inst->cur_exception[0] == '\0') + return NULL; + else + return module_inst->cur_exception; +} + +bool +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); +#endif + if (module_inst->cur_exception[0] != '\0') { + /* NULL is passed if the caller is not interested in getting the + * exception content, but only in knowing if an exception has been + * raised + */ + if (exception_buf != NULL) + bh_memcpy_s(exception_buf, sizeof(module_inst->cur_exception), + module_inst->cur_exception, + sizeof(module_inst->cur_exception)); + has_exception = true; } +#if WASM_ENABLE_SHARED_MEMORY != 0 + if (node) + os_mutex_unlock(&node->shared_mem_lock); #endif - return NULL; + + return has_exception; } void -wasm_runtime_clear_exception(WASMModuleInstanceCommon *module_inst) +wasm_runtime_set_exception(WASMModuleInstanceCommon *module_inst_comm, + const char *exception) +{ + WASMModuleInstance *module_inst = (WASMModuleInstance *)module_inst_comm; + + bh_assert(module_inst_comm->module_type == Wasm_Module_Bytecode + || module_inst_comm->module_type == Wasm_Module_AoT); + wasm_set_exception(module_inst, exception); +} + +const char * +wasm_runtime_get_exception(WASMModuleInstanceCommon *module_inst_comm) +{ + WASMModuleInstance *module_inst = (WASMModuleInstance *)module_inst_comm; + + bh_assert(module_inst_comm->module_type == Wasm_Module_Bytecode + || module_inst_comm->module_type == Wasm_Module_AoT); + return wasm_get_exception(module_inst); +} + +bool +wasm_runtime_copy_exception(WASMModuleInstanceCommon *module_inst_comm, + char *exception_buf) { - wasm_runtime_set_exception(module_inst, NULL); + WASMModuleInstance *module_inst = (WASMModuleInstance *)module_inst_comm; + + bh_assert(module_inst_comm->module_type == Wasm_Module_Bytecode + || module_inst_comm->module_type == Wasm_Module_AoT); + return wasm_copy_exception(module_inst, exception_buf); } void -wasm_runtime_set_custom_data_internal(WASMModuleInstanceCommon *module_inst, - void *custom_data) +wasm_runtime_clear_exception(WASMModuleInstanceCommon *module_inst_comm) { -#if WASM_ENABLE_INTERP != 0 - if (module_inst->module_type == Wasm_Module_Bytecode) { - ((WASMModuleInstance *)module_inst)->custom_data = custom_data; - return; - } -#endif -#if WASM_ENABLE_AOT != 0 - if (module_inst->module_type == Wasm_Module_AoT) { - ((AOTModuleInstance *)module_inst)->custom_data.ptr = custom_data; - return; - } -#endif + bh_assert(module_inst_comm->module_type == Wasm_Module_Bytecode + || module_inst_comm->module_type == Wasm_Module_AoT); + wasm_runtime_set_exception(module_inst_comm, NULL); +} + +void +wasm_runtime_set_custom_data_internal( + WASMModuleInstanceCommon *module_inst_comm, void *custom_data) +{ + WASMModuleInstance *module_inst = (WASMModuleInstance *)module_inst_comm; + + bh_assert(module_inst_comm->module_type == Wasm_Module_Bytecode + || module_inst_comm->module_type == Wasm_Module_AoT); + module_inst->custom_data = custom_data; } void @@ -2089,17 +2472,69 @@ wasm_runtime_set_custom_data(WASMModuleInstanceCommon *module_inst, } void * -wasm_runtime_get_custom_data(WASMModuleInstanceCommon *module_inst) +wasm_runtime_get_custom_data(WASMModuleInstanceCommon *module_inst_comm) +{ + WASMModuleInstance *module_inst = (WASMModuleInstance *)module_inst_comm; + + bh_assert(module_inst_comm->module_type == Wasm_Module_Bytecode + || module_inst_comm->module_type == Wasm_Module_AoT); + return module_inst->custom_data; +} + +uint32 +wasm_runtime_module_malloc_internal(WASMModuleInstanceCommon *module_inst, + WASMExecEnv *exec_env, uint32 size, + void **p_native_addr) { #if WASM_ENABLE_INTERP != 0 if (module_inst->module_type == Wasm_Module_Bytecode) - return ((WASMModuleInstance *)module_inst)->custom_data; + return wasm_module_malloc_internal((WASMModuleInstance *)module_inst, + exec_env, size, p_native_addr); #endif #if WASM_ENABLE_AOT != 0 if (module_inst->module_type == Wasm_Module_AoT) - return ((AOTModuleInstance *)module_inst)->custom_data.ptr; + return aot_module_malloc_internal((AOTModuleInstance *)module_inst, + exec_env, size, p_native_addr); +#endif + return 0; +} + +uint32 +wasm_runtime_module_realloc_internal(WASMModuleInstanceCommon *module_inst, + WASMExecEnv *exec_env, uint32 ptr, + uint32 size, void **p_native_addr) +{ +#if WASM_ENABLE_INTERP != 0 + if (module_inst->module_type == Wasm_Module_Bytecode) + return wasm_module_realloc_internal((WASMModuleInstance *)module_inst, + exec_env, ptr, size, p_native_addr); +#endif +#if WASM_ENABLE_AOT != 0 + if (module_inst->module_type == Wasm_Module_AoT) + return aot_module_realloc_internal((AOTModuleInstance *)module_inst, + exec_env, ptr, size, p_native_addr); +#endif + return 0; +} + +void +wasm_runtime_module_free_internal(WASMModuleInstanceCommon *module_inst, + WASMExecEnv *exec_env, uint32 ptr) +{ +#if WASM_ENABLE_INTERP != 0 + if (module_inst->module_type == Wasm_Module_Bytecode) { + wasm_module_free_internal((WASMModuleInstance *)module_inst, exec_env, + ptr); + return; + } +#endif +#if WASM_ENABLE_AOT != 0 + if (module_inst->module_type == Wasm_Module_AoT) { + aot_module_free_internal((AOTModuleInstance *)module_inst, exec_env, + ptr); + return; + } #endif - return NULL; } uint32 @@ -2171,155 +2606,6 @@ wasm_runtime_module_dup_data(WASMModuleInstanceCommon *module_inst, return 0; } -bool -wasm_runtime_validate_app_addr(WASMModuleInstanceCommon *module_inst, - uint32 app_offset, uint32 size) -{ -#if WASM_ENABLE_INTERP != 0 - if (module_inst->module_type == Wasm_Module_Bytecode) - return wasm_validate_app_addr((WASMModuleInstance *)module_inst, - app_offset, size); -#endif -#if WASM_ENABLE_AOT != 0 - if (module_inst->module_type == Wasm_Module_AoT) - return aot_validate_app_addr((AOTModuleInstance *)module_inst, - app_offset, size); -#endif - return false; -} - -bool -wasm_runtime_validate_app_str_addr(WASMModuleInstanceCommon *module_inst, - uint32 app_str_offset) -{ - uint32 app_end_offset; - char *str, *str_end; - - if (!wasm_runtime_get_app_addr_range(module_inst, app_str_offset, NULL, - &app_end_offset)) - goto fail; - - str = wasm_runtime_addr_app_to_native(module_inst, app_str_offset); - str_end = str + (app_end_offset - app_str_offset); - while (str < str_end && *str != '\0') - str++; - if (str == str_end) - goto fail; - return true; - -fail: - wasm_runtime_set_exception(module_inst, "out of bounds memory access"); - return false; -} - -bool -wasm_runtime_validate_native_addr(WASMModuleInstanceCommon *module_inst, - void *native_ptr, uint32 size) -{ -#if WASM_ENABLE_INTERP != 0 - if (module_inst->module_type == Wasm_Module_Bytecode) - return wasm_validate_native_addr((WASMModuleInstance *)module_inst, - native_ptr, size); -#endif -#if WASM_ENABLE_AOT != 0 - if (module_inst->module_type == Wasm_Module_AoT) - return aot_validate_native_addr((AOTModuleInstance *)module_inst, - native_ptr, size); -#endif - return false; -} - -void * -wasm_runtime_addr_app_to_native(WASMModuleInstanceCommon *module_inst, - uint32 app_offset) -{ -#if WASM_ENABLE_INTERP != 0 - if (module_inst->module_type == Wasm_Module_Bytecode) - return wasm_addr_app_to_native((WASMModuleInstance *)module_inst, - app_offset); -#endif -#if WASM_ENABLE_AOT != 0 - if (module_inst->module_type == Wasm_Module_AoT) - return aot_addr_app_to_native((AOTModuleInstance *)module_inst, - app_offset); -#endif - return NULL; -} - -uint32 -wasm_runtime_addr_native_to_app(WASMModuleInstanceCommon *module_inst, - void *native_ptr) -{ -#if WASM_ENABLE_INTERP != 0 - if (module_inst->module_type == Wasm_Module_Bytecode) - return wasm_addr_native_to_app((WASMModuleInstance *)module_inst, - native_ptr); -#endif -#if WASM_ENABLE_AOT != 0 - if (module_inst->module_type == Wasm_Module_AoT) - return aot_addr_native_to_app((AOTModuleInstance *)module_inst, - native_ptr); -#endif - return 0; -} - -bool -wasm_runtime_get_app_addr_range(WASMModuleInstanceCommon *module_inst, - uint32 app_offset, uint32 *p_app_start_offset, - uint32 *p_app_end_offset) -{ -#if WASM_ENABLE_INTERP != 0 - if (module_inst->module_type == Wasm_Module_Bytecode) - return wasm_get_app_addr_range((WASMModuleInstance *)module_inst, - app_offset, p_app_start_offset, - p_app_end_offset); -#endif -#if WASM_ENABLE_AOT != 0 - if (module_inst->module_type == Wasm_Module_AoT) - return aot_get_app_addr_range((AOTModuleInstance *)module_inst, - app_offset, p_app_start_offset, - p_app_end_offset); -#endif - return false; -} - -bool -wasm_runtime_get_native_addr_range(WASMModuleInstanceCommon *module_inst, - uint8 *native_ptr, - uint8 **p_native_start_addr, - uint8 **p_native_end_addr) -{ -#if WASM_ENABLE_INTERP != 0 - if (module_inst->module_type == Wasm_Module_Bytecode) - return wasm_get_native_addr_range((WASMModuleInstance *)module_inst, - native_ptr, p_native_start_addr, - p_native_end_addr); -#endif -#if WASM_ENABLE_AOT != 0 - if (module_inst->module_type == Wasm_Module_AoT) - return aot_get_native_addr_range((AOTModuleInstance *)module_inst, - native_ptr, p_native_start_addr, - p_native_end_addr); -#endif - return false; -} - -bool -wasm_runtime_enlarge_memory(WASMModuleInstanceCommon *module, - uint32 inc_page_count) -{ -#if WASM_ENABLE_INTERP != 0 - if (module->module_type == Wasm_Module_Bytecode) - return wasm_enlarge_memory((WASMModuleInstance *)module, - inc_page_count); -#endif -#if WASM_ENABLE_AOT != 0 - if (module->module_type == Wasm_Module_AoT) - return aot_enlarge_memory((AOTModuleInstance *)module, inc_page_count); -#endif - return false; -} - #if WASM_ENABLE_LIBC_WASI != 0 static WASIArguments * @@ -2348,19 +2634,27 @@ wasm_runtime_set_wasi_args_ex(WASMModuleCommon *module, const char *dir_list[], { WASIArguments *wasi_args = get_wasi_args_from_module(module); - if (wasi_args) { - wasi_args->dir_list = dir_list; - wasi_args->dir_count = dir_count; - wasi_args->map_dir_list = map_dir_list; - wasi_args->map_dir_count = map_dir_count; - wasi_args->env = env_list; - wasi_args->env_count = env_count; - wasi_args->argv = argv; - wasi_args->argc = (uint32)argc; - wasi_args->stdio[0] = stdinfd; - wasi_args->stdio[1] = stdoutfd; - wasi_args->stdio[2] = stderrfd; + bh_assert(wasi_args); + + wasi_args->dir_list = dir_list; + wasi_args->dir_count = dir_count; + wasi_args->map_dir_list = map_dir_list; + wasi_args->map_dir_count = map_dir_count; + wasi_args->env = env_list; + wasi_args->env_count = env_count; + wasi_args->argv = argv; + wasi_args->argc = (uint32)argc; + wasi_args->stdio[0] = stdinfd; + wasi_args->stdio[1] = stdoutfd; + wasi_args->stdio[2] = stderrfd; + +#if WASM_ENABLE_MULTI_MODULE != 0 +#if WASM_ENABLE_INTERP != 0 + if (module->module_type == Wasm_Module_Bytecode) { + wasm_propagate_wasi_args((WASMModule *)module); } +#endif +#endif } void @@ -2477,20 +2771,8 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, wasm_runtime_set_wasi_ctx(module_inst, wasi_ctx); -#if WASM_ENABLE_INTERP != 0 - if (module_inst->module_type == Wasm_Module_Bytecode - && !((WASMModuleInstance *)module_inst)->default_memory) - return true; -#endif -#if WASM_ENABLE_AOT != 0 - if (module_inst->module_type == Wasm_Module_AoT - && !((AOTModuleInstance *)module_inst) - ->global_table_data.memory_instances[0] - .memory_data.ptr) - return true; -#endif - - /* process argv[0], trip the path and suffix, only keep the program name */ + /* process argv[0], trip the path and suffix, only keep the program name + */ if (!copy_string_array((const char **)argv, argc, &argv_buf, &argv_list, &argv_buf_size)) { set_error_buf(error_buf, error_buf_size, @@ -2548,7 +2830,11 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, } addr_pool_inited = true; - /* Prepopulate curfds with stdin, stdout, and stderr file descriptors. */ + /* Prepopulate curfds with stdin, stdout, and stderr file descriptors. + * + * If -1 is given, use STDIN_FILENO (0), STDOUT_FILENO (1), + * STDERR_FILENO (2) respectively. + */ if (!fd_table_insert_existing(curfds, 0, (stdinfd != -1) ? stdinfd : 0) || !fd_table_insert_existing(curfds, 1, (stdoutfd != -1) ? stdoutfd : 1) || !fd_table_insert_existing(curfds, 2, @@ -2710,17 +2996,18 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, char *argv[], uint32 argc, int stdinfd, int stdoutfd, int stderrfd, char *error_buf, uint32 error_buf_size) { - uvwasi_t *uvwasi = NULL; + WASIContext *ctx; + uvwasi_t *uvwasi; uvwasi_options_t init_options; const char **envp = NULL; uint64 total_size; uint32 i; bool ret = false; - uvwasi = runtime_malloc(sizeof(uvwasi_t), module_inst, error_buf, - error_buf_size); - if (!uvwasi) + ctx = runtime_malloc(sizeof(*ctx), module_inst, error_buf, error_buf_size); + if (!ctx) return false; + uvwasi = &ctx->uvwasi; /* Setup the initialization options */ uvwasi_options_init(&init_options); @@ -2768,7 +3055,7 @@ wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, goto fail; } - wasm_runtime_set_wasi_ctx(module_inst, uvwasi); + wasm_runtime_set_wasi_ctx(module_inst, ctx); ret = true; @@ -2796,7 +3083,7 @@ wasm_runtime_is_wasi_mode(WASMModuleInstanceCommon *module_inst) #endif #if WASM_ENABLE_AOT != 0 if (module_inst->module_type == Wasm_Module_AoT - && ((AOTModule *)((AOTModuleInstance *)module_inst)->aot_module.ptr) + && ((AOTModule *)((AOTModuleInstance *)module_inst)->module) ->import_wasi_api) return true; #endif @@ -2832,7 +3119,7 @@ wasm_runtime_lookup_wasi_start_function(WASMModuleInstanceCommon *module_inst) if (module_inst->module_type == Wasm_Module_AoT) { AOTModuleInstance *aot_inst = (AOTModuleInstance *)module_inst; AOTFunctionInstance *export_funcs = - (AOTFunctionInstance *)aot_inst->export_funcs.ptr; + (AOTFunctionInstance *)aot_inst->export_functions; for (i = 0; i < aot_inst->export_func_count; i++) { if (!strcmp(export_funcs[i].func_name, "_start")) { AOTFuncType *func_type = export_funcs[i].u.func.func_type; @@ -2898,56 +3185,66 @@ wasm_runtime_destroy_wasi(WASMModuleInstanceCommon *module_inst) WASIContext *wasi_ctx = wasm_runtime_get_wasi_ctx(module_inst); if (wasi_ctx) { - uvwasi_destroy(wasi_ctx); + uvwasi_destroy(&wasi_ctx->uvwasi); wasm_runtime_free(wasi_ctx); } } #endif -WASIContext * -wasm_runtime_get_wasi_ctx(WASMModuleInstanceCommon *module_inst) +uint32_t +wasm_runtime_get_wasi_exit_code(WASMModuleInstanceCommon *module_inst) { -#if WASM_ENABLE_INTERP != 0 - if (module_inst->module_type == Wasm_Module_Bytecode) - return ((WASMModuleInstance *)module_inst)->wasi_ctx; -#endif -#if WASM_ENABLE_AOT != 0 - if (module_inst->module_type == Wasm_Module_AoT) - return ((AOTModuleInstance *)module_inst)->wasi_ctx.ptr; + WASIContext *wasi_ctx = wasm_runtime_get_wasi_ctx(module_inst); +#if WASM_ENABLE_THREAD_MGR != 0 + WASMCluster *cluster; + WASMExecEnv *exec_env; + + exec_env = wasm_runtime_get_exec_env_singleton(module_inst); + if (exec_env && (cluster = wasm_exec_env_get_cluster(exec_env))) { + /** + * The main thread may exit earlier than other threads, and + * the exit_code of wasi_ctx may be changed by other thread + * when it runs into wasi_proc_exit, here we wait until all + * other threads exit to avoid getting invalid exit_code. + */ + wasm_cluster_wait_for_all_except_self(cluster, exec_env); + } #endif - return NULL; + return wasi_ctx->exit_code; +} + +WASIContext * +wasm_runtime_get_wasi_ctx(WASMModuleInstanceCommon *module_inst_comm) +{ + WASMModuleInstance *module_inst = (WASMModuleInstance *)module_inst_comm; + + bh_assert(module_inst_comm->module_type == Wasm_Module_Bytecode + || module_inst_comm->module_type == Wasm_Module_AoT); + return module_inst->wasi_ctx; } void -wasm_runtime_set_wasi_ctx(WASMModuleInstanceCommon *module_inst, +wasm_runtime_set_wasi_ctx(WASMModuleInstanceCommon *module_inst_comm, WASIContext *wasi_ctx) { -#if WASM_ENABLE_INTERP != 0 - if (module_inst->module_type == Wasm_Module_Bytecode) - ((WASMModuleInstance *)module_inst)->wasi_ctx = wasi_ctx; -#endif -#if WASM_ENABLE_AOT != 0 - if (module_inst->module_type == Wasm_Module_AoT) - ((AOTModuleInstance *)module_inst)->wasi_ctx.ptr = wasi_ctx; -#endif + WASMModuleInstance *module_inst = (WASMModuleInstance *)module_inst_comm; + + bh_assert(module_inst_comm->module_type == Wasm_Module_Bytecode + || module_inst_comm->module_type == Wasm_Module_AoT); + module_inst->wasi_ctx = wasi_ctx; } #endif /* end of WASM_ENABLE_LIBC_WASI */ WASMModuleCommon * wasm_exec_env_get_module(WASMExecEnv *exec_env) { - WASMModuleInstanceCommon *module_inst = + WASMModuleInstanceCommon *module_inst_comm = wasm_runtime_get_module_inst(exec_env); -#if WASM_ENABLE_INTERP != 0 - if (module_inst->module_type == Wasm_Module_Bytecode) - return (WASMModuleCommon *)((WASMModuleInstance *)module_inst)->module; -#endif -#if WASM_ENABLE_AOT != 0 - if (module_inst->module_type == Wasm_Module_AoT) - return (WASMModuleCommon *)((AOTModuleInstance *)module_inst) - ->aot_module.ptr; -#endif - return NULL; + WASMModuleInstance *module_inst = (WASMModuleInstance *)module_inst_comm; + + bh_assert(module_inst_comm->module_type == Wasm_Module_Bytecode + || module_inst_comm->module_type == Wasm_Module_AoT); + return (WASMModuleCommon *)module_inst->module; } #if WASM_ENABLE_LOAD_CUSTOM_SECTION != 0 @@ -2993,6 +3290,13 @@ wasm_runtime_register_natives_raw(const char *module_name, n_native_symbols); } +bool +wasm_runtime_unregister_natives(const char *module_name, + NativeSymbol *native_symbols) +{ + return wasm_native_unregister_natives(module_name, native_symbols); +} + bool wasm_runtime_invoke_native_raw(WASMExecEnv *exec_env, void *func_ptr, const WASMType *func_type, const char *signature, @@ -3131,7 +3435,7 @@ wasm_runtime_invoke_native_raw(WASMExecEnv *exec_env, void *func_ptr, } } - ret = !wasm_runtime_get_exception(module) ? true : false; + ret = !wasm_runtime_copy_exception(module, NULL); fail: if (argv1 != argv_buf) @@ -3183,7 +3487,8 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, uint32 *argv_ret) { WASMModuleInstanceCommon *module = wasm_runtime_get_module_inst(exec_env); - /* argv buf layout: int args(fix cnt) + float args(fix cnt) + stack args */ + /* argv buf layout: int args(fix cnt) + float args(fix cnt) + stack args + */ uint32 argv_buf[32], *argv1 = argv_buf, *ints, *stacks, size; uint32 *argv_src = argv, i, argc1, n_ints = 0, n_stacks = 0; uint32 arg_i32, ptr_len; @@ -3605,7 +3910,7 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, } exec_env->attachment = NULL; - ret = !wasm_runtime_get_exception(module) ? true : false; + ret = !wasm_runtime_copy_exception(module, NULL); fail: if (argv1 != argv_buf) @@ -3819,7 +4124,7 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, } exec_env->attachment = NULL; - ret = !wasm_runtime_get_exception(module) ? true : false; + ret = !wasm_runtime_copy_exception(module, NULL); fail: if (argv1 != argv_buf) @@ -4146,7 +4451,7 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, } exec_env->attachment = NULL; - ret = !wasm_runtime_get_exception(module) ? true : false; + ret = !wasm_runtime_copy_exception(module, NULL); fail: if (argv1 != argv_buf) wasm_runtime_free(argv1); @@ -4161,9 +4466,11 @@ wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, || defined(BUILD_TARGET_RISCV64_LP64) */ bool -wasm_runtime_call_indirect(WASMExecEnv *exec_env, uint32 element_indices, +wasm_runtime_call_indirect(WASMExecEnv *exec_env, uint32 element_index, uint32 argc, uint32 argv[]) { + bool ret = false; + if (!wasm_runtime_exec_env_check(exec_env)) { LOG_ERROR("Invalid exec env stack info."); return false; @@ -4175,13 +4482,18 @@ wasm_runtime_call_indirect(WASMExecEnv *exec_env, uint32 element_indices, #if WASM_ENABLE_INTERP != 0 if (exec_env->module_inst->module_type == Wasm_Module_Bytecode) - return wasm_call_indirect(exec_env, 0, element_indices, argc, argv); + ret = wasm_call_indirect(exec_env, 0, element_index, argc, argv); #endif #if WASM_ENABLE_AOT != 0 if (exec_env->module_inst->module_type == Wasm_Module_AoT) - return aot_call_indirect(exec_env, 0, element_indices, argc, argv); + ret = aot_call_indirect(exec_env, 0, element_index, argc, argv); #endif - return false; + + if (!ret && clear_wasi_proc_exit_exception(exec_env->module_inst)) { + ret = true; + } + + return ret; } static void @@ -4510,8 +4822,8 @@ interp_mark_all_externrefs(WASMModuleInstance *module_inst) WASMGlobalInstance *global; WASMTableInstance *table; - global = module_inst->globals; - for (i = 0; i < module_inst->global_count; i++, global++) { + global = module_inst->e->globals; + for (i = 0; i < module_inst->e->global_count; i++, global++) { if (global->type == VALUE_TYPE_EXTERNREF) { externref_idx = *(uint32 *)(global_data + global->data_offset); mark_externref(externref_idx); @@ -4519,14 +4831,23 @@ interp_mark_all_externrefs(WASMModuleInstance *module_inst) } for (i = 0; i < module_inst->table_count; i++) { + uint8 elem_type = 0; + uint32 init_size, max_size; + table = wasm_get_table_inst(module_inst, i); - if (table->elem_type == VALUE_TYPE_EXTERNREF) { - table_data = (uint32 *)table->base_addr; + (void)wasm_runtime_get_table_inst_elem_type( + (WASMModuleInstanceCommon *)module_inst, i, &elem_type, &init_size, + &max_size); + + if (elem_type == VALUE_TYPE_EXTERNREF) { + table_data = table->elems; for (j = 0; j < table->cur_size; j++) { externref_idx = table_data[j]; mark_externref(externref_idx); } } + (void)init_size; + (void)max_size; } } #endif @@ -4536,25 +4857,23 @@ static void aot_mark_all_externrefs(AOTModuleInstance *module_inst) { uint32 i = 0, j = 0; - const AOTModule *module = (AOTModule *)(module_inst->aot_module.ptr); + const AOTModule *module = (AOTModule *)module_inst->module; const AOTTable *table = module->tables; const AOTGlobal *global = module->globals; - const AOTTableInstance *table_inst = - (AOTTableInstance *)module_inst->tables.ptr; + const AOTTableInstance *table_inst; for (i = 0; i < module->global_count; i++, global++) { if (global->type == VALUE_TYPE_EXTERNREF) { - mark_externref(*(uint32 *)((uint8 *)module_inst->global_data.ptr - + global->data_offset)); + mark_externref( + *(uint32 *)(module_inst->global_data + global->data_offset)); } } - for (i = 0; i < module->table_count; - i++, table_inst = aot_next_tbl_inst(table_inst)) { - + for (i = 0; i < module->table_count; i++) { + table_inst = module_inst->tables[i]; if ((table + i)->elem_type == VALUE_TYPE_EXTERNREF) { while (j < table_inst->cur_size) { - mark_externref(table_inst->data[j++]); + mark_externref(table_inst->elems[j++]); } } } @@ -4707,6 +5026,82 @@ wasm_runtime_dump_call_stack_to_buf(wasm_exec_env_t exec_env, char *buf, } #endif /* end of WASM_ENABLE_DUMP_CALL_STACK */ +bool +wasm_runtime_get_table_elem_type(const WASMModuleCommon *module_comm, + uint32 table_idx, uint8 *out_elem_type, + uint32 *out_min_size, uint32 *out_max_size) +{ +#if WASM_ENABLE_INTERP != 0 + if (module_comm->module_type == Wasm_Module_Bytecode) { + WASMModule *module = (WASMModule *)module_comm; + + if (table_idx < module->import_table_count) { + WASMTableImport *import_table = + &((module->import_tables + table_idx)->u.table); + *out_elem_type = import_table->elem_type; + *out_min_size = import_table->init_size; + *out_max_size = import_table->max_size; + } + else { + WASMTable *table = + module->tables + (table_idx - module->import_table_count); + *out_elem_type = table->elem_type; + *out_min_size = table->init_size; + *out_max_size = table->max_size; + } + return true; + } +#endif + +#if WASM_ENABLE_AOT != 0 + if (module_comm->module_type == Wasm_Module_AoT) { + AOTModule *module = (AOTModule *)module_comm; + + if (table_idx < module->import_table_count) { + AOTImportTable *import_table = module->import_tables + table_idx; + *out_elem_type = VALUE_TYPE_FUNCREF; + *out_min_size = import_table->table_init_size; + *out_max_size = import_table->table_max_size; + } + else { + AOTTable *table = + module->tables + (table_idx - module->import_table_count); + *out_elem_type = table->elem_type; + *out_min_size = table->table_init_size; + *out_max_size = table->table_max_size; + } + return true; + } +#endif + + return false; +} + +bool +wasm_runtime_get_table_inst_elem_type( + const WASMModuleInstanceCommon *module_inst_comm, uint32 table_idx, + uint8 *out_elem_type, uint32 *out_min_size, uint32 *out_max_size) +{ +#if WASM_ENABLE_INTERP != 0 + if (module_inst_comm->module_type == Wasm_Module_Bytecode) { + WASMModuleInstance *module_inst = + (WASMModuleInstance *)module_inst_comm; + return wasm_runtime_get_table_elem_type( + (WASMModuleCommon *)module_inst->module, table_idx, out_elem_type, + out_min_size, out_max_size); + } +#endif +#if WASM_ENABLE_AOT != 0 + if (module_inst_comm->module_type == Wasm_Module_AoT) { + AOTModuleInstance *module_inst = (AOTModuleInstance *)module_inst_comm; + return wasm_runtime_get_table_elem_type( + (WASMModuleCommon *)module_inst->module, table_idx, out_elem_type, + out_min_size, out_max_size); + } +#endif + return false; +} + bool wasm_runtime_get_export_func_type(const WASMModuleCommon *module_comm, const WASMExport *export, WASMType **out) @@ -4847,50 +5242,8 @@ wasm_runtime_get_export_table_type(const WASMModuleCommon *module_comm, uint8 *out_elem_type, uint32 *out_min_size, uint32 *out_max_size) { -#if WASM_ENABLE_INTERP != 0 - if (module_comm->module_type == Wasm_Module_Bytecode) { - WASMModule *module = (WASMModule *)module_comm; - - if (export->index < module->import_table_count) { - WASMTableImport *import_table = - &((module->import_tables + export->index)->u.table); - *out_elem_type = import_table->elem_type; - *out_min_size = import_table->init_size; - *out_max_size = import_table->max_size; - } - else { - WASMTable *table = - module->tables + (export->index - module->import_table_count); - *out_elem_type = table->elem_type; - *out_min_size = table->init_size; - *out_max_size = table->max_size; - } - return true; - } -#endif - -#if WASM_ENABLE_AOT != 0 - if (module_comm->module_type == Wasm_Module_AoT) { - AOTModule *module = (AOTModule *)module_comm; - - if (export->index < module->import_table_count) { - AOTImportTable *import_table = - module->import_tables + export->index; - *out_elem_type = VALUE_TYPE_FUNCREF; - *out_min_size = import_table->table_init_size; - *out_max_size = import_table->table_max_size; - } - else { - AOTTable *table = - module->tables + (export->index - module->import_table_count); - *out_elem_type = table->elem_type; - *out_min_size = table->table_init_size; - *out_max_size = table->table_max_size; - } - return true; - } -#endif - return false; + return wasm_runtime_get_table_elem_type( + module_comm, export->index, out_elem_type, out_min_size, out_max_size); } static inline bool @@ -5036,10 +5389,13 @@ wasm_runtime_invoke_c_api_native(WASMModuleInstanceCommon *module_inst, if (trap) { if (trap->message->data) { /* since trap->message->data does not end with '\0' */ - char trap_message[128] = { 0 }; - bh_memcpy_s(trap_message, 127, trap->message->data, - (trap->message->size < 127 ? (uint32)trap->message->size - : 127)); + char trap_message[108] = { 0 }; + uint32 max_size_to_copy = (uint32)sizeof(trap_message) - 1; + uint32 size_to_copy = (trap->message->size < max_size_to_copy) + ? (uint32)trap->message->size + : max_size_to_copy; + bh_memcpy_s(trap_message, (uint32)sizeof(trap_message), + trap->message->data, size_to_copy); wasm_runtime_set_exception(module_inst, trap_message); } else { @@ -5096,3 +5452,24 @@ wasm_runtime_get_version(uint32_t *major, uint32_t *minor, uint32_t *patch) *minor = WAMR_VERSION_MINOR; *patch = WAMR_VERSION_PATCH; } + +bool +wasm_runtime_is_import_func_linked(const char *module_name, + const char *func_name) +{ + return wasm_native_resolve_symbol(module_name, func_name, NULL, NULL, NULL, + NULL); +} + +bool +wasm_runtime_is_import_global_linked(const char *module_name, + const char *global_name) +{ +#if WASM_ENABLE_LIBC_BUILTIN != 0 + WASMGlobalImport global = { 0 }; + return wasm_native_lookup_libc_builtin_global(module_name, global_name, + &global); +#else + return false; +#endif +} diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/wasm_runtime_common.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_runtime_common.h similarity index 89% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/wasm_runtime_common.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_runtime_common.h index 874733975f0..00d5ba23714 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/wasm_runtime_common.h +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_runtime_common.h @@ -25,6 +25,9 @@ extern "C" { #endif +/* Internal use for setting default running mode */ +#define Mode_Default 0 + #if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS != 0 #define PUT_I64_TO_ADDR(addr, value) \ @@ -369,9 +372,13 @@ typedef struct WASIContext { char **argv_list; char *env_buf; char **env_list; + uint32_t exit_code; } WASIContext; #else -typedef uvwasi_t WASIContext; +typedef struct WASIContext { + uvwasi_t uvwasi; + uint32_t exit_code; +} WASIContext; #endif #endif @@ -409,6 +416,13 @@ typedef struct wasm_frame_t { const char *func_name_wp; } WASMCApiFrame; +#ifdef WASM_ENABLE_JIT +typedef struct LLVMJITOptions { + uint32 opt_level; + uint32 size_level; +} LLVMJITOptions; +#endif + #ifdef OS_ENABLE_HW_BOUND_CHECK /* Signal info passing to interp/aot signal handler */ typedef struct WASMSignalInfo { @@ -433,10 +447,28 @@ wasm_runtime_get_exec_env_tls(void); WASM_RUNTIME_API_EXTERN bool wasm_runtime_init(void); +/* Internal API */ +RunningMode +wasm_runtime_get_default_running_mode(void); + +#if WASM_ENABLE_JIT != 0 +/* Internal API */ +LLVMJITOptions +wasm_runtime_get_llvm_jit_options(void); +#endif + /* See wasm_export.h for description */ WASM_RUNTIME_API_EXTERN bool wasm_runtime_full_init(RuntimeInitArgs *init_args); +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN bool +wasm_runtime_is_running_mode_supported(RunningMode running_mode); + +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN bool +wasm_runtime_set_default_running_mode(RunningMode running_mode); + /* See wasm_export.h for description */ WASM_RUNTIME_API_EXTERN void wasm_runtime_destroy(void); @@ -466,8 +498,9 @@ wasm_runtime_unload(WASMModuleCommon *module); /* Internal API */ WASMModuleInstanceCommon * wasm_runtime_instantiate_internal(WASMModuleCommon *module, bool is_sub_inst, - uint32 stack_size, uint32 heap_size, - char *error_buf, uint32 error_buf_size); + WASMExecEnv *exec_env_main, uint32 stack_size, + uint32 heap_size, char *error_buf, + uint32 error_buf_size); /* Internal API */ void @@ -476,14 +509,27 @@ wasm_runtime_deinstantiate_internal(WASMModuleInstanceCommon *module_inst, /* See wasm_export.h for description */ WASM_RUNTIME_API_EXTERN WASMModuleInstanceCommon * -wasm_runtime_instantiate(WASMModuleCommon *module, uint32 stack_size, - uint32 heap_size, char *error_buf, +wasm_runtime_instantiate(WASMModuleCommon *module, uint32 default_stack_size, + uint32 host_managed_heap_size, char *error_buf, uint32 error_buf_size); +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN bool +wasm_runtime_set_running_mode(wasm_module_inst_t module_inst, + RunningMode running_mode); + +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN RunningMode +wasm_runtime_get_running_mode(wasm_module_inst_t module_inst); + /* See wasm_export.h for description */ WASM_RUNTIME_API_EXTERN void wasm_runtime_deinstantiate(WASMModuleInstanceCommon *module_inst); +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN WASMModuleCommon * +wasm_runtime_get_module(WASMModuleInstanceCommon *module_inst); + /* See wasm_export.h for description */ WASM_RUNTIME_API_EXTERN WASMFunctionInstanceCommon * wasm_runtime_lookup_function(WASMModuleInstanceCommon *const module_inst, @@ -546,6 +592,12 @@ wasm_runtime_set_user_data(WASMExecEnv *exec_env, void *user_data); WASM_RUNTIME_API_EXTERN void * wasm_runtime_get_user_data(WASMExecEnv *exec_env); +#ifdef OS_ENABLE_HW_BOUND_CHECK +/* Access exception check guard page to trigger the signal handler */ +void +wasm_runtime_access_exce_check_guard_page(); +#endif + /* See wasm_export.h for description */ WASM_RUNTIME_API_EXTERN bool wasm_runtime_call_wasm(WASMExecEnv *exec_env, @@ -564,6 +616,11 @@ wasm_runtime_call_wasm_v(WASMExecEnv *exec_env, uint32 num_results, wasm_val_t *results, uint32 num_args, ...); +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN bool +wasm_runtime_call_indirect(WASMExecEnv *exec_env, uint32 element_index, + uint32 argc, uint32 argv[]); + #if WASM_ENABLE_DEBUG_INTERP != 0 /* See wasm_export.h for description */ WASM_RUNTIME_API_EXTERN uint32 @@ -575,27 +632,6 @@ WASM_RUNTIME_API_EXTERN uint32 wasm_runtime_start_debug_instance(WASMExecEnv *exec_env); #endif -/** - * Call a function reference of a given WASM runtime instance with - * arguments. - * - * @param exec_env the execution environment to call the function - * which must be created from wasm_create_exec_env() - * @param element_indices the function ference indicies, usually - * prvovided by the caller of a registed native function - * @param argc the number of arguments - * @param argv the arguments. If the function method has return value, - * the first (or first two in case 64-bit return value) element of - * argv stores the return value of the called WASM function after this - * function returns. - * - * @return true if success, false otherwise and exception will be thrown, - * the caller can call wasm_runtime_get_exception to get exception info. - */ -bool -wasm_runtime_call_indirect(WASMExecEnv *exec_env, uint32 element_indices, - uint32 argc, uint32 argv[]); - bool wasm_runtime_create_exec_env_singleton(WASMModuleInstanceCommon *module_inst); @@ -640,6 +676,23 @@ wasm_runtime_set_custom_data(WASMModuleInstanceCommon *module_inst, WASM_RUNTIME_API_EXTERN void * wasm_runtime_get_custom_data(WASMModuleInstanceCommon *module_inst); +/* Internal API */ +uint32 +wasm_runtime_module_malloc_internal(WASMModuleInstanceCommon *module_inst, + WASMExecEnv *exec_env, uint32 size, + void **p_native_addr); + +/* Internal API */ +uint32 +wasm_runtime_module_realloc_internal(WASMModuleInstanceCommon *module_inst, + WASMExecEnv *exec_env, uint32 ptr, + uint32 size, void **p_native_addr); + +/* Internal API */ +void +wasm_runtime_module_free_internal(WASMModuleInstanceCommon *module_inst, + WASMExecEnv *exec_env, uint32 ptr); + /* See wasm_export.h for description */ WASM_RUNTIME_API_EXTERN uint32 wasm_runtime_module_malloc(WASMModuleInstanceCommon *module_inst, uint32 size, @@ -768,6 +821,10 @@ wasm_runtime_is_wasi_mode(WASMModuleInstanceCommon *module_inst); WASM_RUNTIME_API_EXTERN WASMFunctionInstanceCommon * wasm_runtime_lookup_wasi_start_function(WASMModuleInstanceCommon *module_inst); +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN uint32_t +wasm_runtime_get_wasi_exit_code(WASMModuleInstanceCommon *module_inst); + bool wasm_runtime_init_wasi(WASMModuleInstanceCommon *module_inst, const char *dir_list[], uint32 dir_count, @@ -852,17 +909,6 @@ wasm_runtime_dump_line_buf_impl(const char *line_buf, bool dump_or_print, WASMModuleCommon * wasm_exec_env_get_module(WASMExecEnv *exec_env); -/** - * Enlarge wasm memory data space. - * - * @param module the wasm module instance - * @param inc_page_count denote the page number to increase - * @return return true if enlarge successfully, false otherwise - */ -bool -wasm_runtime_enlarge_memory(WASMModuleInstanceCommon *module, - uint32 inc_page_count); - /* See wasm_export.h for description */ WASM_RUNTIME_API_EXTERN bool wasm_runtime_register_natives(const char *module_name, @@ -875,6 +921,11 @@ wasm_runtime_register_natives_raw(const char *module_name, NativeSymbol *native_symbols, uint32 n_native_symbols); +/* See wasm_export.h for description */ +WASM_RUNTIME_API_EXTERN bool +wasm_runtime_unregister_natives(const char *module_name, + NativeSymbol *native_symbols); + bool wasm_runtime_invoke_native(WASMExecEnv *exec_env, void *func_ptr, const WASMType *func_type, const char *signature, @@ -900,6 +951,16 @@ wasm_runtime_dump_module_inst_mem_consumption( void wasm_runtime_dump_exec_env_mem_consumption(const WASMExecEnv *exec_env); +bool +wasm_runtime_get_table_elem_type(const WASMModuleCommon *module_comm, + uint32 table_idx, uint8 *out_elem_type, + uint32 *out_min_size, uint32 *out_max_size); + +bool +wasm_runtime_get_table_inst_elem_type( + const WASMModuleInstanceCommon *module_inst_comm, uint32 table_idx, + uint8 *out_elem_type, uint32 *out_min_size, uint32 *out_max_size); + bool wasm_runtime_get_export_func_type(const WASMModuleCommon *module_comm, const WASMExport *export_, WASMType **out); @@ -934,6 +995,14 @@ void wasm_runtime_destroy_custom_sections(WASMCustomSection *section_list); #endif +WASM_RUNTIME_API_EXTERN bool +wasm_runtime_is_import_func_linked(const char *module_name, + const char *func_name); + +WASM_RUNTIME_API_EXTERN bool +wasm_runtime_is_import_global_linked(const char *module_name, + const char *global_name); + #ifdef __cplusplus } #endif diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/wasm_shared_memory.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_shared_memory.c similarity index 53% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/wasm_shared_memory.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_shared_memory.c index 395c677f5bf..54fc8200f0b 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/wasm_shared_memory.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_shared_memory.c @@ -5,6 +5,9 @@ #include "bh_log.h" #include "wasm_shared_memory.h" +#if WASM_ENABLE_THREAD_MGR != 0 +#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; @@ -18,15 +21,15 @@ enum { /* clang-format on */ typedef struct AtomicWaitInfo { - korp_mutex wait_list_lock; bh_list wait_list_head; bh_list *wait_list; + /* WARNING: insert to the list allowed only in acquire_wait_info + otherwise there will be data race as described in PR #2016 */ } AtomicWaitInfo; typedef struct AtomicWaitNode { bh_list_link l; uint8 status; - korp_mutex wait_lock; korp_cond wait_cond; } AtomicWaitNode; @@ -47,6 +50,7 @@ wasm_shared_memory_init() { if (os_mutex_init(&shared_memory_list_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, @@ -61,10 +65,8 @@ wasm_shared_memory_init() void wasm_shared_memory_destroy() { + bh_hash_map_destroy(wait_map); os_mutex_destroy(&shared_memory_list_lock); - if (wait_map) { - bh_hash_map_destroy(wait_map); - } } static WASMSharedMemNode * @@ -97,13 +99,13 @@ int32 shared_memory_inc_reference(WASMModuleCommon *module) { WASMSharedMemNode *node = search_module(module); + uint32 ref_count = -1; if (node) { os_mutex_lock(&node->lock); - node->ref_count++; + ref_count = ++node->ref_count; os_mutex_unlock(&node->lock); - return node->ref_count; } - return -1; + return ref_count; } int32 @@ -120,6 +122,7 @@ shared_memory_dec_reference(WASMModuleCommon *module) 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); } @@ -148,7 +151,14 @@ shared_memory_set_memory_inst(WASMModuleCommon *module, 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; } @@ -197,7 +207,7 @@ notify_wait_list(bh_list *wait_list, uint32 count) AtomicWaitNode *node, *next; uint32 i, notify_count = count; - if ((count == UINT32_MAX) || (count > wait_list->len)) + if (count > wait_list->len) notify_count = wait_list->len; node = bh_list_first_elem(wait_list); @@ -219,18 +229,15 @@ notify_wait_list(bh_list *wait_list, uint32 count) } static AtomicWaitInfo * -acquire_wait_info(void *address, bool create) +acquire_wait_info(void *address, AtomicWaitNode *wait_node) { AtomicWaitInfo *wait_info = NULL; bh_list_status ret; - os_mutex_lock(&shared_memory_list_lock); - if (address) wait_info = (AtomicWaitInfo *)bh_hash_map_find(wait_map, address); - if (!create) { - os_mutex_unlock(&shared_memory_list_lock); + if (!wait_node) { return wait_info; } @@ -238,7 +245,7 @@ acquire_wait_info(void *address, bool create) if (!wait_info) { if (!(wait_info = (AtomicWaitInfo *)wasm_runtime_malloc( sizeof(AtomicWaitInfo)))) { - goto fail1; + return NULL; } memset(wait_info, 0, sizeof(AtomicWaitInfo)); @@ -246,33 +253,19 @@ acquire_wait_info(void *address, bool create) wait_info->wait_list = &wait_info->wait_list_head; ret = bh_list_init(wait_info->wait_list); bh_assert(ret == BH_LIST_SUCCESS); - - /* init wait list lock */ - if (0 != os_mutex_init(&wait_info->wait_list_lock)) { - goto fail2; - } + (void)ret; if (!bh_hash_map_insert(wait_map, address, (void *)wait_info)) { - goto fail3; + wasm_runtime_free(wait_info); + return NULL; } } - os_mutex_unlock(&shared_memory_list_lock); - - bh_assert(wait_info); + ret = bh_list_insert(wait_info->wait_list, wait_node); + bh_assert(ret == BH_LIST_SUCCESS); (void)ret; - return wait_info; - -fail3: - os_mutex_destroy(&wait_info->wait_list_lock); - -fail2: - wasm_runtime_free(wait_info); - -fail1: - os_mutex_unlock(&shared_memory_list_lock); - return NULL; + return wait_info; } static void @@ -286,146 +279,162 @@ destroy_wait_info(void *wait_info) while (node) { next = bh_list_elem_next(node); - os_mutex_destroy(&node->wait_lock); os_cond_destroy(&node->wait_cond); wasm_runtime_free(node); node = next; } - os_mutex_destroy(&((AtomicWaitInfo *)wait_info)->wait_list_lock); wasm_runtime_free(wait_info); } } static void -release_wait_info(HashMap *wait_map_, AtomicWaitInfo *wait_info, void *address) +map_try_release_wait_info(HashMap *wait_map_, AtomicWaitInfo *wait_info, + void *address) { - os_mutex_lock(&shared_memory_list_lock); - - if (wait_info->wait_list->len == 0) { - bh_hash_map_remove(wait_map_, address, NULL, NULL); - destroy_wait_info(wait_info); + if (wait_info->wait_list->len > 0) { + return; } - os_mutex_unlock(&shared_memory_list_lock); + bh_hash_map_remove(wait_map_, address, NULL, NULL); + destroy_wait_info(wait_info); } uint32 wasm_runtime_atomic_wait(WASMModuleInstanceCommon *module, void *address, uint64 expect, int64 timeout, bool wait64) { + WASMModuleInstance *module_inst = (WASMModuleInstance *)module; AtomicWaitInfo *wait_info; AtomicWaitNode *wait_node; - bool check_ret, is_timeout; - -#if WASM_ENABLE_INTERP != 0 - if (module->module_type == Wasm_Module_Bytecode) { - WASMModuleInstance *module_inst = (WASMModuleInstance *)module; - /* Currently we have only one memory instance */ - if (!module_inst->memories[0]->is_shared) { - wasm_runtime_set_exception(module, "expected shared memory"); - return -1; - } - if ((uint8 *)address < module_inst->memories[0]->memory_data - || (uint8 *)address + (wait64 ? 8 : 4) - > module_inst->memories[0]->memory_data_end) { - wasm_runtime_set_exception(module, "out of bounds memory access"); - return -1; - } - } -#endif -#if WASM_ENABLE_AOT != 0 - if (module->module_type == Wasm_Module_AoT) { - AOTModuleInstance *aot_inst = (AOTModuleInstance *)module; - AOTMemoryInstance *aot_memory = - ((AOTMemoryInstance **)aot_inst->memories.ptr)[0]; - /* Currently we have only one memory instance */ - if (!aot_memory->is_shared) { - wasm_runtime_set_exception(module, "expected shared memory"); - return -1; - } - if ((uint8 *)address < (uint8 *)aot_memory->memory_data.ptr - || (uint8 *)address + (wait64 ? 8 : 4) - > (uint8 *)aot_memory->memory_data_end.ptr) { - wasm_runtime_set_exception(module, "out of bounds memory access"); - return -1; - } - } + WASMSharedMemNode *node; +#if WASM_ENABLE_THREAD_MGR != 0 + WASMExecEnv *exec_env; #endif + uint64 timeout_left, timeout_wait, timeout_1sec; + bool check_ret, is_timeout, no_wait; - /* acquire the wait info, create new one if not exists */ - wait_info = acquire_wait_info(address, true); + bh_assert(module->module_type == Wasm_Module_Bytecode + || module->module_type == Wasm_Module_AoT); - if (!wait_info) { - wasm_runtime_set_exception(module, "failed to acquire wait_info"); + if (wasm_copy_exception(module_inst, NULL)) { return -1; } - os_mutex_lock(&wait_info->wait_list_lock); + /* Currently we have only one memory instance */ + if (!module_inst->memories[0]->is_shared) { + wasm_runtime_set_exception(module, "expected shared memory"); + return -1; + } - if ((!wait64 && *(uint32 *)address != (uint32)expect) - || (wait64 && *(uint64 *)address != expect)) { - os_mutex_unlock(&wait_info->wait_list_lock); - return 1; + if ((uint8 *)address < module_inst->memories[0]->memory_data + || (uint8 *)address + (wait64 ? 8 : 4) + > module_inst->memories[0]->memory_data_end) { + wasm_runtime_set_exception(module, "out of bounds memory access"); + return -1; } - else { - bh_list_status ret; - if (!(wait_node = wasm_runtime_malloc(sizeof(AtomicWaitNode)))) { - wasm_runtime_set_exception(module, "failed to create wait node"); - os_mutex_unlock(&wait_info->wait_list_lock); - return -1; - } - memset(wait_node, 0, sizeof(AtomicWaitNode)); +#if WASM_ENABLE_THREAD_MGR != 0 + exec_env = + wasm_clusters_search_exec_env((WASMModuleInstanceCommon *)module_inst); + bh_assert(exec_env); +#endif - if (0 != os_mutex_init(&wait_node->wait_lock)) { - wasm_runtime_free(wait_node); - os_mutex_unlock(&wait_info->wait_list_lock); - return -1; - } + node = search_module((WASMModuleCommon *)module_inst->module); + bh_assert(node); - if (0 != os_cond_init(&wait_node->wait_cond)) { - os_mutex_destroy(&wait_node->wait_lock); - wasm_runtime_free(wait_node); - os_mutex_unlock(&wait_info->wait_list_lock); - return -1; - } + /* 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); - wait_node->status = S_WAITING; + no_wait = (!wait64 && *(uint32 *)address != (uint32)expect) + || (wait64 && *(uint64 *)address != expect); - ret = bh_list_insert(wait_info->wait_list, wait_node); - bh_assert(ret == BH_LIST_SUCCESS); - (void)ret; + if (no_wait) { + os_mutex_unlock(&node->shared_mem_lock); + return 1; } - os_mutex_unlock(&wait_info->wait_list_lock); + if (!(wait_node = wasm_runtime_malloc(sizeof(AtomicWaitNode)))) { + os_mutex_unlock(&node->shared_mem_lock); + wasm_runtime_set_exception(module, "failed to create wait node"); + return -1; + } + memset(wait_node, 0, sizeof(AtomicWaitNode)); - /* condition wait start */ - os_mutex_lock(&wait_node->wait_lock); + if (0 != os_cond_init(&wait_node->wait_cond)) { + os_mutex_unlock(&node->shared_mem_lock); + wasm_runtime_free(wait_node); + wasm_runtime_set_exception(module, "failed to init wait cond"); + return -1; + } - if (timeout < 0) - timeout = BHT_WAIT_FOREVER; - os_cond_reltimedwait(&wait_node->wait_cond, &wait_node->wait_lock, - timeout / 1000); + wait_node->status = S_WAITING; - os_mutex_unlock(&wait_node->wait_lock); + /* Acquire the wait info, create new one if not exists */ + wait_info = acquire_wait_info(address, wait_node); - /* Check the wait node status */ - os_mutex_lock(&wait_info->wait_list_lock); - check_ret = is_wait_node_exists(wait_info->wait_list, wait_node); - bh_assert(check_ret); + if (!wait_info) { + os_mutex_unlock(&node->shared_mem_lock); + os_cond_destroy(&wait_node->wait_cond); + wasm_runtime_free(wait_node); + wasm_runtime_set_exception(module, "failed to acquire wait_info"); + return -1; + } + + /* unit of timeout is nsec, convert it to usec */ + timeout_left = (uint64)timeout / 1000; + timeout_1sec = (uint64)1e6; + + while (1) { + 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, + (uint64)timeout_1sec); + if (wait_node->status == S_NOTIFIED /* notified by atomic.notify */ +#if WASM_ENABLE_THREAD_MGR != 0 + /* terminated by other thread */ + || wasm_cluster_is_thread_terminated(exec_env) +#endif + ) { + break; + } + } + else { + timeout_wait = + timeout_left < timeout_1sec ? timeout_left : timeout_1sec; + os_cond_reltimedwait(&wait_node->wait_cond, &node->shared_mem_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 + /* terminated by other thread */ + || wasm_cluster_is_thread_terminated(exec_env) +#endif + ) { + break; + } + timeout_left -= timeout_wait; + } + } is_timeout = wait_node->status == S_WAITING ? true : false; + check_ret = is_wait_node_exists(wait_info->wait_list, wait_node); + bh_assert(check_ret); + (void)check_ret; + + /* Remove wait node from wait list */ bh_list_remove(wait_info->wait_list, wait_node); - os_mutex_destroy(&wait_node->wait_lock); os_cond_destroy(&wait_node->wait_cond); wasm_runtime_free(wait_node); - os_mutex_unlock(&wait_info->wait_list_lock); - release_wait_info(wait_map, wait_info, 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); - (void)check_ret; return is_timeout ? 2 : 0; } @@ -433,43 +442,50 @@ uint32 wasm_runtime_atomic_notify(WASMModuleInstanceCommon *module, void *address, uint32 count) { + WASMModuleInstance *module_inst = (WASMModuleInstance *)module; uint32 notify_result; AtomicWaitInfo *wait_info; + WASMSharedMemNode *node; + bool out_of_bounds; -#if WASM_ENABLE_INTERP != 0 - if (module->module_type == Wasm_Module_Bytecode) { - WASMModuleInstance *module_inst = (WASMModuleInstance *)module; - if ((uint8 *)address < module_inst->memories[0]->memory_data - || (uint8 *)address + 4 - > module_inst->memories[0]->memory_data_end) { - wasm_runtime_set_exception(module, "out of bounds memory access"); - return -1; - } + bh_assert(module->module_type == Wasm_Module_Bytecode + || module->module_type == Wasm_Module_AoT); + + out_of_bounds = + ((uint8 *)address < module_inst->memories[0]->memory_data + || (uint8 *)address + 4 > module_inst->memories[0]->memory_data_end); + + if (out_of_bounds) { + wasm_runtime_set_exception(module, "out of bounds memory access"); + return -1; } -#endif -#if WASM_ENABLE_AOT != 0 - if (module->module_type == Wasm_Module_AoT) { - AOTModuleInstance *aot_inst = (AOTModuleInstance *)module; - AOTMemoryInstance *aot_memory = - ((AOTMemoryInstance **)aot_inst->memories.ptr)[0]; - if ((uint8 *)address < (uint8 *)aot_memory->memory_data.ptr - || (uint8 *)address + 4 - > (uint8 *)aot_memory->memory_data_end.ptr) { - wasm_runtime_set_exception(module, "out of bounds memory access"); - return -1; - } + + /* Currently we have only one memory instance */ + if (!module_inst->memories[0]->is_shared) { + /* Always return 0 for ushared linear memory since there is + no way to create a waiter on it */ + return 0; } -#endif - wait_info = acquire_wait_info(address, false); + node = search_module((WASMModuleCommon *)module_inst->module); + bh_assert(node); + + /* 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); + + wait_info = acquire_wait_info(address, NULL); /* Nobody wait on this address */ - if (!wait_info) + if (!wait_info) { + os_mutex_unlock(&node->shared_mem_lock); return 0; + } - os_mutex_lock(&wait_info->wait_list_lock); + /* Notify each wait node in the wait list */ notify_result = notify_wait_list(wait_info->wait_list, count); - os_mutex_unlock(&wait_info->wait_list_lock); + + os_mutex_unlock(&node->shared_mem_lock); return notify_result; } diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/wasm_shared_memory.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_shared_memory.h similarity index 95% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/wasm_shared_memory.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_shared_memory.h index bc6f8945cf4..6c1c49210f2 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/common/wasm_shared_memory.h +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/common/wasm_shared_memory.h @@ -26,6 +26,8 @@ typedef struct WASMSharedMemNode { WASMModuleCommon *module; /* The memory information */ WASMMemoryInstanceCommon *memory_inst; + /* Lock used for atomic operations */ + korp_mutex shared_mem_lock; /* reference count */ uint32 ref_count; diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot.h similarity index 94% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot.h index a94bf646954..c67251a6ff6 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot.h +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot.h @@ -149,6 +149,7 @@ typedef struct AOTImportGlobal { uint32 data_offset; /* global data after linked */ WASMValue global_data_linked; + bool is_linked; } AOTImportGlobal; /** @@ -304,14 +305,26 @@ aot_set_last_error_v(const char *format, ...); #endif static inline uint32 -aot_get_tbl_data_slots(const AOTTable *tbl) +aot_get_imp_tbl_data_slots(const AOTImportTable *tbl, bool is_jit_mode) { +#if WASM_ENABLE_MULTI_MODULE != 0 + if (is_jit_mode) + return tbl->table_max_size; +#else + (void)is_jit_mode; +#endif return tbl->possible_grow ? tbl->table_max_size : tbl->table_init_size; } static inline uint32 -aot_get_imp_tbl_data_slots(const AOTImportTable *tbl) +aot_get_tbl_data_slots(const AOTTable *tbl, bool is_jit_mode) { +#if WASM_ENABLE_MULTI_MODULE != 0 + if (is_jit_mode) + return tbl->table_max_size; +#else + (void)is_jit_mode; +#endif return tbl->possible_grow ? tbl->table_max_size : tbl->table_init_size; } diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_compiler.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_compiler.c similarity index 94% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_compiler.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_compiler.c index 04425154f01..06235fe3173 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_compiler.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_compiler.c @@ -211,6 +211,7 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index) case WASM_OP_BLOCK: case WASM_OP_LOOP: case WASM_OP_IF: + { value_type = *frame_ip++; if (value_type == VALUE_TYPE_I32 || value_type == VALUE_TYPE_I64 || value_type == VALUE_TYPE_F32 @@ -245,6 +246,25 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index) param_count, param_types, result_count, result_types)) return false; break; + } + + case EXT_OP_BLOCK: + case EXT_OP_LOOP: + case EXT_OP_IF: + { + read_leb_uint32(frame_ip, frame_ip_end, type_index); + func_type = comp_ctx->comp_data->func_types[type_index]; + param_count = func_type->param_count; + param_types = func_type->types; + result_count = func_type->result_count; + result_types = func_type->types + param_count; + if (!aot_compile_op_block( + comp_ctx, func_ctx, &frame_ip, frame_ip_end, + (uint32)(LABEL_TYPE_BLOCK + opcode - EXT_OP_BLOCK), + param_count, param_types, result_count, result_types)) + return false; + break; + } case WASM_OP_ELSE: if (!aot_compile_op_else(comp_ctx, func_ctx, &frame_ip)) @@ -1220,6 +1240,8 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index) case WASM_OP_ATOMIC_FENCE: /* Skip memory index */ frame_ip++; + if (!aot_compiler_op_atomic_fence(comp_ctx, func_ctx)) + return false; break; case WASM_OP_ATOMIC_I32_LOAD: bytes = 4; @@ -2577,12 +2599,11 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index) } static bool -veriy_module(AOTCompContext *comp_ctx) +verify_module(AOTCompContext *comp_ctx) { char *msg = NULL; bool ret; -#if WASM_ENABLE_LAZY_JIT == 0 ret = LLVMVerifyModule(comp_ctx->module, LLVMPrintMessageAction, &msg); if (!ret && msg) { if (msg[0] != '\0') { @@ -2592,134 +2613,9 @@ veriy_module(AOTCompContext *comp_ctx) } LLVMDisposeMessage(msg); } -#else - uint32 i; - - for (i = 0; i < comp_ctx->func_ctx_count; i++) { - ret = LLVMVerifyModule(comp_ctx->modules[i], LLVMPrintMessageAction, - &msg); - if (!ret && msg) { - if (msg[0] != '\0') { - aot_set_last_error(msg); - LLVMDisposeMessage(msg); - return false; - } - LLVMDisposeMessage(msg); - } - } -#endif - - return true; -} - -static bool -apply_func_passes(AOTCompContext *comp_ctx) -{ - LLVMPassManagerRef pass_mgr; - uint32 i; - -#if WASM_ENABLE_LAZY_JIT == 0 - pass_mgr = LLVMCreateFunctionPassManagerForModule(comp_ctx->module); -#else - pass_mgr = LLVMCreatePassManager(); -#endif - - if (!pass_mgr) { - aot_set_last_error("create LLVM pass manager failed."); - return false; - } - - LLVMAddPromoteMemoryToRegisterPass(pass_mgr); - LLVMAddInstructionCombiningPass(pass_mgr); - LLVMAddCFGSimplificationPass(pass_mgr); - LLVMAddJumpThreadingPass(pass_mgr); -#if LLVM_VERSION_MAJOR < 12 - LLVMAddConstantPropagationPass(pass_mgr); -#endif - LLVMAddIndVarSimplifyPass(pass_mgr); - - if (!comp_ctx->is_jit_mode) { - /* Put Vectorize passes before GVN/LICM passes as the former - might gain more performance improvement and the latter might - break the optimizations for the former */ - LLVMAddLoopVectorizePass(pass_mgr); - LLVMAddSLPVectorizePass(pass_mgr); - LLVMAddLoopRotatePass(pass_mgr); -#if LLVM_VERSION_MAJOR < 15 - LLVMAddLoopUnswitchPass(pass_mgr); -#else - aot_add_simple_loop_unswitch_pass(pass_mgr); -#endif - LLVMAddInstructionCombiningPass(pass_mgr); - LLVMAddCFGSimplificationPass(pass_mgr); - if (!comp_ctx->enable_thread_mgr) { - /* These two passes may destroy the volatile semantics, - disable them when building as multi-thread mode */ - LLVMAddGVNPass(pass_mgr); - LLVMAddLICMPass(pass_mgr); - LLVMAddInstructionCombiningPass(pass_mgr); - LLVMAddCFGSimplificationPass(pass_mgr); - } - } - -#if WASM_ENABLE_LAZY_JIT == 0 - LLVMInitializeFunctionPassManager(pass_mgr); - for (i = 0; i < comp_ctx->func_ctx_count; i++) { - LLVMRunFunctionPassManager(pass_mgr, comp_ctx->func_ctxes[i]->func); - } - LLVMFinalizeFunctionPassManager(pass_mgr); -#else - for (i = 0; i < comp_ctx->func_ctx_count; i++) { - LLVMRunPassManager(pass_mgr, comp_ctx->modules[i]); - } -#endif - - LLVMDisposePassManager(pass_mgr); - return true; -} - -#if WASM_ENABLE_LLVM_LEGACY_PM != 0 || LLVM_VERSION_MAJOR < 12 -static bool -apply_lto_passes(AOTCompContext *comp_ctx) -{ - LLVMPassManagerRef common_pass_mgr; - LLVMPassManagerBuilderRef pass_mgr_builder; -#if WASM_ENABLE_LAZY_JIT != 0 - uint32 i; -#endif - - if (!(common_pass_mgr = LLVMCreatePassManager())) { - aot_set_last_error("create LLVM pass manager failed"); - return false; - } - - if (!(pass_mgr_builder = LLVMPassManagerBuilderCreate())) { - aot_set_last_error("create LLVM pass manager builder failed"); - LLVMDisposePassManager(common_pass_mgr); - return false; - } - - LLVMPassManagerBuilderSetOptLevel(pass_mgr_builder, comp_ctx->opt_level); - LLVMPassManagerBuilderPopulateModulePassManager(pass_mgr_builder, - common_pass_mgr); -#if LLVM_VERSION_MAJOR < 15 - LLVMPassManagerBuilderPopulateLTOPassManager(pass_mgr_builder, - common_pass_mgr, true, true); -#endif - -#if WASM_ENABLE_LAZY_JIT == 0 - LLVMRunPassManager(common_pass_mgr, comp_ctx->module); -#else - for (i = 0; i < comp_ctx->func_ctx_count; i++) { - LLVMRunPassManager(common_pass_mgr, comp_ctx->modules[i]); - } -#endif - LLVMDisposePassManager(common_pass_mgr); - LLVMPassManagerBuilderDispose(pass_mgr_builder); return true; } -#endif /* end of WASM_ENABLE_LLVM_LEGACY_PM != 0 || LLVM_VERSION_MAJOR < 12 */ /* Check whether the target supports hardware atomic instructions */ static bool @@ -2759,9 +2655,6 @@ static bool apply_passes_for_indirect_mode(AOTCompContext *comp_ctx) { LLVMPassManagerRef common_pass_mgr; -#if WASM_ENABLE_LAZY_JIT != 0 - uint32 i; -#endif if (!(common_pass_mgr = LLVMCreatePassManager())) { aot_set_last_error("create pass manager failed"); @@ -2776,13 +2669,7 @@ apply_passes_for_indirect_mode(AOTCompContext *comp_ctx) if (aot_require_lower_switch_pass(comp_ctx)) LLVMAddLowerSwitchPass(common_pass_mgr); -#if WASM_ENABLE_LAZY_JIT == 0 LLVMRunPassManager(common_pass_mgr, comp_ctx->module); -#else - for (i = 0; i < comp_ctx->func_ctx_count; i++) { - LLVMRunPassManager(common_pass_mgr, comp_ctx->modules[i]); - } -#endif LLVMDisposePassManager(common_pass_mgr); return true; @@ -2792,11 +2679,6 @@ bool aot_compile_wasm(AOTCompContext *comp_ctx) { uint32 i; -#if WASM_ENABLE_LAZY_JIT != 0 - LLVMErrorRef err; - LLVMOrcJITDylibRef orc_main_dylib; - LLVMOrcThreadSafeModuleRef orc_thread_safe_module; -#endif if (!aot_validate_wasm(comp_ctx)) { return false; @@ -2813,87 +2695,74 @@ aot_compile_wasm(AOTCompContext *comp_ctx) LLVMDIBuilderFinalize(comp_ctx->debug_builder); #endif - bh_print_time("Begin to verify LLVM module"); - if (!veriy_module(comp_ctx)) { - return false; + /* Disable LLVM module verification for jit mode to speedup + the compilation process */ + if (!comp_ctx->is_jit_mode) { + bh_print_time("Begin to verify LLVM module"); + if (!verify_module(comp_ctx)) { + return false; + } } + /* Run IR optimization before feeding in ORCJIT and AOT codegen */ if (comp_ctx->optimize) { - if (comp_ctx->is_jit_mode) { - /* Only run func passes for JIT mode */ - bh_print_time("Begin to run func optimization passes"); - if (!apply_func_passes(comp_ctx)) { + /* Run passes for AOT/JIT mode. + TODO: Apply these passes in the do_ir_transform callback of + TransformLayer when compiling each jit function, so as to + speedup the launch process. Now there are two issues in the + JIT: one is memory leak in do_ir_transform, the other is + possible core dump. */ + bh_print_time("Begin to run llvm optimization passes"); + aot_apply_llvm_new_pass_manager(comp_ctx, comp_ctx->module); + + /* 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_jit_mode && comp_ctx->is_indirect_mode) { + bh_print_time("Begin to run optimization passes " + "for indirect mode"); + if (!apply_passes_for_indirect_mode(comp_ctx)) { return false; } } - else { -#if WASM_ENABLE_LLVM_LEGACY_PM == 0 && LLVM_VERSION_MAJOR >= 12 - /* Run llvm new pass manager for AOT compiler if llvm - legacy pass manager isn't used */ - bh_print_time("Begin to run llvm optimization passes"); - aot_apply_llvm_new_pass_manager(comp_ctx); -#else - /* Run func passes and lto passes for AOT compiler if llvm - legacy pass manager is used */ - bh_print_time("Begin to run func optimization passes"); - if (!apply_func_passes(comp_ctx)) { - return false; - } - if (!comp_ctx->disable_llvm_lto) { - bh_print_time("Begin to run lto optimization passes"); - if (!apply_lto_passes(comp_ctx)) { - return false; - } - } -#endif - /* Run passes for AOT indirect mode */ - if (comp_ctx->is_indirect_mode) { - bh_print_time("Begin to run optimization passes " - "for indirect mode"); - if (!apply_passes_for_indirect_mode(comp_ctx)) { - return false; - } - } - } + bh_print_time("Finish llvm optimization passes"); } -#if WASM_ENABLE_LAZY_JIT != 0 - orc_main_dylib = LLVMOrcLLJITGetMainJITDylib(comp_ctx->orc_lazyjit); - if (!orc_main_dylib) { - aot_set_last_error("failed to get orc jit main dynmaic library"); - return false; - } +#ifdef DUMP_MODULE + LLVMDumpModule(comp_ctx->module); + os_printf("\n"); +#endif + + if (comp_ctx->is_jit_mode) { + LLVMErrorRef err; + LLVMOrcJITDylibRef orc_main_dylib; + LLVMOrcThreadSafeModuleRef orc_thread_safe_module; + + orc_main_dylib = LLVMOrcLLLazyJITGetMainJITDylib(comp_ctx->orc_jit); + if (!orc_main_dylib) { + aot_set_last_error( + "failed to get orc orc_jit main dynmaic library"); + return false; + } - for (i = 0; i < comp_ctx->func_ctx_count; i++) { orc_thread_safe_module = LLVMOrcCreateNewThreadSafeModule( - comp_ctx->modules[i], comp_ctx->orc_thread_safe_context); + comp_ctx->module, comp_ctx->orc_thread_safe_context); if (!orc_thread_safe_module) { aot_set_last_error("failed to create thread safe module"); return false; } - if ((err = LLVMOrcLLJITAddLLVMIRModule(comp_ctx->orc_lazyjit, - orc_main_dylib, - orc_thread_safe_module))) { + if ((err = LLVMOrcLLLazyJITAddLLVMIRModule( + comp_ctx->orc_jit, orc_main_dylib, orc_thread_safe_module))) { /* If adding the ThreadSafeModule fails then we need to clean it up - by ourselves, otherwise the orc jit will manage the memory. */ + by ourselves, otherwise the orc orc_jit will manage the memory. + */ LLVMOrcDisposeThreadSafeModule(orc_thread_safe_module); aot_handle_llvm_errmsg("failed to addIRModule", err); return false; } } -#endif -#if 0 -#if WASM_ENABLE_LAZY_JIT == 0 - LLVMDumpModule(comp_ctx->module); -#else - for (i = 0; i < comp_ctx->func_ctx_count; i++) { - LLVMDumpModule(comp_ctx->modules[i]); - os_printf("\n"); - } -#endif -#endif return true; } @@ -2927,7 +2796,6 @@ aot_generate_tempfile_name(const char *prefix, const char *extension, } #endif /* end of !(defined(_WIN32) || defined(_WIN32_)) */ -#if WASM_ENABLE_LAZY_JIT == 0 bool aot_emit_llvm_file(AOTCompContext *comp_ctx, const char *file_name) { @@ -3051,4 +2919,3 @@ aot_emit_object_file(AOTCompContext *comp_ctx, char *file_name) return true; } -#endif /* end of WASM_ENABLE_LAZY_JIT == 0 */ diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_compiler.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_compiler.h similarity index 99% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_compiler.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_compiler.h index d5e45f28b5e..e6031ab892f 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_compiler.h +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_compiler.h @@ -259,6 +259,7 @@ check_type_compatible(uint8 src_type, uint8 dst_type) #define I32_SIX LLVM_CONST(i32_six) #define I32_SEVEN LLVM_CONST(i32_seven) #define I32_EIGHT LLVM_CONST(i32_eight) +#define I32_NINE LLVM_CONST(i32_nine) #define I32_NEG_ONE LLVM_CONST(i32_neg_one) #define I64_NEG_ONE LLVM_CONST(i64_neg_one) #define I32_MIN LLVM_CONST(i32_min) diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_emit_aot_file.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_emit_aot_file.c similarity index 99% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_emit_aot_file.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_emit_aot_file.c index 2a46ff9beac..62bb809daa1 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_emit_aot_file.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_emit_aot_file.c @@ -6,8 +6,6 @@ #include "aot_compiler.h" #include "../aot/aot_runtime.h" -#if WASM_ENABLE_LAZY_JIT == 0 - #define PUT_U64_TO_ADDR(addr, value) \ do { \ union { \ @@ -2794,16 +2792,18 @@ aot_obj_data_create(AOTCompContext *comp_ctx) } #endif /* end of defined(_WIN32) || defined(_WIN32_) */ } - else if (LLVMTargetMachineEmitToMemoryBuffer( - comp_ctx->target_machine, comp_ctx->module, LLVMObjectFile, - &err, &obj_data->mem_buf) - != 0) { - if (err) { - LLVMDisposeMessage(err); - err = NULL; + else { + if (LLVMTargetMachineEmitToMemoryBuffer( + comp_ctx->target_machine, comp_ctx->module, LLVMObjectFile, + &err, &obj_data->mem_buf) + != 0) { + if (err) { + LLVMDisposeMessage(err); + err = NULL; + } + aot_set_last_error("llvm emit to memory buffer failed."); + goto fail; } - aot_set_last_error("llvm emit to memory buffer failed."); - goto fail; } if (!(obj_data->binary = LLVMCreateBinary(obj_data->mem_buf, NULL, &err))) { @@ -2928,4 +2928,3 @@ aot_emit_aot_file(AOTCompContext *comp_ctx, AOTCompData *comp_data, return ret; } -#endif /* end of WASM_ENABLE_LAZY_JIT == 0 */ diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_emit_compare.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_emit_compare.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_emit_compare.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_emit_compare.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_emit_compare.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_emit_compare.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_emit_compare.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_emit_compare.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_emit_const.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_emit_const.c similarity index 99% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_emit_const.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_emit_const.c index 2508a36ef4c..4b38aa9626d 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_emit_const.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_emit_const.c @@ -4,7 +4,7 @@ */ #include "aot_emit_const.h" -#include "aot_intrinsic.h" +#include "../aot/aot_intrinsic.h" bool aot_compile_op_i32_const(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_emit_const.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_emit_const.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_emit_const.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_emit_const.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_emit_control.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_emit_control.c similarity index 98% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_emit_control.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_emit_control.c index 6d452b04f06..2cf51cf6727 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_emit_control.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_emit_control.c @@ -462,6 +462,7 @@ aot_compile_op_block(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, false, NULL, NULL))) { goto fail; } + aot_block_destroy(block); return aot_handle_next_reachable_block(comp_ctx, func_ctx, p_frame_ip); } @@ -670,9 +671,16 @@ bool check_suspend_flags(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) { LLVMValueRef terminate_addr, terminate_flags, flag, offset, res; - LLVMBasicBlockRef terminate_check_block, non_terminate_block; + LLVMBasicBlockRef terminate_block, non_terminate_block; AOTFuncType *aot_func_type = func_ctx->aot_func->func_type; - LLVMBasicBlockRef terminate_block; + bool is_shared_memory = + comp_ctx->comp_data->memories[0].memory_flags & 0x02 ? true : false; + + /* Only need to check the suspend flags when memory is shared since + shared memory must be enabled for multi-threading */ + if (!is_shared_memory) { + return true; + } /* Offset of suspend_flags */ offset = I32_FIVE; @@ -693,36 +701,27 @@ check_suspend_flags(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) if (!(terminate_flags = LLVMBuildLoad2(comp_ctx->builder, I32_TYPE, terminate_addr, "terminate_flags"))) { - aot_set_last_error("llvm build bit cast failed"); + aot_set_last_error("llvm build LOAD failed"); return false; } /* Set terminate_flags memory accecc to volatile, so that the value will always be loaded from memory rather than register */ LLVMSetVolatile(terminate_flags, true); - CREATE_BLOCK(terminate_check_block, "terminate_check"); - MOVE_BLOCK_AFTER_CURR(terminate_check_block); + if (!(flag = LLVMBuildAnd(comp_ctx->builder, terminate_flags, I32_ONE, + "termination_flag"))) { + aot_set_last_error("llvm build AND failed"); + return false; + } CREATE_BLOCK(non_terminate_block, "non_terminate"); MOVE_BLOCK_AFTER_CURR(non_terminate_block); - BUILD_ICMP(LLVMIntSGT, terminate_flags, I32_ZERO, res, "need_terminate"); - BUILD_COND_BR(res, terminate_check_block, non_terminate_block); - - /* Move builder to terminate check block */ - SET_BUILDER_POS(terminate_check_block); - CREATE_BLOCK(terminate_block, "terminate"); MOVE_BLOCK_AFTER_CURR(terminate_block); - if (!(flag = LLVMBuildAnd(comp_ctx->builder, terminate_flags, I32_ONE, - "termination_flag"))) { - aot_set_last_error("llvm build AND failed"); - return false; - } - - BUILD_ICMP(LLVMIntSGT, flag, I32_ZERO, res, "need_terminate"); - BUILD_COND_BR(res, terminate_block, non_terminate_block); + BUILD_ICMP(LLVMIntEQ, flag, I32_ZERO, res, "flag_terminate"); + BUILD_COND_BR(res, non_terminate_block, terminate_block); /* Move builder to terminate block */ SET_BUILDER_POS(terminate_block); @@ -730,7 +729,7 @@ check_suspend_flags(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) goto fail; } - /* Move builder to terminate block */ + /* Move builder to non terminate block */ SET_BUILDER_POS(non_terminate_block); return true; diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_emit_control.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_emit_control.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_emit_control.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_emit_control.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_emit_conversion.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_emit_conversion.c similarity index 91% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_emit_conversion.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_emit_conversion.c index a1171110a6d..c3dfa6bf11d 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_emit_conversion.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_emit_conversion.c @@ -9,35 +9,47 @@ #include "../aot/aot_intrinsic.h" #include "../aot/aot_runtime.h" -static bool -trunc_float_to_int(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, - LLVMValueRef operand, LLVMTypeRef src_type, - LLVMTypeRef dest_type, LLVMValueRef min_value, - LLVMValueRef max_value, char *name, bool sign) +static LLVMValueRef +call_fcmp_intrinsic(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, + enum AOTFloatCond cond, LLVMRealPredicate op, + LLVMValueRef lhs, LLVMValueRef rhs, LLVMTypeRef src_type, + const char *name) { - LLVMBasicBlockRef check_nan_succ, check_overflow_succ; - LLVMValueRef is_less, is_greater, res; - + LLVMValueRef res = NULL; if (comp_ctx->disable_llvm_intrinsics && aot_intrinsic_check_capability( comp_ctx, src_type == F32_TYPE ? "f32_cmp" : "f64_cmp")) { LLVMTypeRef param_types[3]; - LLVMValueRef opcond = LLVMConstInt(I32_TYPE, FLOAT_UNO, true); + LLVMValueRef opcond = LLVMConstInt(I32_TYPE, cond, true); param_types[0] = I32_TYPE; param_types[1] = src_type; param_types[2] = src_type; res = aot_call_llvm_intrinsic( comp_ctx, func_ctx, src_type == F32_TYPE ? "f32_cmp" : "f64_cmp", - I32_TYPE, param_types, 3, opcond, operand, operand); + I32_TYPE, param_types, 3, opcond, lhs, rhs); if (!res) { goto fail; } res = LLVMBuildIntCast(comp_ctx->builder, res, INT1_TYPE, "bit_cast"); } else { - res = LLVMBuildFCmp(comp_ctx->builder, LLVMRealUNO, operand, operand, - "fcmp_is_nan"); + res = LLVMBuildFCmp(comp_ctx->builder, op, lhs, rhs, name); } +fail: + return res; +} + +static bool +trunc_float_to_int(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, + LLVMValueRef operand, LLVMTypeRef src_type, + LLVMTypeRef dest_type, LLVMValueRef min_value, + LLVMValueRef max_value, char *name, bool sign) +{ + LLVMBasicBlockRef check_nan_succ, check_overflow_succ; + LLVMValueRef is_less, is_greater, res; + + res = call_fcmp_intrinsic(comp_ctx, func_ctx, FLOAT_UNO, LLVMRealUNO, + operand, operand, src_type, "fcmp_is_nan"); if (!res) { aot_set_last_error("llvm build fcmp failed."); @@ -58,54 +70,18 @@ trunc_float_to_int(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, check_nan_succ))) goto fail; - if (comp_ctx->disable_llvm_intrinsics - && aot_intrinsic_check_capability( - comp_ctx, src_type == F32_TYPE ? "f32_cmp" : "f64_cmp")) { - LLVMTypeRef param_types[3]; - LLVMValueRef opcond = LLVMConstInt(I32_TYPE, FLOAT_LE, true); - param_types[0] = I32_TYPE; - param_types[1] = src_type; - param_types[2] = src_type; - is_less = aot_call_llvm_intrinsic( - comp_ctx, func_ctx, src_type == F32_TYPE ? "f32_cmp" : "f64_cmp", - I32_TYPE, param_types, 3, opcond, operand, min_value); - if (!is_less) { - goto fail; - } - is_less = - LLVMBuildIntCast(comp_ctx->builder, is_less, INT1_TYPE, "bit_cast"); - } - else { - is_less = LLVMBuildFCmp(comp_ctx->builder, LLVMRealOLE, operand, - min_value, "fcmp_min_value"); - } + is_less = + call_fcmp_intrinsic(comp_ctx, func_ctx, FLOAT_LE, LLVMRealOLE, operand, + min_value, src_type, "fcmp_min_value"); if (!is_less) { aot_set_last_error("llvm build fcmp failed."); goto fail; } - if (comp_ctx->disable_llvm_intrinsics - && aot_intrinsic_check_capability( - comp_ctx, src_type == F32_TYPE ? "f32_cmp" : "f64_cmp")) { - LLVMTypeRef param_types[3]; - LLVMValueRef opcond = LLVMConstInt(I32_TYPE, FLOAT_GE, true); - param_types[0] = I32_TYPE; - param_types[1] = src_type; - param_types[2] = src_type; - is_greater = aot_call_llvm_intrinsic( - comp_ctx, func_ctx, src_type == F32_TYPE ? "f32_cmp" : "f64_cmp", - I32_TYPE, param_types, 3, opcond, operand, max_value); - if (!is_greater) { - goto fail; - } - is_greater = LLVMBuildIntCast(comp_ctx->builder, is_greater, INT1_TYPE, - "bit_cast"); - } - else { - is_greater = LLVMBuildFCmp(comp_ctx->builder, LLVMRealOGE, operand, - max_value, "fcmp_min_value"); - } + is_greater = + call_fcmp_intrinsic(comp_ctx, func_ctx, FLOAT_GE, LLVMRealOGE, operand, + max_value, src_type, "fcmp_min_value"); if (!is_greater) { aot_set_last_error("llvm build fcmp failed."); @@ -183,8 +159,9 @@ trunc_sat_float_to_int(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, LLVMValueRef zero = (dest_type == I32_TYPE) ? I32_ZERO : I64_ZERO; LLVMValueRef vmin, vmax; - if (!(res = LLVMBuildFCmp(comp_ctx->builder, LLVMRealUNO, operand, operand, - "fcmp_is_nan"))) { + if (!(res = + call_fcmp_intrinsic(comp_ctx, func_ctx, FLOAT_UNO, LLVMRealUNO, + operand, operand, src_type, "fcmp_is_nan"))) { aot_set_last_error("llvm build fcmp failed."); goto fail; } @@ -212,8 +189,9 @@ trunc_sat_float_to_int(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, /* Start to translate check_nan_succ block */ LLVMPositionBuilderAtEnd(comp_ctx->builder, check_nan_succ); - if (!(is_less = LLVMBuildFCmp(comp_ctx->builder, LLVMRealOLE, operand, - min_value, "fcmp_min_value"))) { + if (!(is_less = call_fcmp_intrinsic(comp_ctx, func_ctx, FLOAT_LE, + LLVMRealOLE, operand, min_value, + src_type, "fcmp_min_value"))) { aot_set_last_error("llvm build fcmp failed."); goto fail; } @@ -232,8 +210,9 @@ trunc_sat_float_to_int(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, /* Start to translate check_less_succ block */ LLVMPositionBuilderAtEnd(comp_ctx->builder, check_less_succ); - if (!(is_greater = LLVMBuildFCmp(comp_ctx->builder, LLVMRealOGE, operand, - max_value, "fcmp_max_value"))) { + if (!(is_greater = call_fcmp_intrinsic(comp_ctx, func_ctx, FLOAT_GE, + LLVMRealOGE, operand, max_value, + src_type, "fcmp_max_value"))) { aot_set_last_error("llvm build fcmp failed."); goto fail; } @@ -261,10 +240,30 @@ trunc_sat_float_to_int(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, param_types, 1, operand); } else { - if (sign) - res = LLVMBuildFPToSI(comp_ctx->builder, operand, dest_type, name); - else - res = LLVMBuildFPToUI(comp_ctx->builder, operand, dest_type, name); + char intrinsic[128]; + + /* Integer width is always 32 or 64 here. */ + + snprintf(intrinsic, sizeof(intrinsic), "i%d_trunc_f%d_%c", + LLVMGetIntTypeWidth(dest_type), + LLVMGetTypeKind(src_type) == LLVMFloatTypeKind ? 32 : 64, + sign ? 's' : 'u'); + + if (comp_ctx->disable_llvm_intrinsics + && aot_intrinsic_check_capability(comp_ctx, intrinsic)) { + res = aot_call_llvm_intrinsic(comp_ctx, func_ctx, intrinsic, + dest_type, &src_type, 1, operand); + } + else { + if (sign) { + res = LLVMBuildFPToSI(comp_ctx->builder, operand, dest_type, + name); + } + else { + res = LLVMBuildFPToUI(comp_ctx->builder, operand, dest_type, + name); + } + } } if (!res) { diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_emit_conversion.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_emit_conversion.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_emit_conversion.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_emit_conversion.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_emit_exception.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_emit_exception.c similarity index 98% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_emit_exception.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_emit_exception.c index 3a16f7f8887..d40ccc6a4cf 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_emit_exception.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_emit_exception.c @@ -4,6 +4,7 @@ */ #include "aot_emit_exception.h" +#include "../interpreter/wasm_runtime.h" #include "../aot/aot_runtime.h" bool @@ -57,7 +58,7 @@ aot_emit_exception(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, } /* Create LLVM function with const function pointer */ if (!(func_const = - I64_CONST((uint64)(uintptr_t)aot_set_exception_with_id)) + I64_CONST((uint64)(uintptr_t)jit_set_exception_with_id)) || !(func = LLVMConstIntToPtr(func_const, func_ptr_type))) { aot_set_last_error("create LLVM value failed."); return false; diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_emit_exception.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_emit_exception.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_emit_exception.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_emit_exception.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_emit_function.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_emit_function.c similarity index 89% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_emit_function.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_emit_function.c index 1065b4c77d9..9ba8baa24f9 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_emit_function.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_emit_function.c @@ -35,7 +35,14 @@ create_func_return_block(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) /* Create return IR */ LLVMPositionBuilderAtEnd(comp_ctx->builder, func_ctx->func_return_block); - if (!aot_build_zero_function_ret(comp_ctx, func_ctx, aot_func_type)) { + if (!comp_ctx->enable_bound_check) { + if (!aot_emit_exception(comp_ctx, func_ctx, EXCE_ALREADY_THROWN, + false, NULL, NULL)) { + return false; + } + } + else if (!aot_build_zero_function_ret(comp_ctx, func_ctx, + aot_func_type)) { return false; } } @@ -162,7 +169,7 @@ call_aot_invoke_native_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, } /* JIT mode, call the function directly */ - if (!(func = I64_CONST((uint64)(uintptr_t)aot_invoke_native)) + if (!(func = I64_CONST((uint64)(uintptr_t)llvm_jit_invoke_native)) || !(func = LLVMConstIntToPtr(func, func_ptr_type))) { aot_set_last_error("create LLVM value failed."); return false; @@ -267,131 +274,6 @@ call_aot_invoke_native_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, return true; } -#if WASM_ENABLE_LAZY_JIT != 0 -static bool -lookup_orcjit_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, - LLVMValueRef func_idx, LLVMValueRef *p_func) -{ - LLVMBasicBlockRef block_curr, block_resolve_func, block_func_resolved; - LLVMValueRef param_values[3], func, value, func_ptr, cmp, phi; - LLVMTypeRef param_types[3], ret_type, func_type, func_ptr_type; - - block_curr = LLVMGetInsertBlock(comp_ctx->builder); - - if (!(block_resolve_func = LLVMAppendBasicBlockInContext( - comp_ctx->context, func_ctx->func, "resolve_func"))) { - aot_set_last_error("llvm add basic block failed."); - return false; - } - if (!(block_func_resolved = LLVMAppendBasicBlockInContext( - comp_ctx->context, func_ctx->func, "func_resolved"))) { - aot_set_last_error("llvm add basic block failed."); - return false; - } - LLVMMoveBasicBlockAfter(block_resolve_func, block_curr); - LLVMMoveBasicBlockAfter(block_func_resolved, block_resolve_func); - - LLVMPositionBuilderAtEnd(comp_ctx->builder, block_func_resolved); - if (!(phi = LLVMBuildPhi(comp_ctx->builder, INT8_PTR_TYPE, "phi"))) { - aot_set_last_error("llvm build phi failed."); - return false; - } - - LLVMPositionBuilderAtEnd(comp_ctx->builder, block_curr); - - /* Load function pointer */ - if (!(func_ptr = LLVMBuildInBoundsGEP2(comp_ctx->builder, OPQ_PTR_TYPE, - func_ctx->func_ptrs, &func_idx, 1, - "func_ptr_tmp"))) { - aot_set_last_error("llvm build inbounds gep failed."); - return false; - } - - if (!(func = LLVMBuildLoad2(comp_ctx->builder, OPQ_PTR_TYPE, func_ptr, - "func_ptr"))) { - aot_set_last_error("llvm build load failed."); - return false; - } - - /* If func ptr is NULL, call aot_lookup_orcjit_func to resolve it */ - if (!(cmp = LLVMBuildIsNull(comp_ctx->builder, func, "cmp"))) { - aot_set_last_error("llvm build is null failed"); - return false; - } - - /* Create condition br */ - if (!LLVMBuildCondBr(comp_ctx->builder, cmp, block_resolve_func, - block_func_resolved)) { - aot_set_last_error("llvm build cond br failed."); - return false; - } - LLVMAddIncoming(phi, &func, &block_curr, 1); - - LLVMPositionBuilderAtEnd(comp_ctx->builder, block_resolve_func); - - param_types[0] = INT8_PTR_TYPE; - param_types[1] = comp_ctx->aot_inst_type; - param_types[2] = I32_TYPE; - ret_type = INT8_PTR_TYPE; - - if (!(func_type = LLVMFunctionType(ret_type, param_types, 3, false)) - || !(func_ptr_type = LLVMPointerType(func_type, 0))) { - aot_set_last_error("llvm add function type failed."); - return false; - } - - if (!(value = I64_CONST((uint64)(uintptr_t)aot_lookup_orcjit_func)) - || !(func = LLVMConstIntToPtr(value, func_ptr_type))) { - aot_set_last_error("create LLVM value failed."); - return false; - } - - param_values[0] = I64_CONST((uintptr_t)comp_ctx->orc_lazyjit); - if (!param_values[0]) { - aot_set_last_error("llvm build const failed."); - return false; - } - if (!(param_values[0] = - LLVMConstIntToPtr(param_values[0], INT8_PTR_TYPE))) { - aot_set_last_error("llvm build bit cast failed."); - return false; - } - - param_values[1] = func_ctx->aot_inst; - - param_values[2] = func_idx; - if (!param_values[2]) { - aot_set_last_error("llvm build const failed."); - return false; - } - - /* Call the function */ - if (!(func = LLVMBuildCall2(comp_ctx->builder, func_type, func, - param_values, 3, "call_orcjit_lookup"))) { - aot_set_last_error("LLVM build call failed."); - return false; - } - - /* Check whether exception was thrown when looking up func */ - if (!check_exception_thrown(comp_ctx, func_ctx)) { - return false; - } - - block_curr = LLVMGetInsertBlock(comp_ctx->builder); - LLVMAddIncoming(phi, &func, &block_curr, 1); - - if (!LLVMBuildBr(comp_ctx->builder, block_func_resolved)) { - aot_set_last_error("llvm build br failed."); - return false; - } - - LLVMPositionBuilderAtEnd(comp_ctx->builder, block_func_resolved); - - *p_func = phi; - return true; -} -#endif - #if (WASM_ENABLE_DUMP_CALL_STACK != 0) || (WASM_ENABLE_PERF_PROFILING != 0) static bool call_aot_alloc_frame_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, @@ -407,7 +289,10 @@ call_aot_alloc_frame_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, param_types[1] = I32_TYPE; ret_type = INT8_TYPE; - GET_AOT_FUNCTION(aot_alloc_frame, 2); + if (comp_ctx->is_jit_mode) + GET_AOT_FUNCTION(llvm_jit_alloc_frame, 2); + else + GET_AOT_FUNCTION(aot_alloc_frame, 2); param_values[0] = func_ctx->exec_env; param_values[1] = func_idx; @@ -461,7 +346,10 @@ call_aot_free_frame_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) param_types[0] = comp_ctx->exec_env_type; ret_type = INT8_TYPE; - GET_AOT_FUNCTION(aot_free_frame, 1); + if (comp_ctx->is_jit_mode) + GET_AOT_FUNCTION(llvm_jit_free_frame, 1); + else + GET_AOT_FUNCTION(aot_free_frame, 1); param_values[0] = func_ctx->exec_env; @@ -478,6 +366,87 @@ call_aot_free_frame_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) #endif /* end of (WASM_ENABLE_DUMP_CALL_STACK != 0) \ || (WASM_ENABLE_PERF_PROFILING != 0) */ +static bool +record_stack_usage(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, + uint32 callee_cell_num) +{ + LLVMBasicBlockRef block_curr = LLVMGetInsertBlock(comp_ctx->builder); + LLVMBasicBlockRef block_update; + LLVMBasicBlockRef block_after_update; + LLVMValueRef callee_local_size, new_sp, cmp; + LLVMValueRef native_stack_top_min; + LLVMTypeRef ptrdiff_type; + if (comp_ctx->pointer_size == sizeof(uint64_t)) { + ptrdiff_type = I64_TYPE; + } + else { + ptrdiff_type = I32_TYPE; + } + + /* + * new_sp = last_alloca - callee_local_size; + * if (*native_stack_top_min_addr > new_sp) { + * *native_stack_top_min_addr = new_sp; + * } + */ + + if (!(callee_local_size = LLVMConstInt( + ptrdiff_type, -(int64_t)callee_cell_num * 4, true))) { + aot_set_last_error("llvm build const failed."); + return false; + } + if (!(new_sp = LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE, + func_ctx->last_alloca, + &callee_local_size, 1, "new_sp"))) { + aot_set_last_error("llvm build gep failed"); + return false; + } + if (!(native_stack_top_min = LLVMBuildLoad2( + comp_ctx->builder, OPQ_PTR_TYPE, + func_ctx->native_stack_top_min_addr, "native_stack_top_min"))) { + aot_set_last_error("llvm build load failed"); + return false; + } + if (!(cmp = LLVMBuildICmp(comp_ctx->builder, LLVMIntULT, new_sp, + native_stack_top_min, "cmp"))) { + aot_set_last_error("llvm build icmp failed."); + return false; + } + + if (!(block_update = LLVMAppendBasicBlockInContext( + comp_ctx->context, func_ctx->func, "block_update"))) { + aot_set_last_error("llvm add basic block failed."); + return false; + } + if (!(block_after_update = LLVMAppendBasicBlockInContext( + comp_ctx->context, func_ctx->func, "block_after_update"))) { + aot_set_last_error("llvm add basic block failed."); + return false; + } + LLVMMoveBasicBlockAfter(block_update, block_curr); + LLVMMoveBasicBlockAfter(block_after_update, block_update); + + if (!LLVMBuildCondBr(comp_ctx->builder, cmp, block_update, + block_after_update)) { + aot_set_last_error("llvm build cond br failed."); + return false; + } + + LLVMPositionBuilderAtEnd(comp_ctx->builder, block_update); + if (!LLVMBuildStore(comp_ctx->builder, new_sp, + func_ctx->native_stack_top_min_addr)) { + aot_set_last_error("llvm build store failed"); + return false; + } + if (!LLVMBuildBr(comp_ctx->builder, block_after_update)) { + aot_set_last_error("llvm build br failed."); + return false; + } + + LLVMPositionBuilderAtEnd(comp_ctx->builder, block_after_update); + return true; +} + static bool check_stack_boundary(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, uint32 callee_cell_num) @@ -521,6 +490,19 @@ check_stack_boundary(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, return true; } +static bool +check_stack(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, + uint32 callee_cell_num) +{ + if (comp_ctx->enable_stack_estimation + && !record_stack_usage(comp_ctx, func_ctx, callee_cell_num)) + return false; + if (comp_ctx->enable_stack_bound_check + && !check_stack_boundary(comp_ctx, func_ctx, callee_cell_num)) + return false; + return true; +} + /** * Check whether the app address and its buffer are inside the linear memory, * if no, throw exception @@ -557,7 +539,7 @@ check_app_addr_and_convert(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, /* JIT mode, call the function directly */ if (!(func = - I64_CONST((uint64)(uintptr_t)aot_check_app_addr_and_convert)) + I64_CONST((uint64)(uintptr_t)jit_check_app_addr_and_convert)) || !(func = LLVMConstIntToPtr(func, func_ptr_type))) { aot_set_last_error("create LLVM value failed."); return false; @@ -613,7 +595,8 @@ check_app_addr_and_convert(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, } /* Check whether exception was thrown when executing the function */ - if (!check_call_return(comp_ctx, func_ctx, res)) { + if (comp_ctx->enable_bound_check + && !check_call_return(comp_ctx, func_ctx, res)) { return false; } @@ -826,7 +809,8 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, goto fail; /* Check whether there was exception thrown when executing the function */ - if (!check_call_return(comp_ctx, func_ctx, res)) + if (comp_ctx->enable_bound_check + && !check_call_return(comp_ctx, func_ctx, res)) goto fail; } else { /* call native func directly */ @@ -903,51 +887,66 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, } } else { -#if WASM_ENABLE_LAZY_JIT == 0 - func = func_ctxes[func_idx - import_func_count]->func; -#else if (func_ctxes[func_idx - import_func_count] == func_ctx) { /* recursive call */ func = func_ctx->func; } else { - LLVMTypeRef func_ptr_type; - LLVMValueRef func_idx_const = I32_CONST(func_idx); - - if (!func_idx_const) { - aot_set_last_error("llvm build const failed."); - goto fail; + if (!comp_ctx->is_jit_mode) { + func = func_ctxes[func_idx - import_func_count]->func; } + else { +#if !(WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_LAZY_JIT != 0) + func = func_ctxes[func_idx - import_func_count]->func; +#else + /* JIT tier-up, load func ptr from func_ptrs[func_idx] */ + LLVMValueRef func_ptr, func_idx_const; + LLVMTypeRef func_ptr_type; - /* For LAZY JIT, each function belongs to its own module, - we call aot_lookup_orcjit_func to get the func pointer */ - if (!lookup_orcjit_func(comp_ctx, func_ctx, func_idx_const, - &func)) { - goto fail; - } + if (!(func_idx_const = I32_CONST(func_idx))) { + aot_set_last_error("llvm build const failed."); + goto fail; + } - if (!(func_ptr_type = LLVMPointerType( - func_ctxes[func_idx - import_func_count]->func_type, - 0))) { - aot_set_last_error("construct func ptr type failed."); - goto fail; - } + if (!(func_ptr = LLVMBuildInBoundsGEP2( + comp_ctx->builder, OPQ_PTR_TYPE, + func_ctx->func_ptrs, &func_idx_const, 1, + "func_ptr_tmp"))) { + aot_set_last_error("llvm build inbounds gep failed."); + goto fail; + } - if (!(func = LLVMBuildBitCast(comp_ctx->builder, func, - func_ptr_type, "aot_func"))) { - aot_set_last_error("llvm bit cast failed."); - goto fail; + if (!(func_ptr = + LLVMBuildLoad2(comp_ctx->builder, OPQ_PTR_TYPE, + func_ptr, "func_ptr"))) { + aot_set_last_error("llvm build load failed."); + goto fail; + } + + if (!(func_ptr_type = LLVMPointerType( + func_ctxes[func_idx - import_func_count] + ->func_type, + 0))) { + aot_set_last_error("construct func ptr type failed."); + goto fail; + } + + if (!(func = LLVMBuildBitCast(comp_ctx->builder, func_ptr, + func_ptr_type, + "indirect_func"))) { + aot_set_last_error("llvm build bit cast failed."); + goto fail; + } +#endif /* end of !(WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_LAZY_JIT != 0) */ } } -#endif } aot_func = func_ctxes[func_idx - import_func_count]->aot_func; callee_cell_num = aot_func->param_cell_num + aot_func->local_cell_num + 1; - if (comp_ctx->enable_bound_check - && !check_stack_boundary(comp_ctx, func_ctx, callee_cell_num)) + if (!check_stack(comp_ctx, func_ctx, callee_cell_num)) goto fail; #if LLVM_VERSION_MAJOR >= 14 @@ -972,7 +971,7 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, /* Check whether there was exception thrown when executing the function */ - if (!tail_call && !recursive_call + if (!tail_call && !recursive_call && comp_ctx->enable_bound_check && !check_exception_thrown(comp_ctx, func_ctx)) goto fail; } @@ -1000,6 +999,14 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, } #endif +#if WASM_ENABLE_THREAD_MGR != 0 + /* Insert suspend check point */ + if (comp_ctx->enable_thread_mgr) { + if (!check_suspend_flags(comp_ctx, func_ctx)) + goto fail; + } +#endif + ret = true; fail: if (param_types) @@ -1047,7 +1054,7 @@ call_aot_call_indirect_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, } /* JIT mode, call the function directly */ - if (!(func = I64_CONST((uint64)(uintptr_t)aot_call_indirect)) + if (!(func = I64_CONST((uint64)(uintptr_t)llvm_jit_call_indirect)) || !(func = LLVMConstIntToPtr(func, func_ptr_type))) { aot_set_last_error("create LLVM value failed."); return false; @@ -1265,7 +1272,7 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, /* load data as i32* */ if (!(offset = I32_CONST(get_tbl_inst_offset(comp_ctx, func_ctx, tbl_idx) - + offsetof(AOTTableInstance, data)))) { + + offsetof(AOTTableInstance, elems)))) { HANDLE_FAILURE("LLVMConstInt"); goto fail; } @@ -1544,7 +1551,8 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, goto fail; /* Check whether exception was thrown when executing the function */ - if (!check_call_return(comp_ctx, func_ctx, res)) + if (comp_ctx->enable_bound_check + && !check_call_return(comp_ctx, func_ctx, res)) goto fail; block_curr = LLVMGetInsertBlock(comp_ctx->builder); @@ -1560,15 +1568,13 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, /* Translate call non-import block */ LLVMPositionBuilderAtEnd(comp_ctx->builder, block_call_non_import); - if (comp_ctx->enable_bound_check - && !check_stack_boundary(comp_ctx, func_ctx, - param_cell_num + ext_cell_num - + 1 - /* Reserve some local variables */ - + 16)) + if (!check_stack(comp_ctx, func_ctx, + param_cell_num + ext_cell_num + + 1 + /* Reserve some local variables */ + + 16)) goto fail; -#if WASM_ENABLE_LAZY_JIT == 0 /* Load function pointer */ if (!(func_ptr = LLVMBuildInBoundsGEP2(comp_ctx->builder, OPQ_PTR_TYPE, func_ctx->func_ptrs, &func_idx, 1, @@ -1582,12 +1588,6 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, aot_set_last_error("llvm build load failed."); goto fail; } -#else - /* For LAZY JIT, each function belongs to its own module, - we call aot_lookup_orcjit_func to get the func pointer */ - if (!lookup_orcjit_func(comp_ctx, func_ctx, func_idx, &func_ptr)) - goto fail; -#endif if (!(llvm_func_type = LLVMFunctionType(ret_type, param_types, total_param_count, false)) @@ -1610,7 +1610,8 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, } /* Check whether exception was thrown when executing the function */ - if (!check_exception_thrown(comp_ctx, func_ctx)) + if (comp_ctx->enable_bound_check + && !check_exception_thrown(comp_ctx, func_ctx)) goto fail; if (func_result_count > 0) { @@ -1652,6 +1653,14 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, } #endif +#if WASM_ENABLE_THREAD_MGR != 0 + /* Insert suspend check point */ + if (comp_ctx->enable_thread_mgr) { + if (!check_suspend_flags(comp_ctx, func_ctx)) + goto fail; + } +#endif + ret = true; fail: diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_emit_function.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_emit_function.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_emit_function.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_emit_function.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_emit_memory.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_emit_memory.c similarity index 96% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_emit_memory.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_emit_memory.c index 05e13b30cce..4da4cc807f5 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_emit_memory.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_emit_memory.c @@ -7,6 +7,7 @@ #include "aot_emit_exception.h" #include "../aot/aot_runtime.h" #include "aot_intrinsic.h" +#include "aot_emit_control.h" #define BUILD_ICMP(op, left, right, res, name) \ do { \ @@ -718,7 +719,7 @@ aot_compile_op_memory_grow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) aot_set_last_error("llvm add pointer type failed."); return false; } - if (!(value = I64_CONST((uint64)(uintptr_t)aot_enlarge_memory)) + if (!(value = I64_CONST((uint64)(uintptr_t)wasm_enlarge_memory)) || !(func = LLVMConstIntToPtr(value, func_ptr_type))) { aot_set_last_error("create LLVM value failed."); return false; @@ -899,7 +900,10 @@ aot_compile_op_memory_init(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, param_types[4] = I32_TYPE; ret_type = INT8_TYPE; - GET_AOT_FUNCTION(aot_memory_init, 5); + if (comp_ctx->is_jit_mode) + GET_AOT_FUNCTION(llvm_jit_memory_init, 5); + else + GET_AOT_FUNCTION(aot_memory_init, 5); /* Call function aot_memory_init() */ param_values[0] = func_ctx->aot_inst; @@ -955,7 +959,10 @@ aot_compile_op_data_drop(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, param_types[1] = I32_TYPE; ret_type = INT8_TYPE; - GET_AOT_FUNCTION(aot_data_drop, 2); + if (comp_ctx->is_jit_mode) + GET_AOT_FUNCTION(llvm_jit_data_drop, 2); + else + GET_AOT_FUNCTION(aot_data_drop, 2); /* Call function aot_data_drop() */ param_values[0] = func_ctx->aot_inst; @@ -987,18 +994,10 @@ aot_compile_op_memory_copy(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) if (!(dst_addr = check_bulk_memory_overflow(comp_ctx, func_ctx, dst, len))) return false; -#if WASM_ENABLE_LAZY_JIT != 0 - call_aot_memmove = true; -#endif - if (comp_ctx->is_indirect_mode) - call_aot_memmove = true; - + call_aot_memmove = comp_ctx->is_indirect_mode || comp_ctx->is_jit_mode; if (call_aot_memmove) { LLVMTypeRef param_types[3], ret_type, func_type, func_ptr_type; LLVMValueRef func, params[3]; -#if WASM_ENABLE_LAZY_JIT == 0 - int32 func_idx; -#endif param_types[0] = INT8_PTR_TYPE; param_types[1] = INT8_PTR_TYPE; @@ -1015,22 +1014,25 @@ aot_compile_op_memory_copy(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) return false; } -#if WASM_ENABLE_LAZY_JIT == 0 - func_idx = aot_get_native_symbol_index(comp_ctx, "memmove"); - if (func_idx < 0) { - return false; - } - if (!(func = aot_get_func_from_table(comp_ctx, func_ctx->native_symbol, - func_ptr_type, func_idx))) { - return false; + if (comp_ctx->is_jit_mode) { + if (!(func = I64_CONST((uint64)(uintptr_t)aot_memmove)) + || !(func = LLVMConstIntToPtr(func, func_ptr_type))) { + aot_set_last_error("create LLVM value failed."); + return false; + } } -#else - if (!(func = I64_CONST((uint64)(uintptr_t)aot_memmove)) - || !(func = LLVMConstIntToPtr(func, func_ptr_type))) { - aot_set_last_error("create LLVM value failed."); - return false; + else { + int32 func_index; + func_index = aot_get_native_symbol_index(comp_ctx, "memmove"); + if (func_index < 0) { + return false; + } + if (!(func = + aot_get_func_from_table(comp_ctx, func_ctx->native_symbol, + func_ptr_type, func_index))) { + return false; + } } -#endif params[0] = dst_addr; params[1] = src_addr; @@ -1054,6 +1056,12 @@ aot_compile_op_memory_copy(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) return false; } +static void * +jit_memset(void *s, int c, size_t n) +{ + return memset(s, c, n); +} + bool aot_compile_op_memory_fill(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) { @@ -1084,7 +1092,7 @@ aot_compile_op_memory_fill(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) } if (comp_ctx->is_jit_mode) { - if (!(func = I64_CONST((uint64)(uintptr_t)aot_memset)) + if (!(func = I64_CONST((uint64)(uintptr_t)jit_memset)) || !(func = LLVMConstIntToPtr(func, func_ptr_type))) { aot_set_last_error("create LLVM value failed."); return false; @@ -1337,7 +1345,7 @@ aot_compile_op_atomic_wait(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, return false; } - BUILD_ICMP(LLVMIntSGT, ret_value, I32_ZERO, cmp, "atomic_wait_ret"); + BUILD_ICMP(LLVMIntNE, ret_value, I32_NEG_ONE, cmp, "atomic_wait_ret"); ADD_BASIC_BLOCK(wait_fail, "atomic_wait_fail"); ADD_BASIC_BLOCK(wait_success, "wait_success"); @@ -1361,6 +1369,14 @@ aot_compile_op_atomic_wait(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, PUSH_I32(ret_value); +#if WASM_ENABLE_THREAD_MGR != 0 + /* Insert suspend check point */ + if (comp_ctx->enable_thread_mgr) { + if (!check_suspend_flags(comp_ctx, func_ctx)) + return false; + } +#endif + return true; fail: return false; @@ -1407,4 +1423,13 @@ aot_compiler_op_atomic_notify(AOTCompContext *comp_ctx, return false; } +bool +aot_compiler_op_atomic_fence(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) +{ + return LLVMBuildFence(comp_ctx->builder, + LLVMAtomicOrderingSequentiallyConsistent, false, "") + ? true + : false; +} + #endif /* end of WASM_ENABLE_SHARED_MEMORY */ diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_emit_memory.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_emit_memory.h similarity index 96% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_emit_memory.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_emit_memory.h index 2c39f725bb4..e49582e3c0c 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_emit_memory.h +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_emit_memory.h @@ -97,6 +97,10 @@ bool aot_compiler_op_atomic_notify(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, uint32 align, uint32 offset, uint32 bytes); + +bool +aot_compiler_op_atomic_fence(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx); #endif #ifdef __cplusplus diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_emit_numberic.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_emit_numberic.c similarity index 88% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_emit_numberic.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_emit_numberic.c index 09ad1c50c70..4c63e8a40be 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_emit_numberic.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_emit_numberic.c @@ -28,6 +28,20 @@ } \ } while (0) +#define LLVM_BUILD_OP_OR_INTRINSIC(Op, left, right, res, intrinsic, name, \ + err_ret) \ + do { \ + if (comp_ctx->disable_llvm_intrinsics \ + && aot_intrinsic_check_capability(comp_ctx, intrinsic)) { \ + res = aot_call_llvm_intrinsic(comp_ctx, func_ctx, intrinsic, \ + param_types[0], param_types, 2, \ + left, right); \ + } \ + else { \ + LLVM_BUILD_OP(Op, left, right, res, name, false); \ + } \ + } while (0) + #define ADD_BASIC_BLOCK(block, name) \ do { \ if (!(block = LLVMAppendBasicBlockInContext(comp_ctx->context, \ @@ -220,15 +234,47 @@ compile_op_float_min_max(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, nan = LLVMConstRealOfString(ret_type, "NaN"); char *intrinsic = is_min ? (is_f32 ? "llvm.minnum.f32" : "llvm.minnum.f64") : (is_f32 ? "llvm.maxnum.f32" : "llvm.maxnum.f64"); - CHECK_LLVM_CONST(nan); param_types[0] = param_types[1] = ret_type; - if (!(is_nan = LLVMBuildFCmp(comp_ctx->builder, LLVMRealUNO, left, right, - "is_nan")) - || !(is_eq = LLVMBuildFCmp(comp_ctx->builder, LLVMRealOEQ, left, right, - "is_eq"))) { + if (comp_ctx->disable_llvm_intrinsics + && aot_intrinsic_check_capability(comp_ctx, + is_f32 ? "f32_cmp" : "f64_cmp")) { + LLVMTypeRef param_types_intrinsic[3]; + LLVMValueRef opcond = LLVMConstInt(I32_TYPE, FLOAT_UNO, true); + param_types_intrinsic[0] = I32_TYPE; + param_types_intrinsic[1] = is_f32 ? F32_TYPE : F64_TYPE; + param_types_intrinsic[2] = param_types_intrinsic[1]; + is_nan = aot_call_llvm_intrinsic( + comp_ctx, func_ctx, is_f32 ? "f32_cmp" : "f64_cmp", I32_TYPE, + param_types_intrinsic, 3, opcond, left, right); + + opcond = LLVMConstInt(I32_TYPE, FLOAT_EQ, true); + is_eq = aot_call_llvm_intrinsic( + comp_ctx, func_ctx, is_f32 ? "f32_cmp" : "f64_cmp", I32_TYPE, + param_types_intrinsic, 3, opcond, left, right); + + if (!is_nan || !is_eq) { + return NULL; + } + + if (!(is_nan = LLVMBuildIntCast(comp_ctx->builder, is_nan, INT1_TYPE, + "bit_cast_is_nan"))) { + aot_set_last_error("llvm build is_nan bit cast fail."); + return NULL; + } + + if (!(is_eq = LLVMBuildIntCast(comp_ctx->builder, is_eq, INT1_TYPE, + "bit_cast_is_eq"))) { + aot_set_last_error("llvm build is_eq bit cast fail."); + return NULL; + } + } + else if (!(is_nan = LLVMBuildFCmp(comp_ctx->builder, LLVMRealUNO, left, + right, "is_nan")) + || !(is_eq = LLVMBuildFCmp(comp_ctx->builder, LLVMRealOEQ, left, + right, "is_eq"))) { aot_set_last_error("llvm build fcmp fail."); return NULL; } @@ -244,9 +290,13 @@ compile_op_float_min_max(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, } if (is_min) - LLVM_BUILD_OP(Or, left_int, right_int, tmp, "tmp_int", NULL); + LLVM_BUILD_OP_OR_INTRINSIC(Or, left_int, right_int, tmp, + is_f32 ? "i32.or" : "i64.or", "tmp_int", + false); else - LLVM_BUILD_OP(And, left_int, right_int, tmp, "tmp_int", NULL); + LLVM_BUILD_OP_OR_INTRINSIC(And, left_int, right_int, tmp, + is_f32 ? "i32.and" : "i64.and", "tmp_int", + false); if (!(tmp = LLVMBuildBitCast(comp_ctx->builder, tmp, ret_type, "tmp"))) { aot_set_last_error("llvm build bitcast fail."); @@ -257,6 +307,14 @@ compile_op_float_min_max(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, param_types, 2, left, right))) return NULL; + /* The result of XIP intrinsic is 0 or 1, should return it directly */ + + if (comp_ctx->disable_llvm_intrinsics + && aot_intrinsic_check_capability(comp_ctx, + is_f32 ? "f32_cmp" : "f64_cmp")) { + return cmp; + } + if (!(cmp = LLVMBuildSelect(comp_ctx->builder, is_eq, tmp, cmp, "cmp"))) { aot_set_last_error("llvm build select fail."); return NULL; @@ -331,6 +389,9 @@ compile_rems(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, { LLVMValueRef phi, no_overflow_value, zero = is_i32 ? I32_ZERO : I64_ZERO; LLVMBasicBlockRef block_curr, no_overflow_block, rems_end_block; + LLVMTypeRef param_types[2]; + + param_types[1] = param_types[0] = is_i32 ? I32_TYPE : I64_TYPE; block_curr = LLVMGetInsertBlock(comp_ctx->builder); @@ -348,8 +409,9 @@ compile_rems(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, /* Translate no_overflow_block */ LLVMPositionBuilderAtEnd(comp_ctx->builder, no_overflow_block); - /* Calculate the rem value */ - LLVM_BUILD_OP(SRem, left, right, no_overflow_value, "rem_s", false); + LLVM_BUILD_OP_OR_INTRINSIC(SRem, left, right, no_overflow_value, + is_i32 ? "i32.rem_s" : "i64.rem_s", "rem_s", + false); /* Jump to rems_end block */ if (!LLVMBuildBr(comp_ctx->builder, rems_end_block)) { @@ -389,6 +451,7 @@ compile_int_div(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, LLVMValueRef left, right, cmp_div_zero, overflow, res; LLVMBasicBlockRef check_div_zero_succ, check_overflow_succ; LLVMTypeRef param_types[2]; + const char *intrinsic = NULL; param_types[1] = param_types[0] = is_i32 ? I32_TYPE : I64_TYPE; @@ -462,56 +525,24 @@ compile_int_div(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, /* Build div */ switch (arith_op) { case INT_DIV_S: - if (comp_ctx->disable_llvm_intrinsics && !is_i32 - && aot_intrinsic_check_capability(comp_ctx, - "i64.div_s")) { - res = aot_call_llvm_intrinsic( - comp_ctx, func_ctx, "i64.div_s", param_types[0], - param_types, 2, left, right); - } - else { - LLVM_BUILD_OP(SDiv, left, right, res, "div_s", - false); - } + LLVM_BUILD_OP_OR_INTRINSIC( + SDiv, left, right, res, + is_i32 ? "i32.div_s" : "i64.div_s", "div_s", false); break; case INT_DIV_U: - if (comp_ctx->disable_llvm_intrinsics && !is_i32 - && aot_intrinsic_check_capability(comp_ctx, - "i64.div_u")) { - res = aot_call_llvm_intrinsic( - comp_ctx, func_ctx, "i64.div_u", param_types[0], - param_types, 2, left, right); - } - else { - LLVM_BUILD_OP(UDiv, left, right, res, "div_u", - false); - } + LLVM_BUILD_OP_OR_INTRINSIC( + UDiv, left, right, res, + is_i32 ? "i32.div_u" : "i64.div_u", "div_u", false); break; case INT_REM_S: - if (comp_ctx->disable_llvm_intrinsics && !is_i32 - && aot_intrinsic_check_capability(comp_ctx, - "i64.rem_s")) { - res = aot_call_llvm_intrinsic( - comp_ctx, func_ctx, "i64.rem_s", param_types[0], - param_types, 2, left, right); - } - else { - LLVM_BUILD_OP(SRem, left, right, res, "rem_s", - false); - } + LLVM_BUILD_OP_OR_INTRINSIC( + SRem, left, right, res, + is_i32 ? "i32.rem_s" : "i64.rem_s", "rem_s", false); break; case INT_REM_U: - if (comp_ctx->disable_llvm_intrinsics && !is_i32 - && aot_intrinsic_check_capability(comp_ctx, - "i64.rem_u")) { - res = aot_call_llvm_intrinsic( - comp_ctx, func_ctx, "i64.rem_u", param_types[0], - param_types, 2, left, right); - } - else { - LLVM_BUILD_OP(URem, left, right, res, "rem_u", - false); - } + LLVM_BUILD_OP_OR_INTRINSIC( + URem, left, right, res, + is_i32 ? "i32.rem_u" : "i64.rem_u", "rem_u", false); break; default: bh_assert(0); @@ -550,11 +581,22 @@ compile_int_div(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, check_overflow_succ))) goto fail; - LLVM_BUILD_OP(SDiv, left, right, res, "div_s", false); + LLVM_BUILD_OP_OR_INTRINSIC(SDiv, left, right, res, + is_i32 ? "i32.div_s" : "i64.div_s", + "div_s", false); PUSH_INT(res); return true; case INT_DIV_U: - LLVM_BUILD_OP(UDiv, left, right, res, "div_u", false); + intrinsic = is_i32 ? "i32.div_u" : "i64.div_u"; + if (comp_ctx->disable_llvm_intrinsics + && aot_intrinsic_check_capability(comp_ctx, intrinsic)) { + res = aot_call_llvm_intrinsic(comp_ctx, func_ctx, intrinsic, + param_types[0], param_types, + 2, left, right); + } + else { + LLVM_BUILD_OP(UDiv, left, right, res, "div_u", false); + } PUSH_INT(res); return true; case INT_REM_S: @@ -566,7 +608,9 @@ compile_int_div(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, return compile_rems(comp_ctx, func_ctx, left, right, overflow, is_i32); case INT_REM_U: - LLVM_BUILD_OP(URem, left, right, res, "rem_u", false); + LLVM_BUILD_OP_OR_INTRINSIC(URem, left, right, res, + is_i32 ? "i32.rem_u" : "i64.rem_u", + "rem_u", false); PUSH_INT(res); return true; default: diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_emit_numberic.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_emit_numberic.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_emit_numberic.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_emit_numberic.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_emit_parametric.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_emit_parametric.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_emit_parametric.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_emit_parametric.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_emit_parametric.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_emit_parametric.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_emit_parametric.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_emit_parametric.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_emit_table.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_emit_table.c similarity index 91% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_emit_table.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_emit_table.c index 984ce8a0494..d8a5efd9137 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_emit_table.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_emit_table.c @@ -15,16 +15,17 @@ get_tbl_inst_offset(const AOTCompContext *comp_ctx, AOTImportTable *imp_tbls = comp_ctx->comp_data->import_tables; AOTTable *tbls = comp_ctx->comp_data->tables; - /* from the head of AOTModuleInstance */ offset = offsetof(AOTModuleInstance, global_table_data.bytes) + (uint64)comp_ctx->comp_data->memory_count * sizeof(AOTMemoryInstance) + comp_ctx->comp_data->global_data_size; while (i < tbl_idx && i < comp_ctx->comp_data->import_table_count) { - offset += offsetof(AOTTableInstance, data); + offset += offsetof(AOTTableInstance, elems); /* avoid loading from current AOTTableInstance */ - offset += sizeof(uint32) * aot_get_imp_tbl_data_slots(imp_tbls + i); + offset += + sizeof(uint32) + * aot_get_imp_tbl_data_slots(imp_tbls + i, comp_ctx->is_jit_mode); ++i; } @@ -35,9 +36,10 @@ get_tbl_inst_offset(const AOTCompContext *comp_ctx, tbl_idx -= comp_ctx->comp_data->import_table_count; i -= comp_ctx->comp_data->import_table_count; while (i < tbl_idx && i < comp_ctx->comp_data->table_count) { - offset += offsetof(AOTTableInstance, data); + offset += offsetof(AOTTableInstance, elems); /* avoid loading from current AOTTableInstance */ - offset += sizeof(uint32) * aot_get_tbl_data_slots(tbls + i); + offset += sizeof(uint32) + * aot_get_tbl_data_slots(tbls + i, comp_ctx->is_jit_mode); ++i; } @@ -82,7 +84,10 @@ aot_compile_op_elem_drop(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, param_types[1] = I32_TYPE; ret_type = VOID_TYPE; - GET_AOT_FUNCTION(aot_drop_table_seg, 2); + if (comp_ctx->is_jit_mode) + GET_AOT_FUNCTION(llvm_jit_drop_table_seg, 2); + else + GET_AOT_FUNCTION(aot_drop_table_seg, 2); param_values[0] = func_ctx->aot_inst; if (!(param_values[1] = I32_CONST(tbl_seg_idx))) { @@ -176,7 +181,7 @@ aot_compile_op_table_get(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, /* load data as i32* */ if (!(offset = I32_CONST(get_tbl_inst_offset(comp_ctx, func_ctx, tbl_idx) - + offsetof(AOTTableInstance, data)))) { + + offsetof(AOTTableInstance, elems)))) { HANDLE_FAILURE("LLVMConstInt"); goto fail; } @@ -230,7 +235,7 @@ aot_compile_op_table_set(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, /* load data as i32* */ if (!(offset = I32_CONST(get_tbl_inst_offset(comp_ctx, func_ctx, tbl_idx) - + offsetof(AOTTableInstance, data)))) { + + offsetof(AOTTableInstance, elems)))) { HANDLE_FAILURE("LLVMConstInt"); goto fail; } @@ -282,7 +287,10 @@ aot_compile_op_table_init(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, param_types[5] = I32_TYPE; ret_type = VOID_TYPE; - GET_AOT_FUNCTION(aot_table_init, 6); + if (comp_ctx->is_jit_mode) + GET_AOT_FUNCTION(llvm_jit_table_init, 6); + else + GET_AOT_FUNCTION(aot_table_init, 6); param_values[0] = func_ctx->aot_inst; @@ -330,7 +338,10 @@ aot_compile_op_table_copy(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, param_types[5] = I32_TYPE; ret_type = VOID_TYPE; - GET_AOT_FUNCTION(aot_table_copy, 6); + if (comp_ctx->is_jit_mode) + GET_AOT_FUNCTION(llvm_jit_table_copy, 6); + else + GET_AOT_FUNCTION(aot_table_copy, 6); param_values[0] = func_ctx->aot_inst; @@ -414,7 +425,10 @@ aot_compile_op_table_grow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, param_types[3] = I32_TYPE; ret_type = I32_TYPE; - GET_AOT_FUNCTION(aot_table_grow, 4); + if (comp_ctx->is_jit_mode) + GET_AOT_FUNCTION(llvm_jit_table_grow, 4); + else + GET_AOT_FUNCTION(aot_table_grow, 4); param_values[0] = func_ctx->aot_inst; @@ -455,7 +469,10 @@ aot_compile_op_table_fill(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, param_types[4] = I32_TYPE; ret_type = VOID_TYPE; - GET_AOT_FUNCTION(aot_table_fill, 5); + if (comp_ctx->is_jit_mode) + GET_AOT_FUNCTION(llvm_jit_table_fill, 5); + else + GET_AOT_FUNCTION(aot_table_fill, 5); param_values[0] = func_ctx->aot_inst; diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_emit_table.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_emit_table.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_emit_table.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_emit_table.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_emit_variable.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_emit_variable.c similarity index 99% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_emit_variable.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_emit_variable.c index 4510a4c344c..70487d4dedb 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_emit_variable.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_emit_variable.c @@ -114,14 +114,16 @@ compile_global(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, { AOTCompData *comp_data = comp_ctx->comp_data; uint32 import_global_count = comp_data->import_global_count; - uint32 global_base_offset = - offsetof(AOTModuleInstance, global_table_data.bytes) - + sizeof(AOTMemoryInstance) * comp_ctx->comp_data->memory_count; + uint32 global_base_offset; uint32 global_offset; uint8 global_type; LLVMValueRef offset, global_ptr, global, res; LLVMTypeRef ptr_type = NULL; + global_base_offset = + offsetof(AOTModuleInstance, global_table_data.bytes) + + sizeof(AOTMemoryInstance) * comp_ctx->comp_data->memory_count; + bh_assert(global_idx < import_global_count + comp_data->global_count); if (global_idx < import_global_count) { diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_emit_variable.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_emit_variable.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_emit_variable.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_emit_variable.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_llvm.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_llvm.c similarity index 86% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_llvm.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_llvm.c index 5f052bf2929..dc3fe7f5959 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_llvm.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_llvm.c @@ -4,6 +4,7 @@ */ #include "aot_llvm.h" +#include "aot_llvm_extra2.h" #include "aot_compiler.h" #include "aot_emit_exception.h" #include "../aot/aot_runtime.h" @@ -48,9 +49,13 @@ aot_add_llvm_func(AOTCompContext *comp_ctx, LLVMModuleRef module, LLVMValueRef func = NULL; LLVMTypeRef *param_types, ret_type, func_type; LLVMValueRef local_value; - char func_name[32]; + LLVMTypeRef func_type_wrapper; + LLVMValueRef func_wrapper; + LLVMBasicBlockRef func_begin; + char func_name[48]; uint64 size; uint32 i, j = 0, param_count = (uint64)aot_func_type->param_count; + uint32 backend_thread_num, compile_thread_num; /* exec env as first parameter */ param_count++; @@ -116,6 +121,43 @@ aot_add_llvm_func(AOTCompContext *comp_ctx, LLVMModuleRef module, if (p_func_type) *p_func_type = func_type; + backend_thread_num = WASM_ORC_JIT_BACKEND_THREAD_NUM; + compile_thread_num = WASM_ORC_JIT_COMPILE_THREAD_NUM; + + /* Add the jit wrapper function with simple prototype, so that we + can easily call it to trigger its compilation and let LLVM JIT + compile the actual jit functions by adding them into the function + list in the PartitionFunction callback */ + if (comp_ctx->is_jit_mode + && (func_index % (backend_thread_num * compile_thread_num) + < backend_thread_num)) { + func_type_wrapper = LLVMFunctionType(VOID_TYPE, NULL, 0, false); + if (!func_type_wrapper) { + aot_set_last_error("create LLVM function type failed."); + goto fail; + } + + snprintf(func_name, sizeof(func_name), "%s%d%s", AOT_FUNC_PREFIX, + func_index, "_wrapper"); + if (!(func_wrapper = + LLVMAddFunction(module, func_name, func_type_wrapper))) { + aot_set_last_error("add LLVM function failed."); + goto fail; + } + + if (!(func_begin = LLVMAppendBasicBlockInContext( + comp_ctx->context, func_wrapper, "func_begin"))) { + aot_set_last_error("add LLVM basic block failed."); + goto fail; + } + + LLVMPositionBuilderAtEnd(comp_ctx->builder, func_begin); + if (!LLVMBuildRetVoid(comp_ctx->builder)) { + aot_set_last_error("llvm build ret failed."); + goto fail; + } + } + fail: wasm_runtime_free(param_types); return func; @@ -188,6 +230,250 @@ aot_create_func_block(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, return NULL; } +static bool +create_argv_buf(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) +{ + LLVMValueRef argv_buf_offset = I32_THREE, argv_buf_addr; + LLVMTypeRef int32_ptr_type; + + /* Get argv buffer address */ + if (!(argv_buf_addr = LLVMBuildInBoundsGEP2( + comp_ctx->builder, OPQ_PTR_TYPE, func_ctx->exec_env, + &argv_buf_offset, 1, "argv_buf_addr"))) { + aot_set_last_error("llvm build in bounds gep failed"); + return false; + } + + if (!(int32_ptr_type = LLVMPointerType(INT32_PTR_TYPE, 0))) { + aot_set_last_error("llvm add pointer type failed"); + return false; + } + + /* Convert to int32 pointer type */ + if (!(argv_buf_addr = LLVMBuildBitCast(comp_ctx->builder, argv_buf_addr, + int32_ptr_type, "argv_buf_ptr"))) { + aot_set_last_error("llvm build load failed"); + return false; + } + + if (!(func_ctx->argv_buf = LLVMBuildLoad2(comp_ctx->builder, INT32_PTR_TYPE, + argv_buf_addr, "argv_buf"))) { + aot_set_last_error("llvm build load failed"); + return false; + } + + return true; +} + +static bool +create_native_stack_bound(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) +{ + LLVMValueRef stack_bound_offset = I32_FOUR, stack_bound_addr; + + if (!(stack_bound_addr = LLVMBuildInBoundsGEP2( + comp_ctx->builder, OPQ_PTR_TYPE, func_ctx->exec_env, + &stack_bound_offset, 1, "stack_bound_addr"))) { + aot_set_last_error("llvm build in bounds gep failed"); + return false; + } + + if (!(func_ctx->native_stack_bound = + LLVMBuildLoad2(comp_ctx->builder, OPQ_PTR_TYPE, stack_bound_addr, + "native_stack_bound"))) { + aot_set_last_error("llvm build load failed"); + return false; + } + + return true; +} + +static bool +create_native_stack_top_min(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) +{ + LLVMValueRef offset = I32_NINE; + + if (!(func_ctx->native_stack_top_min_addr = LLVMBuildInBoundsGEP2( + comp_ctx->builder, OPQ_PTR_TYPE, func_ctx->exec_env, &offset, 1, + "native_stack_top_min_addr"))) { + aot_set_last_error("llvm build in bounds gep failed"); + return false; + } + + return true; +} + +static bool +create_aux_stack_info(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) +{ + LLVMValueRef aux_stack_bound_offset = I32_SIX, aux_stack_bound_addr; + LLVMValueRef aux_stack_bottom_offset = I32_SEVEN, aux_stack_bottom_addr; + + /* Get aux stack boundary address */ + if (!(aux_stack_bound_addr = LLVMBuildInBoundsGEP2( + comp_ctx->builder, OPQ_PTR_TYPE, func_ctx->exec_env, + &aux_stack_bound_offset, 1, "aux_stack_bound_addr"))) { + aot_set_last_error("llvm build in bounds gep failed"); + return false; + } + + if (!(aux_stack_bound_addr = + LLVMBuildBitCast(comp_ctx->builder, aux_stack_bound_addr, + INT32_PTR_TYPE, "aux_stack_bound_ptr"))) { + aot_set_last_error("llvm build bit cast failed"); + return false; + } + + if (!(func_ctx->aux_stack_bound = + LLVMBuildLoad2(comp_ctx->builder, I32_TYPE, aux_stack_bound_addr, + "aux_stack_bound"))) { + aot_set_last_error("llvm build load failed"); + return false; + } + + /* Get aux stack bottom address */ + if (!(aux_stack_bottom_addr = LLVMBuildInBoundsGEP2( + comp_ctx->builder, OPQ_PTR_TYPE, func_ctx->exec_env, + &aux_stack_bottom_offset, 1, "aux_stack_bottom_addr"))) { + aot_set_last_error("llvm build in bounds gep failed"); + return false; + } + + if (!(aux_stack_bottom_addr = + LLVMBuildBitCast(comp_ctx->builder, aux_stack_bottom_addr, + INT32_PTR_TYPE, "aux_stack_bottom_ptr"))) { + aot_set_last_error("llvm build bit cast failed"); + return false; + } + if (!(func_ctx->aux_stack_bottom = + LLVMBuildLoad2(comp_ctx->builder, I32_TYPE, aux_stack_bottom_addr, + "aux_stack_bottom"))) { + aot_set_last_error("llvm build load failed"); + return false; + } + + return true; +} + +static bool +create_native_symbol(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) +{ + LLVMValueRef native_symbol_offset = I32_EIGHT, native_symbol_addr; + + if (!(native_symbol_addr = LLVMBuildInBoundsGEP2( + comp_ctx->builder, OPQ_PTR_TYPE, func_ctx->exec_env, + &native_symbol_offset, 1, "native_symbol_addr"))) { + aot_set_last_error("llvm build in bounds gep failed"); + return false; + } + + if (!(func_ctx->native_symbol = + LLVMBuildLoad2(comp_ctx->builder, OPQ_PTR_TYPE, + native_symbol_addr, "native_symbol_tmp"))) { + aot_set_last_error("llvm build bit cast failed"); + return false; + } + + if (!(func_ctx->native_symbol = + LLVMBuildBitCast(comp_ctx->builder, func_ctx->native_symbol, + comp_ctx->exec_env_type, "native_symbol"))) { + aot_set_last_error("llvm build bit cast failed"); + return false; + } + + return true; +} + +static bool +create_local_variables(AOTCompData *comp_data, AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, AOTFunc *func) +{ + AOTFuncType *aot_func_type = comp_data->func_types[func->func_type_index]; + char local_name[32]; + uint32 i, j = 1; + + for (i = 0; i < aot_func_type->param_count; i++, j++) { + snprintf(local_name, sizeof(local_name), "l%d", i); + func_ctx->locals[i] = + LLVMBuildAlloca(comp_ctx->builder, + TO_LLVM_TYPE(aot_func_type->types[i]), local_name); + if (!func_ctx->locals[i]) { + aot_set_last_error("llvm build alloca failed."); + return false; + } + if (!LLVMBuildStore(comp_ctx->builder, LLVMGetParam(func_ctx->func, j), + func_ctx->locals[i])) { + aot_set_last_error("llvm build store failed."); + return false; + } + } + + for (i = 0; i < func->local_count; i++) { + LLVMTypeRef local_type; + LLVMValueRef local_value = NULL; + snprintf(local_name, sizeof(local_name), "l%d", + aot_func_type->param_count + i); + local_type = TO_LLVM_TYPE(func->local_types[i]); + func_ctx->locals[aot_func_type->param_count + i] = + LLVMBuildAlloca(comp_ctx->builder, local_type, local_name); + if (!func_ctx->locals[aot_func_type->param_count + i]) { + aot_set_last_error("llvm build alloca failed."); + return false; + } + switch (func->local_types[i]) { + case VALUE_TYPE_I32: + local_value = I32_ZERO; + break; + case VALUE_TYPE_I64: + local_value = I64_ZERO; + break; + case VALUE_TYPE_F32: + local_value = F32_ZERO; + break; + case VALUE_TYPE_F64: + local_value = F64_ZERO; + break; + case VALUE_TYPE_V128: + local_value = V128_i64x2_ZERO; + break; + case VALUE_TYPE_FUNCREF: + case VALUE_TYPE_EXTERNREF: + local_value = REF_NULL; + break; + default: + bh_assert(0); + break; + } + if (!LLVMBuildStore(comp_ctx->builder, local_value, + func_ctx->locals[aot_func_type->param_count + i])) { + aot_set_last_error("llvm build store failed."); + return false; + } + } + + if (comp_ctx->enable_stack_bound_check + || comp_ctx->enable_stack_estimation) { + if (aot_func_type->param_count + func->local_count > 0) { + func_ctx->last_alloca = func_ctx->locals[aot_func_type->param_count + + func->local_count - 1]; + if (!(func_ctx->last_alloca = + LLVMBuildBitCast(comp_ctx->builder, func_ctx->last_alloca, + INT8_PTR_TYPE, "stack_ptr"))) { + aot_set_last_error("llvm build bit cast failed."); + return false; + } + } + else { + if (!(func_ctx->last_alloca = LLVMBuildAlloca( + comp_ctx->builder, INT8_TYPE, "stack_ptr"))) { + aot_set_last_error("llvm build alloca failed."); + return false; + } + } + } + + return true; +} + static bool create_memory_info(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, LLVMTypeRef int8_ptr_type, uint32 func_index) @@ -264,7 +550,7 @@ create_memory_info(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, return false; } /* memories[0]->memory_data */ - offset = I32_CONST(offsetof(AOTMemoryInstance, memory_data.ptr)); + offset = I32_CONST(offsetof(AOTMemoryInstance, memory_data)); if (!(func_ctx->mem_info[0].mem_base_addr = LLVMBuildInBoundsGEP2( comp_ctx->builder, INT8_TYPE, shared_mem_addr, &offset, 1, "mem_base_addr_offset"))) { @@ -292,15 +578,24 @@ create_memory_info(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, else #endif { - offset = I32_CONST(offsetof(AOTModuleInstance, global_table_data) - + offsetof(AOTMemoryInstance, memory_data.ptr)); + uint32 offset_of_global_table_data; + + if (comp_ctx->is_jit_mode) + offset_of_global_table_data = + offsetof(WASMModuleInstance, global_table_data); + else + offset_of_global_table_data = + offsetof(AOTModuleInstance, global_table_data); + + offset = I32_CONST(offset_of_global_table_data + + offsetof(AOTMemoryInstance, memory_data)); if (!(func_ctx->mem_info[0].mem_base_addr = LLVMBuildInBoundsGEP2( comp_ctx->builder, INT8_TYPE, func_ctx->aot_inst, &offset, 1, "mem_base_addr_offset"))) { aot_set_last_error("llvm build in bounds gep failed"); return false; } - offset = I32_CONST(offsetof(AOTModuleInstance, global_table_data) + offset = I32_CONST(offset_of_global_table_data + offsetof(AOTMemoryInstance, cur_page_count)); if (!(func_ctx->mem_info[0].mem_cur_page_count_addr = LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE, @@ -309,7 +604,7 @@ create_memory_info(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, aot_set_last_error("llvm build in bounds gep failed"); return false; } - offset = I32_CONST(offsetof(AOTModuleInstance, global_table_data) + offset = I32_CONST(offset_of_global_table_data + offsetof(AOTMemoryInstance, memory_data_size)); if (!(func_ctx->mem_info[0].mem_data_size_addr = LLVMBuildInBoundsGEP2( comp_ctx->builder, INT8_TYPE, func_ctx->aot_inst, &offset, 1, @@ -379,7 +674,7 @@ create_memory_info(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, /* Load memory bound check constants */ offset = I32_CONST(offsetof(AOTMemoryInstance, mem_bound_check_1byte) - - offsetof(AOTMemoryInstance, memory_data.ptr)); + - offsetof(AOTMemoryInstance, memory_data)); if (!(func_ctx->mem_info[0].mem_bound_check_1byte = LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE, mem_info_base, &offset, 1, "bound_check_1byte_offset"))) { @@ -405,7 +700,7 @@ create_memory_info(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, } offset = I32_CONST(offsetof(AOTMemoryInstance, mem_bound_check_2bytes) - - offsetof(AOTMemoryInstance, memory_data.ptr)); + - offsetof(AOTMemoryInstance, memory_data)); if (!(func_ctx->mem_info[0].mem_bound_check_2bytes = LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE, mem_info_base, &offset, 1, "bound_check_2bytes_offset"))) { @@ -431,7 +726,7 @@ create_memory_info(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, } offset = I32_CONST(offsetof(AOTMemoryInstance, mem_bound_check_4bytes) - - offsetof(AOTMemoryInstance, memory_data.ptr)); + - offsetof(AOTMemoryInstance, memory_data)); if (!(func_ctx->mem_info[0].mem_bound_check_4bytes = LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE, mem_info_base, &offset, 1, "bound_check_4bytes_offset"))) { @@ -457,7 +752,7 @@ create_memory_info(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, } offset = I32_CONST(offsetof(AOTMemoryInstance, mem_bound_check_8bytes) - - offsetof(AOTMemoryInstance, memory_data.ptr)); + - offsetof(AOTMemoryInstance, memory_data)); if (!(func_ctx->mem_info[0].mem_bound_check_8bytes = LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE, mem_info_base, &offset, 1, "bound_check_8bytes_offset"))) { @@ -483,7 +778,7 @@ create_memory_info(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, } offset = I32_CONST(offsetof(AOTMemoryInstance, mem_bound_check_16bytes) - - offsetof(AOTMemoryInstance, memory_data.ptr)); + - offsetof(AOTMemoryInstance, memory_data)); if (!(func_ctx->mem_info[0].mem_bound_check_16bytes = LLVMBuildInBoundsGEP2( comp_ctx->builder, INT8_TYPE, mem_info_base, &offset, 1, "bound_check_16bytes_offset"))) { @@ -533,7 +828,7 @@ create_func_type_indexes(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx) LLVMValueRef offset, func_type_indexes_ptr; LLVMTypeRef int32_ptr_type; - offset = I32_CONST(offsetof(AOTModuleInstance, func_type_indexes.ptr)); + offset = I32_CONST(offsetof(AOTModuleInstance, func_type_indexes)); func_type_indexes_ptr = LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE, func_ctx->aot_inst, &offset, 1, "func_type_indexes_ptr"); @@ -613,17 +908,12 @@ aot_create_func_context(AOTCompData *comp_data, AOTCompContext *comp_ctx, { AOTFuncContext *func_ctx; AOTFuncType *aot_func_type = comp_data->func_types[func->func_type_index]; + WASMModule *module = comp_ctx->comp_data->wasm_module; + WASMFunction *wasm_func = module->functions[func_index]; AOTBlock *aot_block; - LLVMTypeRef int8_ptr_type, int32_ptr_type; + LLVMTypeRef int8_ptr_type; LLVMValueRef aot_inst_offset = I32_TWO, aot_inst_addr; - LLVMValueRef argv_buf_offset = I32_THREE, argv_buf_addr; - LLVMValueRef stack_bound_offset = I32_FOUR, stack_bound_addr; - LLVMValueRef aux_stack_bound_offset = I32_SIX, aux_stack_bound_addr; - LLVMValueRef aux_stack_bottom_offset = I32_SEVEN, aux_stack_bottom_addr; - LLVMValueRef native_symbol_offset = I32_EIGHT, native_symbol_addr; - char local_name[32]; uint64 size; - uint32 i, j = 0; /* Allocate memory for the function context */ size = offsetof(AOTFuncContext, locals) @@ -637,232 +927,79 @@ aot_create_func_context(AOTCompData *comp_data, AOTCompContext *comp_ctx, memset(func_ctx, 0, (uint32)size); func_ctx->aot_func = func; -#if WASM_ENABLE_LAZY_JIT == 0 func_ctx->module = comp_ctx->module; -#else - func_ctx->module = comp_ctx->modules[func_index]; -#endif /* Add LLVM function */ if (!(func_ctx->func = aot_add_llvm_func(comp_ctx, func_ctx->module, aot_func_type, - func_index, &func_ctx->func_type))) - goto fail; - - /* Create function's first AOTBlock */ - if (!(aot_block = - aot_create_func_block(comp_ctx, func_ctx, func, aot_func_type))) - goto fail; - -#if WASM_ENABLE_DEBUG_AOT != 0 - func_ctx->debug_func = dwarf_gen_func_info(comp_ctx, func_ctx); -#endif - - aot_block_stack_push(&func_ctx->block_stack, aot_block); - - /* Add local variables */ - LLVMPositionBuilderAtEnd(comp_ctx->builder, aot_block->llvm_entry_block); - - /* Save the pameters for fast access */ - func_ctx->exec_env = LLVMGetParam(func_ctx->func, j++); - - /* Get aot inst address, the layout of exec_env is: - exec_env->next, exec_env->prev, exec_env->module_inst, and argv_buf */ - if (!(aot_inst_addr = LLVMBuildInBoundsGEP2( - comp_ctx->builder, OPQ_PTR_TYPE, func_ctx->exec_env, - &aot_inst_offset, 1, "aot_inst_addr"))) { - aot_set_last_error("llvm build in bounds gep failed"); - goto fail; - } - - /* Load aot inst */ - if (!(func_ctx->aot_inst = LLVMBuildLoad2(comp_ctx->builder, OPQ_PTR_TYPE, - aot_inst_addr, "aot_inst"))) { - aot_set_last_error("llvm build load failed"); - goto fail; - } - - /* Get argv buffer address */ - if (!(argv_buf_addr = LLVMBuildInBoundsGEP2( - comp_ctx->builder, OPQ_PTR_TYPE, func_ctx->exec_env, - &argv_buf_offset, 1, "argv_buf_addr"))) { - aot_set_last_error("llvm build in bounds gep failed"); - goto fail; - } - - if (!(int32_ptr_type = LLVMPointerType(INT32_PTR_TYPE, 0))) { - aot_set_last_error("llvm add pointer type failed"); - goto fail; - } - - /* Convert to int32 pointer type */ - if (!(argv_buf_addr = LLVMBuildBitCast(comp_ctx->builder, argv_buf_addr, - int32_ptr_type, "argv_buf_ptr"))) { - aot_set_last_error("llvm build load failed"); + func_index, &func_ctx->func_type))) { goto fail; } - if (!(func_ctx->argv_buf = LLVMBuildLoad2(comp_ctx->builder, INT32_PTR_TYPE, - argv_buf_addr, "argv_buf"))) { - aot_set_last_error("llvm build load failed"); - goto fail; - } - - /* Get native stack boundary address */ - if (!(stack_bound_addr = LLVMBuildInBoundsGEP2( - comp_ctx->builder, OPQ_PTR_TYPE, func_ctx->exec_env, - &stack_bound_offset, 1, "stack_bound_addr"))) { - aot_set_last_error("llvm build in bounds gep failed"); - goto fail; - } - - if (!(func_ctx->native_stack_bound = - LLVMBuildLoad2(comp_ctx->builder, OPQ_PTR_TYPE, stack_bound_addr, - "native_stack_bound"))) { - aot_set_last_error("llvm build load failed"); - goto fail; - } - - /* Get aux stack boundary address */ - if (!(aux_stack_bound_addr = LLVMBuildInBoundsGEP2( - comp_ctx->builder, OPQ_PTR_TYPE, func_ctx->exec_env, - &aux_stack_bound_offset, 1, "aux_stack_bound_addr"))) { - aot_set_last_error("llvm build in bounds gep failed"); - goto fail; - } - - if (!(aux_stack_bound_addr = - LLVMBuildBitCast(comp_ctx->builder, aux_stack_bound_addr, - INT32_PTR_TYPE, "aux_stack_bound_ptr"))) { - aot_set_last_error("llvm build bit cast failed"); - goto fail; - } - - if (!(func_ctx->aux_stack_bound = - LLVMBuildLoad2(comp_ctx->builder, I32_TYPE, aux_stack_bound_addr, - "aux_stack_bound"))) { - aot_set_last_error("llvm build load failed"); + /* Create function's first AOTBlock */ + if (!(aot_block = + aot_create_func_block(comp_ctx, func_ctx, func, aot_func_type))) { goto fail; } - /* Get aux stack bottom address */ - if (!(aux_stack_bottom_addr = LLVMBuildInBoundsGEP2( +#if WASM_ENABLE_DEBUG_AOT != 0 + func_ctx->debug_func = dwarf_gen_func_info(comp_ctx, func_ctx); +#endif + + aot_block_stack_push(&func_ctx->block_stack, aot_block); + + /* Add local variables */ + LLVMPositionBuilderAtEnd(comp_ctx->builder, aot_block->llvm_entry_block); + + /* Save the pameters for fast access */ + func_ctx->exec_env = LLVMGetParam(func_ctx->func, 0); + + /* Get aot inst address, the layout of exec_env is: + exec_env->next, exec_env->prev, exec_env->module_inst, and argv_buf */ + if (!(aot_inst_addr = LLVMBuildInBoundsGEP2( comp_ctx->builder, OPQ_PTR_TYPE, func_ctx->exec_env, - &aux_stack_bottom_offset, 1, "aux_stack_bottom_addr"))) { + &aot_inst_offset, 1, "aot_inst_addr"))) { aot_set_last_error("llvm build in bounds gep failed"); goto fail; } - if (!(aux_stack_bottom_addr = - LLVMBuildBitCast(comp_ctx->builder, aux_stack_bottom_addr, - INT32_PTR_TYPE, "aux_stack_bottom_ptr"))) { - aot_set_last_error("llvm build bit cast failed"); - goto fail; - } - if (!(func_ctx->aux_stack_bottom = - LLVMBuildLoad2(comp_ctx->builder, I32_TYPE, aux_stack_bottom_addr, - "aux_stack_bottom"))) { + /* Load aot inst */ + if (!(func_ctx->aot_inst = LLVMBuildLoad2(comp_ctx->builder, OPQ_PTR_TYPE, + aot_inst_addr, "aot_inst"))) { aot_set_last_error("llvm build load failed"); goto fail; } - if (!(native_symbol_addr = LLVMBuildInBoundsGEP2( - comp_ctx->builder, OPQ_PTR_TYPE, func_ctx->exec_env, - &native_symbol_offset, 1, "native_symbol_addr"))) { - aot_set_last_error("llvm build in bounds gep failed"); + /* Get argv buffer address */ + if (wasm_func->has_op_func_call && !create_argv_buf(comp_ctx, func_ctx)) { goto fail; } - if (!(func_ctx->native_symbol = - LLVMBuildLoad2(comp_ctx->builder, OPQ_PTR_TYPE, - native_symbol_addr, "native_symbol_tmp"))) { - aot_set_last_error("llvm build bit cast failed"); + /* Get native stack boundary address */ + if (comp_ctx->enable_stack_bound_check + && !create_native_stack_bound(comp_ctx, func_ctx)) { goto fail; } - - if (!(func_ctx->native_symbol = - LLVMBuildBitCast(comp_ctx->builder, func_ctx->native_symbol, - comp_ctx->exec_env_type, "native_symbol"))) { - aot_set_last_error("llvm build bit cast failed"); + if (comp_ctx->enable_stack_estimation + && !create_native_stack_top_min(comp_ctx, func_ctx)) { goto fail; } - for (i = 0; i < aot_func_type->param_count; i++, j++) { - snprintf(local_name, sizeof(local_name), "l%d", i); - func_ctx->locals[i] = - LLVMBuildAlloca(comp_ctx->builder, - TO_LLVM_TYPE(aot_func_type->types[i]), local_name); - if (!func_ctx->locals[i]) { - aot_set_last_error("llvm build alloca failed."); - goto fail; - } - if (!LLVMBuildStore(comp_ctx->builder, LLVMGetParam(func_ctx->func, j), - func_ctx->locals[i])) { - aot_set_last_error("llvm build store failed."); - goto fail; - } + /* Get auxiliary stack info */ + if (wasm_func->has_op_set_global_aux_stack + && !create_aux_stack_info(comp_ctx, func_ctx)) { + goto fail; } - for (i = 0; i < func->local_count; i++) { - LLVMTypeRef local_type; - LLVMValueRef local_value = NULL; - snprintf(local_name, sizeof(local_name), "l%d", - aot_func_type->param_count + i); - local_type = TO_LLVM_TYPE(func->local_types[i]); - func_ctx->locals[aot_func_type->param_count + i] = - LLVMBuildAlloca(comp_ctx->builder, local_type, local_name); - if (!func_ctx->locals[aot_func_type->param_count + i]) { - aot_set_last_error("llvm build alloca failed."); - goto fail; - } - switch (func->local_types[i]) { - case VALUE_TYPE_I32: - local_value = I32_ZERO; - break; - case VALUE_TYPE_I64: - local_value = I64_ZERO; - break; - case VALUE_TYPE_F32: - local_value = F32_ZERO; - break; - case VALUE_TYPE_F64: - local_value = F64_ZERO; - break; - case VALUE_TYPE_V128: - local_value = V128_i64x2_ZERO; - break; - case VALUE_TYPE_FUNCREF: - case VALUE_TYPE_EXTERNREF: - local_value = REF_NULL; - break; - default: - bh_assert(0); - break; - } - if (!LLVMBuildStore(comp_ctx->builder, local_value, - func_ctx->locals[aot_func_type->param_count + i])) { - aot_set_last_error("llvm build store failed."); - goto fail; - } + /* Get native symbol list */ + if (comp_ctx->is_indirect_mode + && !create_native_symbol(comp_ctx, func_ctx)) { + goto fail; } - if (aot_func_type->param_count + func->local_count > 0) { - func_ctx->last_alloca = - func_ctx - ->locals[aot_func_type->param_count + func->local_count - 1]; - if (!(func_ctx->last_alloca = - LLVMBuildBitCast(comp_ctx->builder, func_ctx->last_alloca, - INT8_PTR_TYPE, "stack_ptr"))) { - aot_set_last_error("llvm build bit cast failed."); - goto fail; - } - } - else { - if (!(func_ctx->last_alloca = - LLVMBuildAlloca(comp_ctx->builder, INT8_TYPE, "stack_ptr"))) { - aot_set_last_error("llvm build alloca failed."); - goto fail; - } + /* Create local variables */ + if (!create_local_variables(comp_data, comp_ctx, func_ctx, func)) { + goto fail; } if (!(int8_ptr_type = LLVMPointerType(INT8_PTR_TYPE, 0))) { @@ -871,20 +1008,26 @@ aot_create_func_context(AOTCompData *comp_data, AOTCompContext *comp_ctx, } /* Create base addr, end addr, data size of mem, heap */ - if (!create_memory_info(comp_ctx, func_ctx, int8_ptr_type, func_index)) + if (wasm_func->has_memory_operations + && !create_memory_info(comp_ctx, func_ctx, int8_ptr_type, func_index)) { goto fail; + } /* Load current exception */ - if (!create_cur_exception(comp_ctx, func_ctx)) + if (!create_cur_exception(comp_ctx, func_ctx)) { goto fail; + } /* Load function type indexes */ - if (!create_func_type_indexes(comp_ctx, func_ctx)) + if (wasm_func->has_op_call_indirect + && !create_func_type_indexes(comp_ctx, func_ctx)) { goto fail; + } /* Load function pointers */ - if (!create_func_ptrs(comp_ctx, func_ctx)) + if (!create_func_ptrs(comp_ctx, func_ctx)) { goto fail; + } return func_ctx; @@ -1235,16 +1378,6 @@ get_target_arch_from_triple(const char *triple, char *arch_buf, uint32 buf_size) bh_assert(*triple == '-' || *triple == '\0'); } -LLVMBool -WAMRCreateMCJITCompilerForModule(LLVMExecutionEngineRef *OutJIT, - LLVMModuleRef M, - struct LLVMMCJITCompilerOptions *Options, - size_t SizeOfOptions, char **OutError); - -void -LLVMAddPromoteMemoryToRegisterPass(LLVMPassManagerRef PM); - -#if WASM_ENABLE_LAZY_JIT != 0 void aot_handle_llvm_errmsg(const char *string, LLVMErrorRef err) { @@ -1254,40 +1387,30 @@ aot_handle_llvm_errmsg(const char *string, LLVMErrorRef err) } static bool -orc_lazyjit_create(AOTCompContext *comp_ctx, uint32 func_count) +create_target_machine_detect_host(AOTCompContext *comp_ctx) { - uint32 i; + char *triple = NULL; + LLVMTargetRef target = NULL; char *err_msg = NULL; char *cpu = NULL; char *features = NULL; - char *llvm_triple = NULL; - char func_name[32] = { 0 }; - LLVMErrorRef err; - LLVMTargetRef llvm_targetref = NULL; - LLVMTargetMachineRef target_machine_for_orcjit = NULL; - LLVMOrcLLJITRef orc_lazyjit = NULL; - LLVMOrcJITTargetMachineBuilderRef target_machine_builder = NULL; - LLVMOrcLLJITBuilderRef orc_lazyjit_builder = NULL; - LLVMOrcMaterializationUnitRef orc_material_unit = NULL; - LLVMOrcExecutionSessionRef orc_execution_session = NULL; - LLVMOrcLazyCallThroughManagerRef orc_call_through_mgr = NULL; - LLVMOrcIndirectStubsManagerRef orc_indirect_stub_mgr = NULL; - LLVMOrcCSymbolAliasMapPair *orc_symbol_map_pairs = NULL; - - llvm_triple = LLVMGetDefaultTargetTriple(); - if (llvm_triple == NULL) { + LLVMTargetMachineRef target_machine = NULL; + bool ret = false; + + triple = LLVMGetDefaultTargetTriple(); + if (triple == NULL) { aot_set_last_error("failed to get default target triple."); goto fail; } - if (LLVMGetTargetFromTriple(llvm_triple, &llvm_targetref, &err_msg) != 0) { + if (LLVMGetTargetFromTriple(triple, &target, &err_msg) != 0) { aot_set_last_error_v("failed to get llvm target from triple %s.", err_msg); LLVMDisposeMessage(err_msg); goto fail; } - if (!LLVMTargetHasJIT(llvm_targetref)) { + if (!LLVMTargetHasJIT(target)) { aot_set_last_error("unspported JIT on this platform."); goto fail; } @@ -1307,161 +1430,115 @@ orc_lazyjit_create(AOTCompContext *comp_ctx, uint32 func_count) LOG_VERBOSE("LLVM ORCJIT detected CPU \"%s\", with features \"%s\"\n", cpu, features); - comp_ctx->target_machine = LLVMCreateTargetMachine( - llvm_targetref, llvm_triple, cpu, features, LLVMCodeGenLevelDefault, + /* create TargetMachine */ + target_machine = LLVMCreateTargetMachine( + target, triple, cpu, features, LLVMCodeGenLevelDefault, LLVMRelocDefault, LLVMCodeModelJITDefault); - if (!comp_ctx->target_machine) { + if (!target_machine) { aot_set_last_error("failed to create target machine."); goto fail; } + comp_ctx->target_machine = target_machine; - target_machine_for_orcjit = LLVMCreateTargetMachine( - llvm_targetref, llvm_triple, cpu, features, LLVMCodeGenLevelDefault, - LLVMRelocDefault, LLVMCodeModelJITDefault); - if (!target_machine_for_orcjit) { - aot_set_last_error("failed to create target machine."); - goto fail; - } + /* Save target arch */ + get_target_arch_from_triple(triple, comp_ctx->target_arch, + sizeof(comp_ctx->target_arch)); + ret = true; + +fail: + if (triple) + LLVMDisposeMessage(triple); + if (features) + LLVMDisposeMessage(features); + if (cpu) + LLVMDisposeMessage(cpu); + + return ret; +} - target_machine_builder = - LLVMOrcJITTargetMachineBuilderCreateFromTargetMachine( - target_machine_for_orcjit); - if (!target_machine_builder) { - aot_set_last_error("failed to create target machine builder."); +static bool +orc_jit_create(AOTCompContext *comp_ctx) +{ + LLVMErrorRef err; + LLVMOrcLLLazyJITRef orc_jit = NULL; + LLVMOrcLLLazyJITBuilderRef builder = NULL; + LLVMOrcJITTargetMachineBuilderRef jtmb = NULL; + bool ret = false; + + builder = LLVMOrcCreateLLLazyJITBuilder(); + if (builder == NULL) { + aot_set_last_error("failed to create jit builder."); goto fail; } - /* The target_machine_for_orcjit has been disposed before - LLVMOrcJITTargetMachineBuilderCreateFromTargetMachine() returns */ - target_machine_for_orcjit = NULL; - orc_lazyjit_builder = LLVMOrcCreateLLJITBuilder(); - if (!orc_lazyjit_builder) { - aot_set_last_error("failed to create lazy jit builder."); + err = LLVMOrcJITTargetMachineBuilderDetectHost(&jtmb); + if (err != LLVMErrorSuccess) { + aot_handle_llvm_errmsg( + "quited to create LLVMOrcJITTargetMachineBuilderRef", err); goto fail; } - LLVMOrcLLJITBuilderSetNumCompileThreads(orc_lazyjit_builder, - WASM_LAZY_JIT_COMPILE_THREAD_NUM); - LLVMOrcLLJITBuilderSetJITTargetMachineBuilder(orc_lazyjit_builder, - target_machine_builder); - /* Should not dispose of the JITTargetMachineBuilder after calling - LLVMOrcLLJITBuilderSetJITTargetMachineBuilder() */ - target_machine_builder = NULL; - - err = LLVMOrcCreateLLJIT(&orc_lazyjit, orc_lazyjit_builder); - if (err) { - aot_handle_llvm_errmsg("failed to create llvm lazy orcjit instance", + + LLVMOrcLLLazyJITBuilderSetNumCompileThreads( + builder, WASM_ORC_JIT_COMPILE_THREAD_NUM); + + /* Ownership transfer: + LLVMOrcJITTargetMachineBuilderRef -> LLVMOrcLLJITBuilderRef */ + LLVMOrcLLLazyJITBuilderSetJITTargetMachineBuilder(builder, jtmb); + err = LLVMOrcCreateLLLazyJIT(&orc_jit, builder); + if (err != LLVMErrorSuccess) { + aot_handle_llvm_errmsg("quited to create llvm lazy orcjit instance", err); goto fail; } - /* The orc_lazyjit_builder is managed by orc_lazyjit after calling - LLVMOrcCreateLLJIT(), here we should not dispose it again */ - orc_lazyjit_builder = NULL; - - if (func_count > 0) { - orc_execution_session = LLVMOrcLLJITGetExecutionSession(orc_lazyjit); - if (!orc_execution_session) { - aot_set_last_error("failed to get orc execution session"); - goto fail; - } + /* Ownership transfer: LLVMOrcLLJITBuilderRef -> LLVMOrcLLJITRef */ + builder = NULL; - err = LLVMOrcCreateLocalLazyCallThroughManager( - llvm_triple, orc_execution_session, 0, &orc_call_through_mgr); - if (err) { - aot_handle_llvm_errmsg("failed to create orc call through manager", - err); - goto fail; - } + /* Ownership transfer: local -> AOTCompContext */ + comp_ctx->orc_jit = orc_jit; + orc_jit = NULL; + ret = true; - orc_indirect_stub_mgr = - LLVMOrcCreateLocalIndirectStubsManager(llvm_triple); - if (!orc_indirect_stub_mgr) { - aot_set_last_error("failed to create orc indirect stub manager"); - goto fail; - } +fail: + if (builder) + LLVMOrcDisposeLLLazyJITBuilder(builder); - if (!(orc_symbol_map_pairs = wasm_runtime_malloc( - sizeof(LLVMOrcCSymbolAliasMapPair) * func_count))) { - aot_set_last_error("failed to allocate memory"); - goto fail; - } - memset(orc_symbol_map_pairs, 0, - sizeof(LLVMOrcCSymbolAliasMapPair) * func_count); - - for (i = 0; i < func_count; i++) { - snprintf(func_name, sizeof(func_name), "orcjit_%s%d", - AOT_FUNC_PREFIX, i); - orc_symbol_map_pairs[i].Name = - LLVMOrcExecutionSessionIntern(orc_execution_session, func_name); - snprintf(func_name, sizeof(func_name), "%s%d", AOT_FUNC_PREFIX, i); - orc_symbol_map_pairs[i].Entry.Name = - LLVMOrcExecutionSessionIntern(orc_execution_session, func_name); - orc_symbol_map_pairs[i].Entry.Flags.GenericFlags = - LLVMJITSymbolGenericFlagsExported - | LLVMJITSymbolGenericFlagsCallable; - orc_symbol_map_pairs[i].Entry.Flags.TargetFlags = - LLVMJITSymbolGenericFlagsExported - | LLVMJITSymbolGenericFlagsCallable; - - if (!orc_symbol_map_pairs[i].Name - || !orc_symbol_map_pairs[i].Entry.Name) { - aot_set_last_error("failed to allocate memory"); - goto fail; - } - } + if (orc_jit) + LLVMOrcDisposeLLLazyJIT(orc_jit); + return ret; +} - orc_material_unit = - LLVMOrcLazyReexports(orc_call_through_mgr, orc_indirect_stub_mgr, - LLVMOrcLLJITGetMainJITDylib(orc_lazyjit), - orc_symbol_map_pairs, func_count); - if (!orc_material_unit) { - aot_set_last_error("failed to orc re-exports"); - goto fail; - } - } +bool +aot_compiler_init(void) +{ + /* Initialize LLVM environment */ - comp_ctx->orc_lazyjit = orc_lazyjit; - comp_ctx->orc_material_unit = orc_material_unit; - comp_ctx->orc_symbol_map_pairs = orc_symbol_map_pairs; - comp_ctx->orc_call_through_mgr = orc_call_through_mgr; - comp_ctx->orc_indirect_stub_mgr = orc_indirect_stub_mgr; + LLVMInitializeCore(LLVMGetGlobalPassRegistry()); +#if WASM_ENABLE_WAMR_COMPILER != 0 + /* Init environment of all targets for AOT compiler */ + LLVMInitializeAllTargetInfos(); + LLVMInitializeAllTargets(); + LLVMInitializeAllTargetMCs(); + LLVMInitializeAllAsmPrinters(); +#else + /* Init environment of native for JIT compiler */ + LLVMInitializeNativeTarget(); + LLVMInitializeNativeTarget(); + LLVMInitializeNativeAsmPrinter(); +#endif - LLVMDisposeMessage(llvm_triple); - LLVMDisposeMessage(cpu); - LLVMDisposeMessage(features); return true; +} -fail: - if (orc_symbol_map_pairs) - wasm_runtime_free(orc_symbol_map_pairs); - if (orc_call_through_mgr) - LLVMOrcDisposeLazyCallThroughManager(orc_call_through_mgr); - if (orc_indirect_stub_mgr) - LLVMOrcDisposeIndirectStubsManager(orc_indirect_stub_mgr); - if (orc_lazyjit) - LLVMOrcDisposeLLJIT(orc_lazyjit); - if (target_machine_builder) - LLVMOrcDisposeJITTargetMachineBuilder(target_machine_builder); - if (orc_lazyjit_builder) - LLVMOrcDisposeLLJITBuilder(orc_lazyjit_builder); - if (target_machine_for_orcjit) - LLVMDisposeTargetMachine(target_machine_for_orcjit); - if (features) - LLVMDisposeMessage(features); - if (cpu) - LLVMDisposeMessage(cpu); - if (llvm_triple) - LLVMDisposeMessage(llvm_triple); - return false; +void +aot_compiler_destroy(void) +{ + LLVMShutdown(); } -#endif /* WASM_ENABLE_LAZY_JIT != 0 */ AOTCompContext * aot_create_comp_context(AOTCompData *comp_data, aot_comp_option_t option) { AOTCompContext *comp_ctx, *ret = NULL; -#if WASM_ENABLE_LAZY_JIT == 0 - struct LLVMMCJITCompilerOptions jit_options; -#endif LLVMTargetRef target; char *triple = NULL, *triple_norm, *arch, *abi; char *cpu = NULL, *features, buf[128]; @@ -1473,20 +1550,6 @@ aot_create_comp_context(AOTCompData *comp_data, aot_comp_option_t option) LLVMCodeModel code_model; LLVMTargetDataRef target_data_ref; - /* Initialize LLVM environment */ -#if WASM_ENABLE_LAZY_JIT != 0 - LLVMInitializeCore(LLVMGetGlobalPassRegistry()); - LLVMInitializeNativeTarget(); - LLVMInitializeNativeAsmPrinter(); - LLVMInitializeNativeAsmParser(); -#else - LLVMInitializeAllTargetInfos(); - LLVMInitializeAllTargets(); - LLVMInitializeAllTargetMCs(); - LLVMInitializeAllAsmPrinters(); - LLVMLinkInMCJIT(); -#endif - /* Allocate memory */ if (!(comp_ctx = wasm_runtime_malloc(sizeof(AOTCompContext)))) { aot_set_last_error("allocate memory failed."); @@ -1497,7 +1560,6 @@ aot_create_comp_context(AOTCompData *comp_data, aot_comp_option_t option) comp_ctx->comp_data = comp_data; /* Create LLVM context, module and builder */ -#if WASM_ENABLE_LAZY_JIT != 0 comp_ctx->orc_thread_safe_context = LLVMOrcCreateNewThreadSafeContext(); if (!comp_ctx->orc_thread_safe_context) { aot_set_last_error("create LLVM ThreadSafeContext failed."); @@ -1512,53 +1574,26 @@ aot_create_comp_context(AOTCompData *comp_data, aot_comp_option_t option) aot_set_last_error("get context from LLVM ThreadSafeContext failed."); goto fail; } -#else - if (!(comp_ctx->context = LLVMContextCreate())) { - aot_set_last_error("create LLVM context failed."); - goto fail; - } -#endif if (!(comp_ctx->builder = LLVMCreateBuilderInContext(comp_ctx->context))) { aot_set_last_error("create LLVM builder failed."); goto fail; } -#if WASM_ENABLE_LAZY_JIT == 0 + /* Create LLVM module for each jit function, note: + different from non ORC JIT mode, no need to dispose it, + it will be disposed when the thread safe context is disposed */ if (!(comp_ctx->module = LLVMModuleCreateWithNameInContext( "WASM Module", comp_ctx->context))) { aot_set_last_error("create LLVM module failed."); goto fail; } -#else - if (comp_data->func_count > 0) { - if (!(comp_ctx->modules = wasm_runtime_malloc( - sizeof(LLVMModuleRef) * comp_data->func_count))) { - aot_set_last_error("allocate memory failed."); - goto fail; - } - memset(comp_ctx->modules, 0, - sizeof(LLVMModuleRef) * comp_data->func_count); - for (i = 0; i < comp_data->func_count; i++) { - char module_name[32]; - snprintf(module_name, sizeof(module_name), "WASM Module %d", i); - /* Create individual modules for each aot function, note: - different from non LAZY JIT mode, no need to dispose them, - they will be disposed when the thread safe context is disposed */ - if (!(comp_ctx->modules[i] = LLVMModuleCreateWithNameInContext( - module_name, comp_ctx->context))) { - aot_set_last_error("create LLVM module failed."); - goto fail; - } - } - } -#endif if (BH_LIST_ERROR == bh_list_init(&comp_ctx->native_symbols)) { goto fail; } -#if WASM_ENABLE_DEBUG_AOT != 0 && WASM_ENABLE_LAZY_JIT == 0 +#if WASM_ENABLE_DEBUG_AOT != 0 if (!(comp_ctx->debug_builder = LLVMCreateDIBuilder(comp_ctx->module))) { aot_set_last_error("create LLVM Debug Infor builder failed."); goto fail; @@ -1608,6 +1643,9 @@ aot_create_comp_context(AOTCompData *comp_data, aot_comp_option_t option) if (option->disable_llvm_lto) comp_ctx->disable_llvm_lto = true; + if (option->enable_stack_estimation) + comp_ctx->enable_stack_estimation = true; + comp_ctx->opt_level = option->opt_level; comp_ctx->size_level = option->size_level; @@ -1615,64 +1653,34 @@ aot_create_comp_context(AOTCompData *comp_data, aot_comp_option_t option) comp_ctx->custom_sections_count = option->custom_sections_count; if (option->is_jit_mode) { - char *triple_jit = NULL; - comp_ctx->is_jit_mode = true; -#if WASM_ENABLE_LAZY_JIT != 0 - /* Create LLJIT Instance */ - if (!orc_lazyjit_create(comp_ctx, comp_data->func_count)) { + /* Create TargetMachine */ + if (!create_target_machine_detect_host(comp_ctx)) goto fail; - } -#else - /* Create LLVM execution engine */ - LLVMInitializeMCJITCompilerOptions(&jit_options, sizeof(jit_options)); - jit_options.OptLevel = LLVMCodeGenLevelAggressive; - jit_options.EnableFastISel = true; - /*jit_options.CodeModel = LLVMCodeModelSmall;*/ - if (WAMRCreateMCJITCompilerForModule(&comp_ctx->exec_engine, - comp_ctx->module, &jit_options, - sizeof(jit_options), &err) - != 0) { - if (err) { - LLVMDisposeMessage(err); - err = NULL; - } - aot_set_last_error("create LLVM JIT compiler failed."); + /* Create LLJIT Instance */ + if (!orc_jit_create(comp_ctx)) goto fail; - } - comp_ctx->target_machine = - LLVMGetExecutionEngineTargetMachine(comp_ctx->exec_engine); -#endif #ifndef OS_ENABLE_HW_BOUND_CHECK comp_ctx->enable_bound_check = true; + /* Always enable stack boundary check if `bounds-checks` + is enabled */ + comp_ctx->enable_stack_bound_check = true; #else comp_ctx->enable_bound_check = false; -#endif - -#if WASM_ENABLE_LAZY_JIT != 0 - if (!(triple_jit = - (char *)LLVMOrcLLJITGetTripleString(comp_ctx->orc_lazyjit))) { - aot_set_last_error("can not get triple from the target machine"); - goto fail; - } - - /* Save target arch */ - get_target_arch_from_triple(triple_jit, comp_ctx->target_arch, - sizeof(comp_ctx->target_arch)); + /* When `bounds-checks` is disabled, we set stack boundary + check status according to the compilation option */ +#if WASM_DISABLE_STACK_HW_BOUND_CHECK != 0 + /* Native stack overflow check with hardware trap is disabled, + we need to enable the check by LLVM JITed/AOTed code */ + comp_ctx->enable_stack_bound_check = true; #else - if (!(triple_jit = - LLVMGetTargetMachineTriple(comp_ctx->target_machine))) { - aot_set_last_error("can not get triple from the target machine"); - goto fail; - } - - /* Save target arch */ - get_target_arch_from_triple(triple_jit, comp_ctx->target_arch, - sizeof(comp_ctx->target_arch)); - LLVMDisposeMessage(triple_jit); + /* Native stack overflow check with hardware trap is enabled, + no need to enable the check by LLVM JITed/AOTed code */ + comp_ctx->enable_stack_bound_check = false; +#endif #endif } else { @@ -1933,17 +1941,9 @@ aot_create_comp_context(AOTCompData *comp_data, aot_comp_option_t option) aot_set_last_error("create metadata string failed."); goto fail; } -#if WASM_ENABLE_LAZY_JIT == 0 LLVMAddModuleFlag(comp_ctx->module, LLVMModuleFlagBehaviorError, "target-abi", strlen("target-abi"), meta_target_abi); -#else - for (i = 0; i < comp_data->func_count; i++) { - LLVMAddModuleFlag(comp_ctx->modules[i], - LLVMModuleFlagBehaviorError, "target-abi", - strlen("target-abi"), meta_target_abi); - } -#endif if (!strcmp(abi, "lp64d") || !strcmp(abi, "ilp32d")) { if (features) { @@ -1992,6 +1992,18 @@ aot_create_comp_context(AOTCompData *comp_data, aot_comp_option_t option) } } + if (comp_ctx->enable_bound_check) { + /* Always enable stack boundary check if `bounds-checks` + is enabled */ + comp_ctx->enable_stack_bound_check = true; + } + else { + /* When `bounds-checks` is disabled, we set stack boundary + check status according to the input option */ + comp_ctx->enable_stack_bound_check = + (option->stack_bounds_checks == 1) ? true : false; + } + os_printf("Create AoT compiler with:\n"); os_printf(" target: %s\n", comp_ctx->target_arch); os_printf(" target cpu: %s\n", cpu); @@ -2044,16 +2056,13 @@ aot_create_comp_context(AOTCompData *comp_data, aot_comp_option_t option) code_model = LLVMCodeModelSmall; /* Create the target machine */ - if (!(comp_ctx->target_machine = LLVMCreateTargetMachine( + if (!(comp_ctx->target_machine = LLVMCreateTargetMachineWithOpts( target, triple_norm, cpu, features, opt_level, - LLVMRelocStatic, code_model))) { + LLVMRelocStatic, code_model, false, + option->stack_usage_file))) { aot_set_last_error("create LLVM target machine failed."); goto fail; } - -#if WASM_ENABLE_LAZY_JIT == 0 - LLVMSetTarget(comp_ctx->module, triple_norm); -#endif } if (option->enable_simd && strcmp(comp_ctx->target_arch, "x86_64") != 0 @@ -2162,56 +2171,21 @@ aot_destroy_comp_context(AOTCompContext *comp_ctx) if (!comp_ctx) return; -#if WASM_ENABLE_LAZY_JIT != 0 - if (comp_ctx->orc_symbol_map_pairs) - wasm_runtime_free(comp_ctx->orc_symbol_map_pairs); - - if (comp_ctx->orc_call_through_mgr) - LLVMOrcDisposeLazyCallThroughManager(comp_ctx->orc_call_through_mgr); - - if (comp_ctx->orc_indirect_stub_mgr) - LLVMOrcDisposeIndirectStubsManager(comp_ctx->orc_indirect_stub_mgr); - - if (comp_ctx->orc_material_unit) - LLVMOrcDisposeMaterializationUnit(comp_ctx->orc_material_unit); - if (comp_ctx->target_machine) LLVMDisposeTargetMachine(comp_ctx->target_machine); if (comp_ctx->builder) LLVMDisposeBuilder(comp_ctx->builder); - if (comp_ctx->orc_lazyjit) - LLVMOrcDisposeLLJIT(comp_ctx->orc_lazyjit); - if (comp_ctx->orc_thread_safe_context) LLVMOrcDisposeThreadSafeContext(comp_ctx->orc_thread_safe_context); - if (comp_ctx->modules) - wasm_runtime_free(comp_ctx->modules); - - /* Note: don't dispose comp_ctx->context and comp_ctx->modules[i] as + /* Note: don't dispose comp_ctx->context and comp_ctx->module as they are disposed when disposing the thread safe context */ - LLVMShutdown(); -#else - if (comp_ctx->target_machine && !comp_ctx->is_jit_mode) - LLVMDisposeTargetMachine(comp_ctx->target_machine); - - if (comp_ctx->builder) - LLVMDisposeBuilder(comp_ctx->builder); - - if (comp_ctx->exec_engine) { - LLVMDisposeExecutionEngine(comp_ctx->exec_engine); - /* The LLVM module is freed when disposing execution engine, - no need to dispose it again. */ - } - else if (comp_ctx->module) - LLVMDisposeModule(comp_ctx->module); - - if (comp_ctx->context) - LLVMContextDispose(comp_ctx->context); -#endif + /* Has to be the last one */ + if (comp_ctx->orc_jit) + LLVMOrcDisposeLLLazyJIT(comp_ctx->orc_jit); if (comp_ctx->func_ctxes) aot_destroy_func_contexts(comp_ctx->func_ctxes, @@ -2280,11 +2254,11 @@ aot_get_native_symbol_index(AOTCompContext *comp_ctx, const char *symbol) if (idx < 0) { if (comp_ctx->pointer_size == sizeof(uint32) - && !strncmp(symbol, "f64#", 4)) { + && (!strncmp(symbol, "f64#", 4) || !strncmp(symbol, "i64#", 4))) { idx = bh_list_length(&comp_ctx->native_symbols); /* Add 4 bytes padding on 32-bit target to make sure that the f64 const is stored on 8-byte aligned address */ - if ((idx & 1) && !strncmp(comp_ctx->target_arch, "i386", 4)) { + if (idx & 1) { if (!insert_native_symbol(comp_ctx, "__ignore", idx)) { return -1; } @@ -2297,7 +2271,7 @@ aot_get_native_symbol_index(AOTCompContext *comp_ctx, const char *symbol) } if (comp_ctx->pointer_size == sizeof(uint32) - && !strncmp(symbol, "f64#", 4)) { + && (!strncmp(symbol, "f64#", 4) || !strncmp(symbol, "i64#", 4))) { /* f64 const occupies 2 pointer slots on 32-bit target */ if (!insert_native_symbol(comp_ctx, "__ignore", idx + 1)) { return -1; diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_llvm.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_llvm.h similarity index 91% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_llvm.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_llvm.h index 7964c3acd97..2a1564019d7 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_llvm.h +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_llvm.h @@ -20,20 +20,18 @@ #include "llvm-c/Transforms/Vectorize.h" #include "llvm-c/Transforms/PassManagerBuilder.h" -#if WASM_ENABLE_LAZY_JIT != 0 #include "llvm-c/Orc.h" #include "llvm-c/Error.h" #include "llvm-c/Support.h" #include "llvm-c/Initialization.h" #include "llvm-c/TargetMachine.h" -#if LLVM_VERSION_MAJOR >= 12 #include "llvm-c/LLJIT.h" -#endif -#endif #if WASM_ENABLE_DEBUG_AOT != 0 #include "llvm-c/DebugInfo.h" #endif +#include "aot_orc_extra.h" + #ifdef __cplusplus extern "C" { #endif @@ -52,6 +50,16 @@ extern "C" { #define OPQ_PTR_TYPE INT8_PTR_TYPE #endif +#ifndef NDEBUG +#undef DEBUG_PASS +#undef DUMP_MODULE +// #define DEBUG_PASS +// #define DUMP_MODULE +#else +#undef DEBUG_PASS +#undef DUMP_MODULE +#endif + /** * Value in the WASM operation stack, each stack element * is an LLVM value @@ -155,6 +163,7 @@ typedef struct AOTFuncContext { LLVMValueRef aot_inst; LLVMValueRef argv_buf; LLVMValueRef native_stack_bound; + LLVMValueRef native_stack_top_min_addr; LLVMValueRef aux_stack_bound; LLVMValueRef aux_stack_bottom; LLVMValueRef native_symbol; @@ -270,12 +279,6 @@ typedef struct AOTCompContext { /* LLVM variables required to emit LLVM IR */ LLVMContextRef context; -#if WASM_ENABLE_LAZY_JIT == 0 - /* Create one module only for non LAZY JIT mode, - for LAZY JIT mode, modules are created, each - aot function has its own module */ - LLVMModuleRef module; -#endif LLVMBuilderRef builder; #if WASM_ENABLE_DEBUG_AOT LLVMDIBuilderRef debug_builder; @@ -290,19 +293,11 @@ typedef struct AOTCompContext { /* Hardware intrinsic compability flags */ uint64 flags[8]; - /* LLVM execution engine required by JIT */ -#if WASM_ENABLE_LAZY_JIT != 0 - LLVMOrcLLJITRef orc_lazyjit; - LLVMOrcMaterializationUnitRef orc_material_unit; - LLVMOrcLazyCallThroughManagerRef orc_call_through_mgr; - LLVMOrcIndirectStubsManagerRef orc_indirect_stub_mgr; - LLVMOrcCSymbolAliasMapPairs orc_symbol_map_pairs; + /* required by JIT */ + LLVMOrcLLLazyJITRef orc_jit; LLVMOrcThreadSafeContextRef orc_thread_safe_context; - /* Each aot function has its own module */ - LLVMModuleRef *modules; -#else - LLVMExecutionEngineRef exec_engine; -#endif + + LLVMModuleRef module; bool is_jit_mode; @@ -316,6 +311,12 @@ typedef struct AOTCompContext { /* Bounday Check */ bool enable_bound_check; + /* Native stack bounday Check */ + bool enable_stack_bound_check; + + /* Native stack usage estimation */ + bool enable_stack_estimation; + /* 128-bit SIMD */ bool enable_simd; @@ -361,6 +362,7 @@ typedef struct AOTCompContext { AOTLLVMConsts llvm_consts; /* Function contexts */ + /* TODO: */ AOTFuncContext **func_ctxes; uint32 func_ctx_count; char **custom_sections_wp; @@ -405,14 +407,23 @@ typedef struct AOTCompOption { bool enable_aux_stack_frame; bool disable_llvm_intrinsics; bool disable_llvm_lto; + bool enable_stack_estimation; uint32 opt_level; uint32 size_level; uint32 output_format; uint32 bounds_checks; + uint32 stack_bounds_checks; char **custom_sections; uint32 custom_sections_count; + const char *stack_usage_file; } AOTCompOption, *aot_comp_option_t; +bool +aot_compiler_init(void); + +void +aot_compiler_destroy(void); + AOTCompContext * aot_create_comp_context(AOTCompData *comp_data, aot_comp_option_t option); @@ -503,24 +514,11 @@ void aot_add_simple_loop_unswitch_pass(LLVMPassManagerRef pass); void -aot_apply_llvm_new_pass_manager(AOTCompContext *comp_ctx); - -#if WASM_ENABLE_LAZY_JIT != 0 -LLVMOrcJITTargetMachineBuilderRef -LLVMOrcJITTargetMachineBuilderCreateFromTargetMachine(LLVMTargetMachineRef TM); - -void -LLVMOrcLLJITBuilderSetNumCompileThreads(LLVMOrcLLJITBuilderRef orcjit_builder, - unsigned num_compile_threads); +aot_apply_llvm_new_pass_manager(AOTCompContext *comp_ctx, LLVMModuleRef module); void aot_handle_llvm_errmsg(const char *string, LLVMErrorRef err); -void * -aot_lookup_orcjit_func(LLVMOrcLLJITRef orc_lazyjit, void *module_inst, - uint32 func_idx); -#endif - #ifdef __cplusplus } /* end of extern "C" */ #endif diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_llvm_extra.cpp b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_llvm_extra.cpp similarity index 53% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_llvm_extra.cpp rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_llvm_extra.cpp index ed9fabd99aa..9b77f5e6a1e 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/aot_llvm_extra.cpp +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_llvm_extra.cpp @@ -3,6 +3,8 @@ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception */ +#include +#include #include #include #include @@ -42,23 +44,15 @@ #if LLVM_VERSION_MAJOR >= 12 #include #endif + #include -#if WASM_ENABLE_LAZY_JIT != 0 #include "../aot/aot_runtime.h" -#endif - #include "aot_llvm.h" using namespace llvm; using namespace llvm::orc; -extern "C" { - -LLVMBool -WAMRCreateMCJITCompilerForModule(LLVMExecutionEngineRef *OutJIT, - LLVMModuleRef M, - LLVMMCJITCompilerOptions *PassedOptions, - size_t SizeOfPassedOptions, char **OutError); +LLVM_C_EXTERN_C_BEGIN bool aot_check_simd_compatibility(const char *arch_c_str, const char *cpu_c_str); @@ -70,93 +64,11 @@ void aot_add_simple_loop_unswitch_pass(LLVMPassManagerRef pass); void -aot_func_disable_tce(LLVMValueRef func); - -void -aot_apply_llvm_new_pass_manager(AOTCompContext *comp_ctx); -} - -static TargetMachine * -unwrap(LLVMTargetMachineRef P) -{ - return reinterpret_cast(P); -} +aot_apply_llvm_new_pass_manager(AOTCompContext *comp_ctx, LLVMModuleRef module); -LLVMBool -WAMRCreateMCJITCompilerForModule(LLVMExecutionEngineRef *OutJIT, - LLVMModuleRef M, - LLVMMCJITCompilerOptions *PassedOptions, - size_t SizeOfPassedOptions, char **OutError) -{ - LLVMMCJITCompilerOptions options; - // If the user passed a larger sized options struct, then they were compiled - // against a newer LLVM. Tell them that something is wrong. - if (SizeOfPassedOptions > sizeof(options)) { - *OutError = strdup("Refusing to use options struct that is larger than " - "my own; assuming LLVM library mismatch."); - return 1; - } - - // Defend against the user having an old version of the API by ensuring that - // any fields they didn't see are cleared. We must defend against fields - // being set to the bitwise equivalent of zero, and assume that this means - // "do the default" as if that option hadn't been available. - LLVMInitializeMCJITCompilerOptions(&options, sizeof(options)); - memcpy(&options, PassedOptions, SizeOfPassedOptions); - - TargetOptions targetOptions; - targetOptions.EnableFastISel = options.EnableFastISel; - std::unique_ptr Mod(unwrap(M)); - - if (Mod) { - // Set function attribute "frame-pointer" based on - // NoFramePointerElim. - for (auto &F : *Mod) { - auto Attrs = F.getAttributes(); - StringRef Value = options.NoFramePointerElim ? "all" : "none"; -#if LLVM_VERSION_MAJOR <= 13 - Attrs = - Attrs.addAttribute(F.getContext(), AttributeList::FunctionIndex, - "frame-pointer", Value); -#else - Attrs = Attrs.addAttributeAtIndex(F.getContext(), - AttributeList::FunctionIndex, - "frame-pointer", Value); -#endif - F.setAttributes(Attrs); - } - } +LLVM_C_EXTERN_C_END - std::string Error; - bool JIT; - char *host_cpu = LLVMGetHostCPUName(); - - if (!host_cpu) { - *OutError = NULL; - return false; - } - - std::string mcpu(host_cpu); - LLVMDisposeMessage(host_cpu); - - EngineBuilder builder(std::move(Mod)); - builder.setEngineKind(EngineKind::JIT) - .setErrorStr(&Error) - .setMCPU(mcpu) - .setOptLevel((CodeGenOpt::Level)options.OptLevel) - .setTargetOptions(targetOptions); - if (Optional CM = unwrap(options.CodeModel, JIT)) - builder.setCodeModel(*CM); - if (options.MCJMM) - builder.setMCJITMemoryManager( - std::unique_ptr(unwrap(options.MCJMM))); - if (ExecutionEngine *JIT = builder.create()) { - *OutJIT = wrap(JIT); - return 0; - } - *OutError = strdup(Error.c_str()); - return 1; -} +ExitOnError ExitOnErr; class ExpandMemoryOpPass : public llvm::ModulePass { @@ -258,13 +170,15 @@ ExpandMemoryOpPass::runOnModule(Module &M) void aot_add_expand_memory_op_pass(LLVMPassManagerRef pass) { - unwrap(pass)->add(new ExpandMemoryOpPass()); + reinterpret_cast(pass)->add( + new ExpandMemoryOpPass()); } void aot_add_simple_loop_unswitch_pass(LLVMPassManagerRef pass) { - unwrap(pass)->add(createSimpleLoopUnswitchLegacyPass()); + reinterpret_cast(pass)->add( + createSimpleLoopUnswitchLegacyPass()); } bool @@ -308,123 +222,54 @@ aot_check_simd_compatibility(const char *arch_c_str, const char *cpu_c_str) #endif /* WASM_ENABLE_SIMD */ } -#if WASM_ENABLE_LAZY_JIT != 0 - -#if LLVM_VERSION_MAJOR < 12 -LLVMOrcJITTargetMachineBuilderRef -LLVMOrcJITTargetMachineBuilderFromTargetMachine(LLVMTargetMachineRef TM); - -LLVMOrcJITTargetMachineBuilderRef -LLVMOrcJITTargetMachineBuilderCreateFromTargetMachine(LLVMTargetMachineRef TM) -{ - return LLVMOrcJITTargetMachineBuilderFromTargetMachine(TM); -} -#endif - -DEFINE_SIMPLE_CONVERSION_FUNCTIONS(LLJITBuilder, LLVMOrcLLJITBuilderRef) - -void -LLVMOrcLLJITBuilderSetNumCompileThreads(LLVMOrcLLJITBuilderRef orcjit_builder, - unsigned num_compile_threads) -{ - unwrap(orcjit_builder)->setNumCompileThreads(num_compile_threads); -} - -void * -aot_lookup_orcjit_func(LLVMOrcLLJITRef orc_lazyjit, void *module_inst, - uint32 func_idx) -{ - char func_name[32], buf[128], *err_msg = NULL; - LLVMErrorRef error; - LLVMOrcJITTargetAddress func_addr = 0; - AOTModuleInstance *aot_inst = (AOTModuleInstance *)module_inst; - AOTModule *aot_module = (AOTModule *)aot_inst->aot_module.ptr; - void **func_ptrs = (void **)aot_inst->func_ptrs.ptr; - - /** - * No need to lock the func_ptr[func_idx] here as it is basic - * data type, the load/store for it can be finished by one cpu - * instruction, and there can be only one cpu instruction - * loading/storing at the same time. - */ - if (func_ptrs[func_idx]) - return func_ptrs[func_idx]; - - snprintf(func_name, sizeof(func_name), "%s%d", AOT_FUNC_PREFIX, - func_idx - aot_module->import_func_count); - if ((error = LLVMOrcLLJITLookup(orc_lazyjit, &func_addr, func_name))) { - err_msg = LLVMGetErrorMessage(error); - snprintf(buf, sizeof(buf), "failed to lookup orcjit function: %s", - err_msg); - aot_set_exception(aot_inst, buf); - LLVMDisposeErrorMessage(err_msg); - return NULL; - } - func_ptrs[func_idx] = (void *)func_addr; - return (void *)func_addr; -} -#endif /* end of WASM_ENABLE_LAZY_JIT != 0 */ - void -aot_func_disable_tce(LLVMValueRef func) +aot_apply_llvm_new_pass_manager(AOTCompContext *comp_ctx, LLVMModuleRef module) { - Function *F = unwrap(func); - auto Attrs = F->getAttributes(); - -#if LLVM_VERSION_MAJOR <= 13 - Attrs = Attrs.addAttribute(F->getContext(), AttributeList::FunctionIndex, - "disable-tail-calls", "true"); -#else - Attrs = - Attrs.addAttributeAtIndex(F->getContext(), AttributeList::FunctionIndex, - "disable-tail-calls", "true"); -#endif - F->setAttributes(Attrs); -} - -#if LLVM_VERSION_MAJOR >= 12 -void -aot_apply_llvm_new_pass_manager(AOTCompContext *comp_ctx) -{ - Module *M; - TargetMachine *TM = unwrap(comp_ctx->target_machine); - bool disable_llvm_lto = false; - - LoopAnalysisManager LAM; - FunctionAnalysisManager FAM; - CGSCCAnalysisManager CGAM; - ModuleAnalysisManager MAM; - + TargetMachine *TM = + reinterpret_cast(comp_ctx->target_machine); PipelineTuningOptions PTO; PTO.LoopVectorization = true; PTO.SLPVectorization = true; PTO.LoopUnrolling = true; +#ifdef DEBUG_PASS + PassInstrumentationCallbacks PIC; + PassBuilder PB(TM, PTO, None, &PIC); +#else #if LLVM_VERSION_MAJOR == 12 PassBuilder PB(false, TM, PTO); #else PassBuilder PB(TM, PTO); +#endif #endif - // Register the target library analysis directly and give it a - // customized preset TLI. + /* Register all the basic analyses with the managers */ + LoopAnalysisManager LAM; + FunctionAnalysisManager FAM; + CGSCCAnalysisManager CGAM; + ModuleAnalysisManager MAM; + + /* Register the target library analysis directly and give it a + customized preset TLI */ std::unique_ptr TLII( new TargetLibraryInfoImpl(Triple(TM->getTargetTriple()))); FAM.registerPass([&] { return TargetLibraryAnalysis(*TLII); }); - // Register the AA manager first so that our version is the one used. + /* Register the AA manager first so that our version is the one used */ AAManager AA = PB.buildDefaultAAPipeline(); FAM.registerPass([&] { return std::move(AA); }); - // Register all the basic analyses with the managers. - PB.registerModuleAnalyses(MAM); - PB.registerCGSCCAnalyses(CGAM); +#ifdef DEBUG_PASS + StandardInstrumentations SI(true, false); + SI.registerCallbacks(PIC, &FAM); +#endif + PB.registerFunctionAnalyses(FAM); PB.registerLoopAnalyses(LAM); + PB.registerModuleAnalyses(MAM); + PB.registerCGSCCAnalyses(CGAM); PB.crossRegisterProxies(LAM, FAM, CGAM, MAM); - ModulePassManager MPM; - #if LLVM_VERSION_MAJOR <= 13 PassBuilder::OptimizationLevel OL; @@ -463,25 +308,23 @@ aot_apply_llvm_new_pass_manager(AOTCompContext *comp_ctx) } #endif /* end of LLVM_VERSION_MAJOR */ - if (comp_ctx->disable_llvm_lto) { - disable_llvm_lto = true; - } + bool disable_llvm_lto = comp_ctx->disable_llvm_lto; #if WASM_ENABLE_SPEC_TEST != 0 disable_llvm_lto = true; #endif + Module *M = reinterpret_cast(module); if (disable_llvm_lto) { - uint32 i; - - for (i = 0; i < comp_ctx->func_ctx_count; i++) { - aot_func_disable_tce(comp_ctx->func_ctxes[i]->func); + for (Function &F : *M) { + F.addFnAttr("disable-tail-calls", "true"); } } + ModulePassManager MPM; if (comp_ctx->is_jit_mode) { - /* Apply normal pipeline for JIT mode, without - Vectorize related passes, without LTO */ - MPM.addPass(PB.buildPerModuleDefaultPipeline(OL)); + const char *Passes = + "mem2reg,instcombine,simplifycfg,jump-threading,indvars"; + ExitOnErr(PB.parsePassPipeline(MPM, Passes)); } else { FunctionPassManager FPM; @@ -501,27 +344,17 @@ aot_apply_llvm_new_pass_manager(AOTCompContext *comp_ctx) if (!disable_llvm_lto) { /* Apply LTO for AOT mode */ -#if LLVM_VERSION_MAJOR < 14 - MPM.addPass(PB.buildLTODefaultPipeline(OL, NULL)); -#else - MPM.addPass(PB.buildLTOPreLinkDefaultPipeline(OL)); -#endif + if (comp_ctx->comp_data->func_count >= 10) + /* Adds the pre-link optimizations if the func count + is large enough */ + MPM.addPass(PB.buildLTOPreLinkDefaultPipeline(OL)); + else + MPM.addPass(PB.buildLTODefaultPipeline(OL, NULL)); } else { MPM.addPass(PB.buildPerModuleDefaultPipeline(OL)); } } -#if WASM_ENABLE_LAZY_JIT == 0 - M = unwrap(comp_ctx->module); MPM.run(*M, MAM); -#else - uint32 i; - - for (i = 0; i < comp_ctx->func_ctx_count; i++) { - M = unwrap(comp_ctx->modules[i]); - MPM.run(*M, MAM); - } -#endif } -#endif /* end of LLVM_VERSION_MAJOR >= 12 */ diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_llvm_extra2.cpp b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_llvm_extra2.cpp new file mode 100644 index 00000000000..9bd44bbff77 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_llvm_extra2.cpp @@ -0,0 +1,108 @@ +/* + * Copyright (c)2023 YAMAMOTO Takashi. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include +#include +#include + +#include "bh_assert.h" + +#include "aot_llvm_extra2.h" + +static llvm::Optional +convert(LLVMRelocMode reloc_mode) +{ + switch (reloc_mode) { + case LLVMRelocDefault: + return llvm::None; + case LLVMRelocStatic: + return llvm::Reloc::Static; + case LLVMRelocPIC: + return llvm::Reloc::PIC_; + case LLVMRelocDynamicNoPic: + return llvm::Reloc::DynamicNoPIC; + case LLVMRelocROPI: + return llvm::Reloc::ROPI; + case LLVMRelocRWPI: + return llvm::Reloc::RWPI; + case LLVMRelocROPI_RWPI: + return llvm::Reloc::ROPI_RWPI; + } + bh_assert(0); + return llvm::None; +} + +static llvm::CodeGenOpt::Level +convert(LLVMCodeGenOptLevel opt_level) +{ + switch (opt_level) { + case LLVMCodeGenLevelNone: + return llvm::CodeGenOpt::None; + case LLVMCodeGenLevelLess: + return llvm::CodeGenOpt::Less; + case LLVMCodeGenLevelDefault: + return llvm::CodeGenOpt::Default; + case LLVMCodeGenLevelAggressive: + return llvm::CodeGenOpt::Aggressive; + } + bh_assert(0); + return llvm::CodeGenOpt::None; +} + +static llvm::Optional +convert(LLVMCodeModel code_model, bool *jit) +{ + *jit = false; + switch (code_model) { + case LLVMCodeModelDefault: + return llvm::None; + case LLVMCodeModelJITDefault: + *jit = true; + return llvm::None; + case LLVMCodeModelTiny: + return llvm::CodeModel::Tiny; + case LLVMCodeModelSmall: + return llvm::CodeModel::Small; + case LLVMCodeModelKernel: + return llvm::CodeModel::Kernel; + case LLVMCodeModelMedium: + return llvm::CodeModel::Medium; + case LLVMCodeModelLarge: + return llvm::CodeModel::Large; + } + bh_assert(0); + return llvm::None; +} + +LLVMTargetMachineRef +LLVMCreateTargetMachineWithOpts(LLVMTargetRef ctarget, const char *triple, + const char *cpu, const char *features, + LLVMCodeGenOptLevel opt_level, + LLVMRelocMode reloc_mode, + LLVMCodeModel code_model, + bool EmitStackSizeSection, + const char *StackUsageOutput) +{ + llvm::TargetOptions opts; + + // -fstack-size-section equiv + // emit it to ".stack_sizes" section in case of ELF + // you can read it with "llvm-readobj --stack-sizes" + opts.EmitStackSizeSection = EmitStackSizeSection; + + // -fstack-usage equiv + if (StackUsageOutput != NULL) { + opts.StackUsageOutput = StackUsageOutput; + } + + auto target = reinterpret_cast(ctarget); + auto rm = convert(reloc_mode); + auto ol = convert(opt_level); + bool jit; + auto cm = convert(code_model, &jit); + auto targetmachine = target->createTargetMachine(triple, cpu, features, + opts, rm, cm, ol, jit); + return reinterpret_cast(targetmachine); +} diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_llvm_extra2.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_llvm_extra2.h new file mode 100644 index 00000000000..ef99622a431 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_llvm_extra2.h @@ -0,0 +1,17 @@ +/* + * Copyright (c)2023 YAMAMOTO Takashi. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include + +LLVM_C_EXTERN_C_BEGIN +LLVMTargetMachineRef +LLVMCreateTargetMachineWithOpts(LLVMTargetRef ctarget, const char *triple, + const char *cpu, const char *features, + LLVMCodeGenOptLevel opt_level, + LLVMRelocMode reloc_mode, + LLVMCodeModel code_model, + bool EmitStackSizeSection, + const char *StackUsageOutput); +LLVM_C_EXTERN_C_END diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_orc_extra.cpp b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_orc_extra.cpp new file mode 100644 index 00000000000..8cf253e9487 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_orc_extra.cpp @@ -0,0 +1,289 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "llvm-c/LLJIT.h" +#include "llvm-c/Orc.h" +#include "llvm-c/OrcEE.h" +#include "llvm-c/TargetMachine.h" + +#include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h" +#include "llvm/ExecutionEngine/Orc/LLJIT.h" +#include "llvm/ExecutionEngine/Orc/ObjectTransformLayer.h" +#include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h" +#include "llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h" +#include "llvm/ExecutionEngine/SectionMemoryManager.h" +#include "llvm/Support/CBindingWrapping.h" + +#include "aot_orc_extra.h" +#include "aot.h" + +using namespace llvm; +using namespace llvm::orc; +using GlobalValueSet = std::set; + +namespace llvm { +namespace orc { + +class InProgressLookupState; + +class OrcV2CAPIHelper +{ + public: + using PoolEntry = SymbolStringPtr::PoolEntry; + using PoolEntryPtr = SymbolStringPtr::PoolEntryPtr; + + // Move from SymbolStringPtr to PoolEntryPtr (no change in ref count). + static PoolEntryPtr moveFromSymbolStringPtr(SymbolStringPtr S) + { + PoolEntryPtr Result = nullptr; + std::swap(Result, S.S); + return Result; + } + + // Move from a PoolEntryPtr to a SymbolStringPtr (no change in ref count). + static SymbolStringPtr moveToSymbolStringPtr(PoolEntryPtr P) + { + SymbolStringPtr S; + S.S = P; + return S; + } + + // Copy a pool entry to a SymbolStringPtr (increments ref count). + static SymbolStringPtr copyToSymbolStringPtr(PoolEntryPtr P) + { + return SymbolStringPtr(P); + } + + static PoolEntryPtr getRawPoolEntryPtr(const SymbolStringPtr &S) + { + return S.S; + } + + static void retainPoolEntry(PoolEntryPtr P) + { + SymbolStringPtr S(P); + S.S = nullptr; + } + + static void releasePoolEntry(PoolEntryPtr P) + { + SymbolStringPtr S; + S.S = P; + } + + static InProgressLookupState *extractLookupState(LookupState &LS) + { + return LS.IPLS.release(); + } + + static void resetLookupState(LookupState &LS, InProgressLookupState *IPLS) + { + return LS.reset(IPLS); + } +}; + +} // namespace orc +} // namespace llvm + +// ORC.h +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(ExecutionSession, LLVMOrcExecutionSessionRef) +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(IRTransformLayer, LLVMOrcIRTransformLayerRef) +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(JITDylib, LLVMOrcJITDylibRef) +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(JITTargetMachineBuilder, + LLVMOrcJITTargetMachineBuilderRef) +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(ObjectTransformLayer, + LLVMOrcObjectTransformLayerRef) +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(OrcV2CAPIHelper::PoolEntry, + LLVMOrcSymbolStringPoolEntryRef) +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(SymbolStringPool, LLVMOrcSymbolStringPoolRef) +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(ThreadSafeModule, LLVMOrcThreadSafeModuleRef) + +// LLJIT.h +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(LLJITBuilder, LLVMOrcLLJITBuilderRef) +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(LLLazyJITBuilder, LLVMOrcLLLazyJITBuilderRef) +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(LLLazyJIT, LLVMOrcLLLazyJITRef) + +void +LLVMOrcLLJITBuilderSetNumCompileThreads(LLVMOrcLLJITBuilderRef Builder, + unsigned NumCompileThreads) +{ + unwrap(Builder)->setNumCompileThreads(NumCompileThreads); +} + +LLVMOrcLLLazyJITBuilderRef +LLVMOrcCreateLLLazyJITBuilder(void) +{ + return wrap(new LLLazyJITBuilder()); +} + +void +LLVMOrcDisposeLLLazyJITBuilder(LLVMOrcLLLazyJITBuilderRef Builder) +{ + delete unwrap(Builder); +} + +void +LLVMOrcLLLazyJITBuilderSetNumCompileThreads(LLVMOrcLLLazyJITBuilderRef Builder, + unsigned NumCompileThreads) +{ + unwrap(Builder)->setNumCompileThreads(NumCompileThreads); +} + +void +LLVMOrcLLLazyJITBuilderSetJITTargetMachineBuilder( + LLVMOrcLLLazyJITBuilderRef Builder, LLVMOrcJITTargetMachineBuilderRef JTMP) +{ + unwrap(Builder)->setJITTargetMachineBuilder(*unwrap(JTMP)); + /* Destroy the JTMP, similar to + LLVMOrcLLJITBuilderSetJITTargetMachineBuilder */ + LLVMOrcDisposeJITTargetMachineBuilder(JTMP); +} + +static Optional +PartitionFunction(GlobalValueSet Requested) +{ + std::vector GVsToAdd; + + for (auto *GV : Requested) { + if (isa(GV) && GV->hasName()) { + auto &F = cast(*GV); /* get LLVM function */ + const Module *M = F.getParent(); /* get LLVM module */ + auto GVName = GV->getName(); /* get the function name */ + const char *gvname = GVName.begin(); /* C function name */ + const char *wrapper; + uint32 prefix_len = strlen(AOT_FUNC_PREFIX); + + /* Convert "aot_func#n_wrapper" to "aot_func#n" */ + if (strstr(gvname, AOT_FUNC_PREFIX) + && (wrapper = strstr(gvname + prefix_len, "_wrapper"))) { + char buf[16] = { 0 }; + char func_name[64]; + int group_stride, i, j; + + bh_assert(wrapper - (gvname + prefix_len) > 0); + /* Get AOT function index */ + bh_memcpy_s(buf, (uint32)sizeof(buf), gvname + prefix_len, + (uint32)(wrapper - (gvname + prefix_len))); + i = atoi(buf); + + group_stride = WASM_ORC_JIT_BACKEND_THREAD_NUM; + + /* Compile some functions each time */ + for (j = 0; j < WASM_ORC_JIT_COMPILE_THREAD_NUM; j++) { + snprintf(func_name, sizeof(func_name), "%s%d", + AOT_FUNC_PREFIX, i + j * group_stride); + Function *F1 = M->getFunction(func_name); + if (F1) { + LOG_DEBUG("compile func %s", func_name); + GVsToAdd.push_back(cast(F1)); + } + } + } + } + } + + for (auto *GV : GVsToAdd) { + Requested.insert(GV); + } + + return Requested; +} + +LLVMErrorRef +LLVMOrcCreateLLLazyJIT(LLVMOrcLLLazyJITRef *Result, + LLVMOrcLLLazyJITBuilderRef Builder) +{ + assert(Result && "Result can not be null"); + + if (!Builder) + Builder = LLVMOrcCreateLLLazyJITBuilder(); + + auto J = unwrap(Builder)->create(); + LLVMOrcDisposeLLLazyJITBuilder(Builder); + + if (!J) { + Result = nullptr; + return 0; + } + + LLLazyJIT *lazy_jit = J->release(); + lazy_jit->setPartitionFunction(PartitionFunction); + + *Result = wrap(lazy_jit); + return LLVMErrorSuccess; +} + +LLVMErrorRef +LLVMOrcDisposeLLLazyJIT(LLVMOrcLLLazyJITRef J) +{ + delete unwrap(J); + return LLVMErrorSuccess; +} + +LLVMErrorRef +LLVMOrcLLLazyJITAddLLVMIRModule(LLVMOrcLLLazyJITRef J, LLVMOrcJITDylibRef JD, + LLVMOrcThreadSafeModuleRef TSM) +{ + std::unique_ptr TmpTSM(unwrap(TSM)); + return wrap(unwrap(J)->addLazyIRModule(*unwrap(JD), std::move(*TmpTSM))); +} + +LLVMErrorRef +LLVMOrcLLLazyJITLookup(LLVMOrcLLLazyJITRef J, LLVMOrcExecutorAddress *Result, + const char *Name) +{ + assert(Result && "Result can not be null"); + + auto Sym = unwrap(J)->lookup(Name); + if (!Sym) { + *Result = 0; + return wrap(Sym.takeError()); + } + +#if LLVM_VERSION_MAJOR < 15 + *Result = Sym->getAddress(); +#else + *Result = Sym->getValue(); +#endif + return LLVMErrorSuccess; +} + +LLVMOrcSymbolStringPoolEntryRef +LLVMOrcLLLazyJITMangleAndIntern(LLVMOrcLLLazyJITRef J, + const char *UnmangledName) +{ + return wrap(OrcV2CAPIHelper::moveFromSymbolStringPtr( + unwrap(J)->mangleAndIntern(UnmangledName))); +} + +LLVMOrcJITDylibRef +LLVMOrcLLLazyJITGetMainJITDylib(LLVMOrcLLLazyJITRef J) +{ + return wrap(&unwrap(J)->getMainJITDylib()); +} + +const char * +LLVMOrcLLLazyJITGetTripleString(LLVMOrcLLLazyJITRef J) +{ + return unwrap(J)->getTargetTriple().str().c_str(); +} + +LLVMOrcExecutionSessionRef +LLVMOrcLLLazyJITGetExecutionSession(LLVMOrcLLLazyJITRef J) +{ + return wrap(&unwrap(J)->getExecutionSession()); +} + +LLVMOrcIRTransformLayerRef +LLVMOrcLLLazyJITGetIRTransformLayer(LLVMOrcLLLazyJITRef J) +{ + return wrap(&unwrap(J)->getIRTransformLayer()); +} + +LLVMOrcObjectTransformLayerRef +LLVMOrcLLLazyJITGetObjTransformLayer(LLVMOrcLLLazyJITRef J) +{ + return wrap(&unwrap(J)->getObjTransformLayer()); +} diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_orc_extra.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_orc_extra.h new file mode 100644 index 00000000000..e152b877843 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/aot_orc_extra.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef _AOT_ORC_LAZINESS_H_ +#define _AOT_ORC_LAZINESS_H_ + +#include "llvm-c/Error.h" +#include "llvm-c/ExternC.h" +#include "llvm-c/LLJIT.h" +#include "llvm-c/Orc.h" +#include "llvm-c/Types.h" + +LLVM_C_EXTERN_C_BEGIN + +typedef struct LLVMOrcOpaqueLLLazyJITBuilder *LLVMOrcLLLazyJITBuilderRef; +typedef struct LLVMOrcOpaqueLLLazyJIT *LLVMOrcLLLazyJITRef; + +// Extra bindings for LLJIT +void +LLVMOrcLLJITBuilderSetNumCompileThreads(LLVMOrcLLJITBuilderRef Builder, + unsigned NumCompileThreads); + +// Extra bindings for LLLazyJIT +LLVMOrcLLLazyJITBuilderRef +LLVMOrcCreateLLLazyJITBuilder(void); + +void +LLVMOrcDisposeLLLazyJITBuilder(LLVMOrcLLLazyJITBuilderRef Builder); + +void +LLVMOrcLLLazyJITBuilderSetJITTargetMachineBuilder( + LLVMOrcLLLazyJITBuilderRef Builder, LLVMOrcJITTargetMachineBuilderRef JTMP); + +void +LLVMOrcLLLazyJITBuilderSetNumCompileThreads(LLVMOrcLLLazyJITBuilderRef Builder, + unsigned NumCompileThreads); + +LLVMErrorRef +LLVMOrcCreateLLLazyJIT(LLVMOrcLLLazyJITRef *Result, + LLVMOrcLLLazyJITBuilderRef Builder); + +LLVMErrorRef +LLVMOrcDisposeLLLazyJIT(LLVMOrcLLLazyJITRef J); + +LLVMErrorRef +LLVMOrcLLLazyJITAddLLVMIRModule(LLVMOrcLLLazyJITRef J, LLVMOrcJITDylibRef JD, + LLVMOrcThreadSafeModuleRef TSM); + +LLVMErrorRef +LLVMOrcLLLazyJITLookup(LLVMOrcLLLazyJITRef J, LLVMOrcExecutorAddress *Result, + const char *Name); + +LLVMOrcSymbolStringPoolEntryRef +LLVMOrcLLLazyJITMangleAndIntern(LLVMOrcLLLazyJITRef J, + const char *UnmangledName); + +LLVMOrcJITDylibRef +LLVMOrcLLLazyJITGetMainJITDylib(LLVMOrcLLLazyJITRef J); + +const char * +LLVMOrcLLLazyJITGetTripleString(LLVMOrcLLLazyJITRef J); + +LLVMOrcExecutionSessionRef +LLVMOrcLLLazyJITGetExecutionSession(LLVMOrcLLLazyJITRef J); + +LLVMOrcIRTransformLayerRef +LLVMOrcLLLazyJITGetIRTransformLayer(LLVMOrcLLLazyJITRef J); + +LLVMOrcObjectTransformLayerRef +LLVMOrcLLLazyJITGetObjTransformLayer(LLVMOrcLLLazyJITRef J); + +LLVM_C_EXTERN_C_END +#endif diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/debug/dwarf_extractor.cpp b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/debug/dwarf_extractor.cpp similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/debug/dwarf_extractor.cpp rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/debug/dwarf_extractor.cpp diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/debug/dwarf_extractor.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/debug/dwarf_extractor.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/debug/dwarf_extractor.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/debug/dwarf_extractor.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/iwasm_compl.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/iwasm_compl.cmake similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/iwasm_compl.cmake rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/iwasm_compl.cmake diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/simd/simd_access_lanes.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/simd/simd_access_lanes.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/simd/simd_access_lanes.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/simd/simd_access_lanes.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/simd/simd_access_lanes.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/simd/simd_access_lanes.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/simd/simd_access_lanes.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/simd/simd_access_lanes.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/simd/simd_bit_shifts.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/simd/simd_bit_shifts.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/simd/simd_bit_shifts.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/simd/simd_bit_shifts.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/simd/simd_bit_shifts.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/simd/simd_bit_shifts.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/simd/simd_bit_shifts.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/simd/simd_bit_shifts.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/simd/simd_bitmask_extracts.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/simd/simd_bitmask_extracts.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/simd/simd_bitmask_extracts.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/simd/simd_bitmask_extracts.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/simd/simd_bitmask_extracts.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/simd/simd_bitmask_extracts.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/simd/simd_bitmask_extracts.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/simd/simd_bitmask_extracts.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/simd/simd_bitwise_ops.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/simd/simd_bitwise_ops.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/simd/simd_bitwise_ops.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/simd/simd_bitwise_ops.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/simd/simd_bitwise_ops.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/simd/simd_bitwise_ops.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/simd/simd_bitwise_ops.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/simd/simd_bitwise_ops.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/simd/simd_bool_reductions.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/simd/simd_bool_reductions.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/simd/simd_bool_reductions.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/simd/simd_bool_reductions.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/simd/simd_bool_reductions.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/simd/simd_bool_reductions.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/simd/simd_bool_reductions.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/simd/simd_bool_reductions.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/simd/simd_common.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/simd/simd_common.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/simd/simd_common.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/simd/simd_common.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/simd/simd_common.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/simd/simd_common.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/simd/simd_common.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/simd/simd_common.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/simd/simd_comparisons.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/simd/simd_comparisons.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/simd/simd_comparisons.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/simd/simd_comparisons.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/simd/simd_comparisons.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/simd/simd_comparisons.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/simd/simd_comparisons.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/simd/simd_comparisons.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/simd/simd_construct_values.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/simd/simd_construct_values.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/simd/simd_construct_values.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/simd/simd_construct_values.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/simd/simd_construct_values.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/simd/simd_construct_values.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/simd/simd_construct_values.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/simd/simd_construct_values.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/simd/simd_conversions.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/simd/simd_conversions.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/simd/simd_conversions.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/simd/simd_conversions.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/simd/simd_conversions.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/simd/simd_conversions.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/simd/simd_conversions.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/simd/simd_conversions.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/simd/simd_floating_point.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/simd/simd_floating_point.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/simd/simd_floating_point.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/simd/simd_floating_point.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/simd/simd_floating_point.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/simd/simd_floating_point.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/simd/simd_floating_point.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/simd/simd_floating_point.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/simd/simd_int_arith.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/simd/simd_int_arith.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/simd/simd_int_arith.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/simd/simd_int_arith.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/simd/simd_int_arith.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/simd/simd_int_arith.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/simd/simd_int_arith.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/simd/simd_int_arith.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/simd/simd_load_store.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/simd/simd_load_store.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/simd/simd_load_store.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/simd/simd_load_store.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/simd/simd_load_store.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/simd/simd_load_store.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/simd/simd_load_store.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/simd/simd_load_store.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/simd/simd_sat_int_arith.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/simd/simd_sat_int_arith.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/simd/simd_sat_int_arith.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/simd/simd_sat_int_arith.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/simd/simd_sat_int_arith.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/simd/simd_sat_int_arith.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/compilation/simd/simd_sat_int_arith.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/compilation/simd/simd_sat_int_arith.h diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/doc/classic_interpreter.MD b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/doc/classic_interpreter.MD new file mode 100644 index 00000000000..a607758e264 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/doc/classic_interpreter.MD @@ -0,0 +1,5 @@ +# Classic interpreter + +## stack format + +![](./images/stack_format_ci.svg) \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/doc/images/export_function.excalidraw b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/doc/images/export_function.excalidraw new file mode 100644 index 00000000000..b983af05b18 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/doc/images/export_function.excalidraw @@ -0,0 +1,5695 @@ +{ + "type": "excalidraw", + "version": 2, + "source": "https://marketplace.visualstudio.com/items?itemName=pomdtr.excalidraw-editor", + "elements": [ + { + "type": "rectangle", + "version": 469, + "versionNonce": 587617691, + "isDeleted": false, + "id": "YQFdEhDm9LI_5UD2YjLU-", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 238.99996948242188, + "y": 207.16673278808577, + "strokeColor": "#000000", + "backgroundColor": "#ced4da", + "width": 221.3333740234375, + "height": 94.629648844401, + "seed": 1964509979, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679555887720, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 318, + "versionNonce": 929539477, + "isDeleted": false, + "id": "pDkkkqvgrizIP6AYdFbkj", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 239.66665649414062, + "y": 161.83335876464827, + "strokeColor": "#1864ab", + "backgroundColor": "transparent", + "width": 96, + "height": 19, + "seed": 278267925, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679555887720, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 3, + "text": "WASMModule", + "baseline": 15, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "WASMModule" + }, + { + "type": "rectangle", + "version": 592, + "versionNonce": 276752955, + "isDeleted": false, + "id": "awCpIZpFN-gQRBgh6iG1X", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 228.33334350585938, + "y": 191.50007629394514, + "strokeColor": "#1864ab", + "backgroundColor": "transparent", + "width": 247.11109754774304, + "height": 265.6667175292969, + "seed": 1908273083, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679555887720, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 411, + "versionNonce": 1793600245, + "isDeleted": false, + "id": "TOmX9MwwNOgbfjNJ8V8j7", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 239.4444953070747, + "y": 233.9815283881292, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 211, + "height": 56, + "seed": 86392181, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "2NQmRBF_NE2Myp3-jqLfT", + "type": "arrow" + } + ], + "updated": 1679555887720, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 2, + "text": " WASMTable *tables;\n WASMMemory *memories;\n WASMGlobal *globals;", + "baseline": 52, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": " WASMTable *tables;\n WASMMemory *memories;\n WASMGlobal *globals;" + }, + { + "type": "text", + "version": 390, + "versionNonce": 1283272731, + "isDeleted": false, + "id": "FPUGB-iP7ep91gfoTuV2d", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 289.3334045410156, + "y": 374.1667327880857, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 165, + "height": 19, + "seed": 504570933, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "OdDm5a5O_NIoZbF3u0c0H", + "type": "arrow" + } + ], + "updated": 1679555887720, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 2, + "text": "WASMExport *exports;", + "baseline": 15, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "WASMExport *exports;" + }, + { + "type": "rectangle", + "version": 371, + "versionNonce": 692171541, + "isDeleted": false, + "id": "iP-OL8X-L4CE8z9CTp9qG", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 243.66677856445312, + "y": 359.5001068115232, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 216, + "height": 42.6666259765625, + "seed": 1531454875, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679555887720, + "link": null, + "locked": false + }, + { + "type": "diamond", + "version": 336, + "versionNonce": 1261860027, + "isDeleted": false, + "id": "jkgMB1VHPK6x-xD6Wuey7", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 258.3335266113281, + "y": 370.16679382324196, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 15.33331298828125, + "height": 22.66668701171875, + "seed": 2028656021, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679555887720, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 286, + "versionNonce": 1775181787, + "isDeleted": false, + "id": "v4paccURicZAp-WeQNnlQ", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 585.7036675347218, + "y": 278.944342719184, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 156, + "height": 128.33334350585938, + "seed": 766182741, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679555887720, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 176, + "versionNonce": 907517781, + "isDeleted": false, + "id": "blxQLl_yf7DMD76qHC5rc", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 587.9629041883677, + "y": 256.3147176106771, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 97, + "height": 19, + "seed": 1409110677, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "OdDm5a5O_NIoZbF3u0c0H", + "type": "arrow" + } + ], + "updated": 1679555887720, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 2, + "text": "WASMExport", + "baseline": 15, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "WASMExport" + }, + { + "type": "text", + "version": 216, + "versionNonce": 271871099, + "isDeleted": false, + "id": "xQPYBI_XdfyZkh2-U_YQB", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 617.3703240288627, + "y": 289.2776862250434, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 88, + "height": 19, + "seed": 1776880725, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "YidAloK-3ikBBzvuu-S22", + "type": "arrow" + } + ], + "updated": 1679555887720, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 2, + "text": "char *name;", + "baseline": 15, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "char *name;" + }, + { + "type": "text", + "version": 241, + "versionNonce": 217246901, + "isDeleted": false, + "id": "lB_sRHE0gMYdFdpT2Dvja", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 614.7036370171439, + "y": 321.6110602484809, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 75, + "height": 19, + "seed": 1312575355, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679555887720, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 2, + "text": "uint8 kind;", + "baseline": 15, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "uint8 kind;" + }, + { + "type": "text", + "version": 230, + "versionNonce": 562504987, + "isDeleted": false, + "id": "SQI7khDAbJL0pLh0deiej", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 610.0369805230033, + "y": 354.944342719184, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 93, + "height": 19, + "seed": 2114894261, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "C_HvFqwDiW4wGe01QNKFg", + "type": "arrow" + } + ], + "updated": 1679555887720, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 2, + "text": "uint32 index;", + "baseline": 15, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "uint32 index;" + }, + { + "type": "rectangle", + "version": 188, + "versionNonce": 2042465813, + "isDeleted": false, + "id": "sqBZGoR4vKErEsSE7jSJk", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 601.0370110405812, + "y": 284.9443579779731, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 120.66668701171875, + "height": 29.666671752929688, + "seed": 1817827573, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "YidAloK-3ikBBzvuu-S22", + "type": "arrow" + } + ], + "updated": 1679555887720, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 255, + "versionNonce": 892979643, + "isDeleted": false, + "id": "xy3rvXCHxwYSjuQZAaa0Y", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 601.7036675347218, + "y": 320.6110602484809, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 118, + "height": 26.33331298828125, + "seed": 1394813013, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679555887720, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 190, + "versionNonce": 728564597, + "isDeleted": false, + "id": "noIblgsWe1zKM-bENF8Ev", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 599.0370110405812, + "y": 351.61102973090277, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 126, + "height": 29.666656494140625, + "seed": 410891355, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679555887720, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 174, + "versionNonce": 1447480533, + "isDeleted": false, + "id": "q8XZjMjkc5oaR7KNqOcGF", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 654.3703545464408, + "y": 385.7777167426215, + "strokeColor": "#000000", + "backgroundColor": "#ced4da", + "width": 20, + "height": 19, + "seed": 1931744507, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679555887720, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 2, + "text": "[0]", + "baseline": 15, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "[0]" + }, + { + "type": "rectangle", + "version": 177, + "versionNonce": 804837115, + "isDeleted": false, + "id": "cywWwhg521rh-6jpDBbTE", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 586.3703240288625, + "y": 407.94437323676215, + "strokeColor": "#000000", + "backgroundColor": "#ced4da", + "width": 158, + "height": 42, + "seed": 19921979, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "type": "text", + "id": "8dd-iKzlb9Z4V1eqnx9a-" + } + ], + "updated": 1679555887720, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 152, + "versionNonce": 165702197, + "isDeleted": false, + "id": "8dd-iKzlb9Z4V1eqnx9a-", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 655.3703240288627, + "y": 419.44437323676215, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 20, + "height": 19, + "seed": 1593993467, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679555887720, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 2, + "text": "[1]", + "baseline": 15, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "cywWwhg521rh-6jpDBbTE", + "originalText": "[1]" + }, + { + "type": "rectangle", + "version": 191, + "versionNonce": 1381646235, + "isDeleted": false, + "id": "SsP3zaE3LuSyRa2Ma4ffB", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 587.3703240288625, + "y": 450.94437323676215, + "strokeColor": "#000000", + "backgroundColor": "#ced4da", + "width": 158, + "height": 42, + "seed": 1216947029, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "type": "text", + "id": "Ux1Agae75_DS0veGHXMuH" + } + ], + "updated": 1679555887721, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 169, + "versionNonce": 1193237397, + "isDeleted": false, + "id": "Ux1Agae75_DS0veGHXMuH", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 654.3703240288627, + "y": 462.44437323676215, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 24, + "height": 19, + "seed": 982329467, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679555887721, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 2, + "text": "[...]", + "baseline": 15, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "SsP3zaE3LuSyRa2Ma4ffB", + "originalText": "[...]" + }, + { + "type": "text", + "version": 248, + "versionNonce": 1555249749, + "isDeleted": false, + "id": "o7FaW1SjzOKpt86xZNbly", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -71.58126068115234, + "y": 146.11661834716801, + "strokeColor": "#e67700", + "backgroundColor": "transparent", + "width": 171, + "height": 19, + "seed": 1768482683, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679555887721, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 3, + "text": "WASMModuleInstance", + "baseline": 15, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "WASMModuleInstance" + }, + { + "type": "rectangle", + "version": 131, + "versionNonce": 1297489444, + "isDeleted": false, + "id": "MC9rQuxIk7iVRtsas7ICs", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -73.99992370605469, + "y": 180.9666107177734, + "strokeColor": "#d9480f", + "backgroundColor": "transparent", + "width": 210.66668701171875, + "height": 314.33334350585943, + "seed": 1805099445, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679558426546, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 473, + "versionNonce": 1484728732, + "isDeleted": false, + "id": "6pGqkyRY8AHL4k5LTJ0Yl", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -51.000274658203125, + "y": 425.4667785644531, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 174.66668701171875, + "height": 31.666625976562507, + "seed": 957429083, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679558303924, + "link": null, + "locked": false + }, + { + "type": "diamond", + "version": 499, + "versionNonce": 1368837668, + "isDeleted": false, + "id": "cDohxEkx3HhhoX-zcCc9Q", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -45.666961669921875, + "y": 433.1334350585937, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 10.66668701171875, + "height": 17.666656494140625, + "seed": 63676885, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679558303924, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 208, + "versionNonce": 1386190364, + "isDeleted": false, + "id": "kOP_SYX2hDGyTbKOLrSY7", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -25.66693115234375, + "y": 429.9667785644531, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 115, + "height": 20, + "seed": 697815547, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "xGVX08X1n0JU0OA60_t9A", + "type": "arrow" + } + ], + "updated": 1679558303924, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "export_tables", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "export_tables" + }, + { + "type": "rectangle", + "version": 534, + "versionNonce": 1960518965, + "isDeleted": false, + "id": "FnISIa4MPRb3okZ9nUHSQ", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -58.66651916503906, + "y": 359.8333740234375, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 174.66668701171875, + "height": 31.666625976562507, + "seed": 1723426171, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679555887721, + "link": null, + "locked": false + }, + { + "type": "diamond", + "version": 562, + "versionNonce": 901559451, + "isDeleted": false, + "id": "KPco9Nm_8Olmg0Uq3NVQ1", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -53.33320617675781, + "y": 367.5000305175781, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 10.66668701171875, + "height": 17.666656494140625, + "seed": 135660469, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679555887721, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 260, + "versionNonce": 420132501, + "isDeleted": false, + "id": "8KE83CX20gDJQwJueCKwN", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -39.33323669433594, + "y": 365.66668701171875, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 131, + "height": 20, + "seed": 788856347, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "v2uiV8UbBxa6_yEOLAehf", + "type": "arrow" + } + ], + "updated": 1679555887721, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "export_memories", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "export_memories" + }, + { + "type": "rectangle", + "version": 477, + "versionNonce": 1527867707, + "isDeleted": false, + "id": "_CbJcjswexYEsNuWct5mC", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -51.99998474121094, + "y": 189.83334350585938, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 174.66668701171875, + "height": 31.666625976562507, + "seed": 1344002453, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679555887721, + "link": null, + "locked": false + }, + { + "type": "diamond", + "version": 505, + "versionNonce": 671161333, + "isDeleted": false, + "id": "hGw4Pp4LnIpkfSfU4PeRb", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -46.66667175292969, + "y": 197.5, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 10.66668701171875, + "height": 17.666656494140625, + "seed": 861402683, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679555887721, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 213, + "versionNonce": 690391515, + "isDeleted": false, + "id": "67MrbK1oKDTBrmUzIQlr1", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -26.666641235351562, + "y": 194.33334350585938, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 118, + "height": 20, + "seed": 1190518517, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679555887721, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "export_globals", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "export_globals" + }, + { + "type": "rectangle", + "version": 400, + "versionNonce": 1237570901, + "isDeleted": false, + "id": "eMcaE0yc0BCbsQ4MrLuGP", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -51.33323669433594, + "y": 271.8333740234375, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 174.66668701171875, + "height": 31.666625976562507, + "seed": 1337283029, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679555887721, + "link": null, + "locked": false + }, + { + "type": "diamond", + "version": 429, + "versionNonce": 84842107, + "isDeleted": false, + "id": "rW76UbdBzelN0CWuqQjTc", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -45.99992370605469, + "y": 279.5000305175781, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 10.66668701171875, + "height": 17.666656494140625, + "seed": 778117627, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "4eMPasZehGc58H7vVusCf", + "type": "arrow" + } + ], + "updated": 1679555887721, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 136, + "versionNonce": 162030261, + "isDeleted": false, + "id": "NfPonNQyhbRCCPh50Ed7I", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -25.999893188476562, + "y": 276.3333740234375, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 136, + "height": 20, + "seed": 1026969397, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "4eMPasZehGc58H7vVusCf", + "type": "arrow" + } + ], + "updated": 1679555887721, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "export_functions", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "export_functions" + }, + { + "type": "text", + "version": 121, + "versionNonce": 227282715, + "isDeleted": false, + "id": "ILDnCNxtBv4qdrhMb3QoZ", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -365.33335876464844, + "y": 193.1666259765625, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 193, + "height": 19, + "seed": 282525979, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679555887721, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 2, + "text": "WASMExportFuncInstance", + "baseline": 15, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "WASMExportFuncInstance" + }, + { + "type": "rectangle", + "version": 201, + "versionNonce": 1817461781, + "isDeleted": false, + "id": "2agHBzF-91Fb2ws0hYObd", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -354.33335876464844, + "y": 223.83334350585938, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 177.33331298828122, + "height": 121.00006103515625, + "seed": 1290367509, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "4eMPasZehGc58H7vVusCf", + "type": "arrow" + } + ], + "updated": 1679555887721, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 176, + "versionNonce": 1961256348, + "isDeleted": false, + "id": "aZL7IU5LEszDJmyyWcmtp", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -340.6666717529297, + "y": 239.83328247070312, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 117, + "height": 31, + "seed": 1714300347, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "type": "text", + "id": "P3_9LebxO4r1Nud8xISGk" + }, + { + "id": "YidAloK-3ikBBzvuu-S22", + "type": "arrow" + } + ], + "updated": 1679558297714, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 194, + "versionNonce": 2136035876, + "isDeleted": false, + "id": "P3_9LebxO4r1Nud8xISGk", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -334.6666717529297, + "y": 244.83328247070312, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 105, + "height": 21, + "seed": 2004641653, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679558297727, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "char* name ", + "baseline": 14, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "aZL7IU5LEszDJmyyWcmtp", + "originalText": "char* name " + }, + { + "type": "diamond", + "version": 159, + "versionNonce": 1002521691, + "isDeleted": false, + "id": "qdga26-o2AGoXkwH2yP4N", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -323.00001525878906, + "y": 284.1666259765625, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 14.666656494140625, + "height": 17.666656494140625, + "seed": 444053083, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679555887721, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 216, + "versionNonce": 1328022229, + "isDeleted": false, + "id": "2onXRIpW3Znosk6O46QtY", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -338.33335876464844, + "y": 276.49993896484375, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 128, + "height": 38, + "seed": 852078805, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "type": "text", + "id": "Zrwh0TsrNxBSNhpJZIqbu" + } + ], + "updated": 1679555887721, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 183, + "versionNonce": 1455378972, + "isDeleted": false, + "id": "Zrwh0TsrNxBSNhpJZIqbu", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -305.83335876464844, + "y": 285.49993896484375, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 63, + "height": 21, + "seed": 2089169659, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679558297728, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "function", + "baseline": 14, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "2onXRIpW3Znosk6O46QtY", + "originalText": "function" + }, + { + "type": "arrow", + "version": 505, + "versionNonce": 2099961909, + "isDeleted": false, + "id": "nG4vs8WttuFFZPXDKIdNr", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -320.33335876464844, + "y": 293.49993896484375, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 111.00001525878906, + "height": 184.2470495648475, + "seed": 476499509, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1679555887721, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": { + "elementId": "7JcYtZ-KQ0WF1SDFDwvcV", + "gap": 1.2531640581994319, + "focus": -0.8059388021902064 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -111.00001525878906, + 33.166717529296875 + ], + [ + -35.26115412319115, + 184.2470495648475 + ] + ] + }, + { + "type": "text", + "version": 531, + "versionNonce": 363532693, + "isDeleted": false, + "id": "7MNv-pmgV4-8yJ5lIFY1U", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 496.5186225043402, + "y": 71.31480577256946, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 235, + "height": 149, + "seed": 2074251419, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "YidAloK-3ikBBzvuu-S22", + "type": "arrow" + }, + { + "id": "2NQmRBF_NE2Myp3-jqLfT", + "type": "arrow" + } + ], + "updated": 1679555887721, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 2, + "text": "name: shown to external\nindex: refer to item idx for export \n in current kind\nkind: total 4 export kinds:\n- function\n- globals\n- memory\n- table", + "baseline": 145, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "name: shown to external\nindex: refer to item idx for export \n in current kind\nkind: total 4 export kinds:\n- function\n- globals\n- memory\n- table" + }, + { + "type": "rectangle", + "version": 81, + "versionNonce": 997735995, + "isDeleted": false, + "id": "orpW0tFerpELyreVDruzO", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -353.3333740234375, + "y": 343.99998474121094, + "strokeColor": "#000000", + "backgroundColor": "#fab005", + "width": 180, + "height": 32.333343505859375, + "seed": 940489147, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "type": "text", + "id": "KlcGzdua5BpLa_-0RGeFO" + } + ], + "updated": 1679555887721, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 53, + "versionNonce": 1965780388, + "isDeleted": false, + "id": "KlcGzdua5BpLa_-0RGeFO", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -274.3333740234375, + "y": 350.1666564941406, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 22, + "height": 21, + "seed": 1399452699, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679558297729, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "[1]", + "baseline": 14, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "orpW0tFerpELyreVDruzO", + "originalText": "[1]" + }, + { + "type": "text", + "version": 71, + "versionNonce": 1609219803, + "isDeleted": false, + "id": "da0XYl9R6gkV-BQ4X1JdF", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -278.166748046875, + "y": 324.33338928222656, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 29, + "height": 20, + "seed": 848835675, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679555887721, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "[0]", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "[0]" + }, + { + "type": "rectangle", + "version": 109, + "versionNonce": 528755579, + "isDeleted": false, + "id": "oVhH9XqC6rs2uaPMH4x2B", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -353.0001220703125, + "y": 377.50006103515625, + "strokeColor": "#000000", + "backgroundColor": "#fab005", + "width": 180, + "height": 32.333343505859375, + "seed": 1099143605, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "type": "text", + "id": "wu6BDVXXPWLo-Z-l7TYGW" + }, + { + "id": "Eda9W8eaZom6PATRAm5EX", + "type": "arrow" + } + ], + "updated": 1679555887721, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 83, + "versionNonce": 1472638620, + "isDeleted": false, + "id": "wu6BDVXXPWLo-Z-l7TYGW", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -278.5001220703125, + "y": 383.66673278808594, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 31, + "height": 21, + "seed": 1029949467, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679558297730, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "[...]", + "baseline": 14, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "oVhH9XqC6rs2uaPMH4x2B", + "originalText": "[...]" + }, + { + "type": "rectangle", + "version": 134, + "versionNonce": 1882593572, + "isDeleted": false, + "id": "t8xOhAVyJcx51xJsmWC6j", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -352.33331298828125, + "y": 408.5001220703125, + "strokeColor": "#000000", + "backgroundColor": "#fab005", + "width": 180, + "height": 31, + "seed": 883564757, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "type": "text", + "id": "F09zazRYIO_G3oM7DmBbr" + }, + { + "id": "Eda9W8eaZom6PATRAm5EX", + "type": "arrow" + } + ], + "updated": 1679558297730, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 111, + "versionNonce": 1756265244, + "isDeleted": false, + "id": "F09zazRYIO_G3oM7DmBbr", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -274.83331298828125, + "y": 418.5001220703125, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 25, + "height": 21, + "seed": 1529135867, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679558297738, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "[n]", + "baseline": 14, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "t8xOhAVyJcx51xJsmWC6j", + "originalText": "[n]" + }, + { + "type": "line", + "version": 284, + "versionNonce": 350603451, + "isDeleted": false, + "id": "XphCtXmoQONIDWT15UPmf", + "fillStyle": "hachure", + "strokeWidth": 4, + "strokeStyle": "dotted", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 169.00015258789057, + "y": 21.389623853895444, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 1.66656494140625, + "height": 838.3330154418943, + "seed": 395797243, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679555887721, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": null, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": null, + "points": [ + [ + 0, + 0 + ], + [ + 1.66656494140625, + 838.3330154418943 + ] + ] + }, + { + "type": "arrow", + "version": 156, + "versionNonce": 1808036981, + "isDeleted": false, + "id": "4eMPasZehGc58H7vVusCf", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -40.66667175292969, + "y": 278.5517677558588, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 133.01236173861167, + "height": 54.587889349881976, + "seed": 526956341, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679555887721, + "link": null, + "locked": false, + "startBinding": { + "elementId": "NfPonNQyhbRCCPh50Ed7I", + "focus": -0.6897037086038879, + "gap": 14.666778564453125 + }, + "endBinding": { + "elementId": "2agHBzF-91Fb2ws0hYObd", + "focus": -1.0127197558064842, + "gap": 3.3210122848258408 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -133.01236173861167, + -54.587889349881976 + ] + ] + }, + { + "type": "rectangle", + "version": 227, + "versionNonce": 2017655131, + "isDeleted": false, + "id": "7JcYtZ-KQ0WF1SDFDwvcV", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -362, + "y": 478.3334655761719, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 223.3334655761719, + "height": 33.00015258789055, + "seed": 857261429, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "nG4vs8WttuFFZPXDKIdNr", + "type": "arrow" + } + ], + "updated": 1679555887721, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 351, + "versionNonce": 1552424405, + "isDeleted": false, + "id": "QLOWRmBSKHUu_NrX66JPt", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -355.3333740234375, + "y": 486.00006103515625, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 208, + "height": 20, + "seed": 513338651, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "nG4vs8WttuFFZPXDKIdNr", + "type": "arrow" + }, + { + "id": "Vhva2LNBhtrohj4Y3bGV9", + "type": "arrow" + } + ], + "updated": 1679555887721, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "(refer to function diagam)", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "(refer to function diagam)" + }, + { + "type": "text", + "version": 94, + "versionNonce": 636556795, + "isDeleted": false, + "id": "R3bNKi3-D-UlbcoafRHR5", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -40.6666259765625, + "y": 316.9998779296875, + "strokeColor": "#000000", + "backgroundColor": "#fab005", + "width": 154, + "height": 20, + "seed": 1038062939, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "Eda9W8eaZom6PATRAm5EX", + "type": "arrow" + } + ], + "updated": 1679555887721, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "export_func_count", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "export_func_count" + }, + { + "type": "arrow", + "version": 162, + "versionNonce": 1037015861, + "isDeleted": false, + "id": "Eda9W8eaZom6PATRAm5EX", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -51.354154838890395, + "y": 333.9999084472656, + "strokeColor": "#000000", + "backgroundColor": "#fab005", + "width": 192.10502044691845, + "height": 89.91317165306509, + "seed": 518031893, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1679555887721, + "link": null, + "locked": false, + "startBinding": { + "elementId": "mZobbVjOOfzbAK_1alOcK", + "focus": 0.6974503894293331, + "gap": 1 + }, + "endBinding": { + "elementId": "oVhH9XqC6rs2uaPMH4x2B", + "focus": 0.8116332021918504, + "gap": 14.079675559315092 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -81.97918866696898, + 54.666717529296875 + ], + [ + -192.10502044691845, + 89.91317165306509 + ] + ] + }, + { + "type": "rectangle", + "version": 71, + "versionNonce": 2013293717, + "isDeleted": false, + "id": "mZobbVjOOfzbAK_1alOcK", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -50.66668701171875, + "y": 311.333251953125, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 172.666748046875, + "height": 31.66668701171875, + "seed": 1172380085, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "Eda9W8eaZom6PATRAm5EX", + "type": "arrow" + } + ], + "updated": 1679555887721, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 417, + "versionNonce": 1255150069, + "isDeleted": false, + "id": "YyGWHpfM0OE4uzGAFwZ12", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 484.1481289333766, + "y": 65.53704833984384, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 287.70376925998266, + "height": 162.29637824164502, + "seed": 274906523, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "YidAloK-3ikBBzvuu-S22", + "type": "arrow" + } + ], + "updated": 1679555887721, + "link": null, + "locked": false + }, + { + "type": "arrow", + "version": 1048, + "versionNonce": 392819675, + "isDeleted": false, + "id": "YidAloK-3ikBBzvuu-S22", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 743.579402430669, + "y": 225.04108862166348, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 21.48420572561895, + "height": 53.29342358325337, + "seed": 1380550619, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1679555887721, + "link": null, + "locked": false, + "startBinding": { + "elementId": "7MNv-pmgV4-8yJ5lIFY1U", + "focus": -0.6782971803849929, + "gap": 12.953770184814061 + }, + "endBinding": { + "elementId": "sqBZGoR4vKErEsSE7jSJk", + "focus": 0.7448990456524555, + "gap": 10.515841746169144 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 10.124343093419043, + 26.347898601643806 + ], + [ + -11.359862632199906, + 53.29342358325337 + ] + ] + }, + { + "type": "text", + "version": 264, + "versionNonce": 1665403733, + "isDeleted": false, + "id": "sRzZXOvjblsPsAM89sUXa", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -705.3333892822266, + "y": 113.58320617675781, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 192, + "height": 19, + "seed": 700308213, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679555887721, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 2, + "text": "WASMExportGlobInstance", + "baseline": 15, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "WASMExportGlobInstance" + }, + { + "type": "rectangle", + "version": 348, + "versionNonce": 1800716411, + "isDeleted": false, + "id": "xWPtNuyAqazMMUyouKnhf", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -694.3333892822266, + "y": 144.2499237060547, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 177.33331298828122, + "height": 121.00006103515625, + "seed": 1037646555, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "RxhU0Qr-hmqzklRZdxsvn", + "type": "arrow" + } + ], + "updated": 1679555887721, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 323, + "versionNonce": 467621028, + "isDeleted": false, + "id": "7uYVutqCDMjhS1LtgrSpl", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -680.6667022705078, + "y": 160.24986267089844, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 117, + "height": 31, + "seed": 328250453, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "type": "text", + "id": "PlRFeDiD1tywOAk_rJgHg" + } + ], + "updated": 1679558297741, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 337, + "versionNonce": 334018460, + "isDeleted": false, + "id": "PlRFeDiD1tywOAk_rJgHg", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -674.6667022705078, + "y": 165.24986267089844, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 105, + "height": 21, + "seed": 843261819, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679558297749, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "char* name ", + "baseline": 14, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "7uYVutqCDMjhS1LtgrSpl", + "originalText": "char* name " + }, + { + "type": "diamond", + "version": 301, + "versionNonce": 2143222293, + "isDeleted": false, + "id": "01IysLeEkWSJyxI9NbVb8", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -663.0000457763672, + "y": 204.5832061767578, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 14.666656494140625, + "height": 17.666656494140625, + "seed": 1686200757, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679555887721, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 360, + "versionNonce": 458563003, + "isDeleted": false, + "id": "lWjh1xjt4eB1XKwJJx59D", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -678.3333892822266, + "y": 196.91651916503906, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 128, + "height": 38, + "seed": 671514651, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "type": "text", + "id": "VQ0ymOLfMpjFiupR01ZFb" + } + ], + "updated": 1679555887721, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 327, + "versionNonce": 97853476, + "isDeleted": false, + "id": "VQ0ymOLfMpjFiupR01ZFb", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -637.3333892822266, + "y": 205.91651916503906, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 46, + "height": 21, + "seed": 565535509, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679558297750, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "global", + "baseline": 14, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "lWjh1xjt4eB1XKwJJx59D", + "originalText": "global" + }, + { + "type": "arrow", + "version": 624, + "versionNonce": 2147462747, + "isDeleted": false, + "id": "E_RGDiJbGUf1aNH6jDnvz", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -660.3333892822266, + "y": 213.91651916503906, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 111.00001525878906, + "height": 176.67764729852638, + "seed": 152421563, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1679555887722, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": { + "elementId": "KWKN5CpCB6zVtYZd6txj9", + "focus": -0.8240578974308156, + "gap": 7.457318223231596 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -111.00001525878906, + 33.166717529296875 + ], + [ + -17.790676987880033, + 176.67764729852638 + ] + ] + }, + { + "type": "rectangle", + "version": 225, + "versionNonce": 1372149301, + "isDeleted": false, + "id": "uLMWTXI90CGAIKI4zHJML", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -693.3334045410156, + "y": 264.41656494140625, + "strokeColor": "#000000", + "backgroundColor": "#fab005", + "width": 180, + "height": 32.333343505859375, + "seed": 1208836565, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "type": "text", + "id": "AGXBiW0dSLHn3nGEzduCY" + } + ], + "updated": 1679555887722, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 196, + "versionNonce": 1168598044, + "isDeleted": false, + "id": "AGXBiW0dSLHn3nGEzduCY", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -614.3334045410156, + "y": 270.58323669433594, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 22, + "height": 21, + "seed": 324145659, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679558297750, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "[1]", + "baseline": 14, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "uLMWTXI90CGAIKI4zHJML", + "originalText": "[1]" + }, + { + "type": "text", + "version": 213, + "versionNonce": 2064304021, + "isDeleted": false, + "id": "QvT_bIR-th1HBXIOu8j7Y", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -618.1667785644531, + "y": 244.74996948242188, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 29, + "height": 20, + "seed": 269246261, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679555887722, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "[0]", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "[0]" + }, + { + "type": "rectangle", + "version": 253, + "versionNonce": 630646843, + "isDeleted": false, + "id": "zom5ZNn_gBWzVI1PMMYQo", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -693.0001525878906, + "y": 297.91664123535156, + "strokeColor": "#000000", + "backgroundColor": "#fab005", + "width": 180, + "height": 32.333343505859375, + "seed": 215227035, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "type": "text", + "id": "U2e2lWVjWzkRt9x6FkfeD" + } + ], + "updated": 1679555887722, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 226, + "versionNonce": 1443199908, + "isDeleted": false, + "id": "U2e2lWVjWzkRt9x6FkfeD", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -618.5001525878906, + "y": 304.08331298828125, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 31, + "height": 21, + "seed": 1845801109, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679558297751, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "[...]", + "baseline": 14, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "zom5ZNn_gBWzVI1PMMYQo", + "originalText": "[...]" + }, + { + "type": "rectangle", + "version": 278, + "versionNonce": 333217948, + "isDeleted": false, + "id": "IbfRch-fWorg9yld9Wih5", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -692.3333435058594, + "y": 328.9167022705078, + "strokeColor": "#000000", + "backgroundColor": "#fab005", + "width": 180, + "height": 31, + "seed": 1716260667, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "type": "text", + "id": "So5vnnPiQUj6m6ZH6HSMP" + } + ], + "updated": 1679558297752, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 254, + "versionNonce": 111044388, + "isDeleted": false, + "id": "So5vnnPiQUj6m6ZH6HSMP", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -614.8333435058594, + "y": 338.9167022705078, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 25, + "height": 21, + "seed": 2141967861, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679558297758, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "[n]", + "baseline": 14, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "IbfRch-fWorg9yld9Wih5", + "originalText": "[n]" + }, + { + "type": "rectangle", + "version": 257, + "versionNonce": 494949755, + "isDeleted": false, + "id": "KWKN5CpCB6zVtYZd6txj9", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -670.666748046875, + "y": 392.7500457763672, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 196.00015258789062, + "height": 39.33346557617187, + "seed": 35418075, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "E_RGDiJbGUf1aNH6jDnvz", + "type": "arrow" + } + ], + "updated": 1679555887722, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 415, + "versionNonce": 964039605, + "isDeleted": false, + "id": "uEz53YqVhDB8JRuE5hMcU", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -659.3334655761719, + "y": 402.41664123535156, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 164, + "height": 20, + "seed": 268914517, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679555887722, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "WASMGlobalInstance", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "WASMGlobalInstance" + }, + { + "type": "text", + "version": 236, + "versionNonce": 2005417979, + "isDeleted": false, + "id": "FiGf5f4dzHNrO5L3NMiwT", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -604.5001068115234, + "y": 504.4166564941406, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 193, + "height": 19, + "seed": 1644818613, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "v2uiV8UbBxa6_yEOLAehf", + "type": "arrow" + } + ], + "updated": 1679555887722, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 2, + "text": "WASMExportMemInstance", + "baseline": 15, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "WASMExportMemInstance" + }, + { + "type": "rectangle", + "version": 316, + "versionNonce": 1410863413, + "isDeleted": false, + "id": "tgz_9er4fEh_TbaYDZF6u", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -593.5001068115234, + "y": 535.0833740234375, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 177.33331298828122, + "height": 121.00006103515625, + "seed": 273834267, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679555887722, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 295, + "versionNonce": 104467740, + "isDeleted": false, + "id": "fZ94UaMm9ypc37Hwvn9SX", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -579.8334197998047, + "y": 551.0833129882812, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 117, + "height": 31, + "seed": 492048917, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "type": "text", + "id": "QBs13zYnt2LZX4M9cdFuH" + } + ], + "updated": 1679558297759, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 308, + "versionNonce": 470672036, + "isDeleted": false, + "id": "QBs13zYnt2LZX4M9cdFuH", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -573.8334197998047, + "y": 556.0833129882812, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 105, + "height": 21, + "seed": 524125627, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679558297764, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "char* name ", + "baseline": 14, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "fZ94UaMm9ypc37Hwvn9SX", + "originalText": "char* name " + }, + { + "type": "diamond", + "version": 271, + "versionNonce": 424590651, + "isDeleted": false, + "id": "nqJwiZ18KG3vCMfANM8aQ", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -562.1667633056641, + "y": 595.4166564941406, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 14.666656494140625, + "height": 17.666656494140625, + "seed": 563283829, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679555887722, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 332, + "versionNonce": 1978861557, + "isDeleted": false, + "id": "HEJvi8QjWRiMWcoZPLHIl", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -577.5001068115234, + "y": 587.7499694824219, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 128, + "height": 38, + "seed": 983242331, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "type": "text", + "id": "HU6nOicEloKkqYD55hBWR" + } + ], + "updated": 1679555887722, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 304, + "versionNonce": 1580337564, + "isDeleted": false, + "id": "HU6nOicEloKkqYD55hBWR", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -540.5001068115234, + "y": 596.7499694824219, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 54, + "height": 21, + "seed": 554455253, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679558297765, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "memory", + "baseline": 14, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "HEJvi8QjWRiMWcoZPLHIl", + "originalText": "memory" + }, + { + "type": "arrow", + "version": 546, + "versionNonce": 1519927637, + "isDeleted": false, + "id": "O2ixOO7WSexT4tbgcUDGA", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -559.5001068115234, + "y": 604.7499694824219, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 111.00001525878906, + "height": 176.67764729852638, + "seed": 20812539, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1679555887722, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": { + "elementId": "Sn4zW4Qj5F8AgPuajBnRy", + "focus": -0.8240578974308156, + "gap": 7.457318223231596 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -111.00001525878906, + 33.166717529296875 + ], + [ + -17.790676987880033, + 176.67764729852638 + ] + ] + }, + { + "type": "text", + "version": 371, + "versionNonce": 1795615355, + "isDeleted": false, + "id": "XjbCYdp81z8HsAXal748C", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -794.1667785644531, + "y": 589.7500152587891, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 190, + "height": 20, + "seed": 1767206453, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679555887722, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "(WASMMemoryInstance*)", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "(WASMMemoryInstance*)" + }, + { + "type": "rectangle", + "version": 197, + "versionNonce": 1561284277, + "isDeleted": false, + "id": "8-N4VCgO26s4M3_joLoAg", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -592.5001220703125, + "y": 655.2500152587891, + "strokeColor": "#000000", + "backgroundColor": "#fab005", + "width": 180, + "height": 32.333343505859375, + "seed": 329743259, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "type": "text", + "id": "_zHc4H95qdMAwSfBAe4ji" + } + ], + "updated": 1679555887722, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 167, + "versionNonce": 1560407588, + "isDeleted": false, + "id": "_zHc4H95qdMAwSfBAe4ji", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -513.5001220703125, + "y": 661.4166870117188, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 22, + "height": 21, + "seed": 2035539861, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679558297766, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "[1]", + "baseline": 14, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "8-N4VCgO26s4M3_joLoAg", + "originalText": "[1]" + }, + { + "type": "text", + "version": 183, + "versionNonce": 201175061, + "isDeleted": false, + "id": "8MK4DV6gTxwniJIipRt0r", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -517.33349609375, + "y": 635.5834197998047, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 29, + "height": 20, + "seed": 1577799739, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679555887722, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "[0]", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "[0]" + }, + { + "type": "rectangle", + "version": 225, + "versionNonce": 313275, + "isDeleted": false, + "id": "tIAX2kAFoZpVqZ5qUAx0Z", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -592.1668701171875, + "y": 688.7500915527344, + "strokeColor": "#000000", + "backgroundColor": "#fab005", + "width": 180, + "height": 32.333343505859375, + "seed": 1463624949, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "type": "text", + "id": "2puZDaevwGxRcBgZ-ptc6" + } + ], + "updated": 1679555887722, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 197, + "versionNonce": 1593210396, + "isDeleted": false, + "id": "2puZDaevwGxRcBgZ-ptc6", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -517.6668701171875, + "y": 694.9167633056641, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 31, + "height": 21, + "seed": 575377627, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679558297767, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "[...]", + "baseline": 14, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "tIAX2kAFoZpVqZ5qUAx0Z", + "originalText": "[...]" + }, + { + "type": "rectangle", + "version": 250, + "versionNonce": 174623140, + "isDeleted": false, + "id": "N0OFLsAea9yT6OuliaHBO", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -591.5000610351562, + "y": 719.7501525878906, + "strokeColor": "#000000", + "backgroundColor": "#fab005", + "width": 180, + "height": 31, + "seed": 647413333, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "type": "text", + "id": "q7ppugt7g7qcpJ5yt5OdE" + } + ], + "updated": 1679558297767, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 225, + "versionNonce": 360272540, + "isDeleted": false, + "id": "q7ppugt7g7qcpJ5yt5OdE", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -514.0000610351562, + "y": 729.7501525878906, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 25, + "height": 21, + "seed": 1106951547, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679558297771, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "[n]", + "baseline": 14, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "N0OFLsAea9yT6OuliaHBO", + "originalText": "[n]" + }, + { + "type": "rectangle", + "version": 228, + "versionNonce": 647779579, + "isDeleted": false, + "id": "Sn4zW4Qj5F8AgPuajBnRy", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -569.8334655761719, + "y": 783.58349609375, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 196.00015258789062, + "height": 39.33346557617187, + "seed": 2117479349, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "O2ixOO7WSexT4tbgcUDGA", + "type": "arrow" + } + ], + "updated": 1679555887722, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 386, + "versionNonce": 1606143029, + "isDeleted": false, + "id": "ADaMm1yoqbZuEu8DJV90L", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -558.5001831054688, + "y": 793.2500915527344, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 170, + "height": 20, + "seed": 1213945371, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679555887722, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "WASMMemoryInstance", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "WASMMemoryInstance" + }, + { + "type": "arrow", + "version": 134, + "versionNonce": 1991153820, + "isDeleted": false, + "id": "RxhU0Qr-hmqzklRZdxsvn", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -42.66673278808594, + "y": 209.66668701171875, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 470.2476914752049, + "height": 74.33332824707031, + "seed": 1569902293, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1679558440686, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": { + "elementId": "xWPtNuyAqazMMUyouKnhf", + "focus": -0.7987290948340221, + "gap": 4.085652030654501 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -274, + -74.33332824707031 + ], + [ + -470.2476914752049, + -62.82886586813058 + ] + ] + }, + { + "type": "arrow", + "version": 214, + "versionNonce": 1329495445, + "isDeleted": false, + "id": "v2uiV8UbBxa6_yEOLAehf", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -54.615555578359704, + "y": 386.91916605443436, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 362.7179252566011, + "height": 185.08100179224533, + "seed": 1266609179, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1679555887722, + "link": null, + "locked": false, + "startBinding": { + "elementId": "8KE83CX20gDJQwJueCKwN", + "focus": 1.000586020261827, + "gap": 15.33355712890625 + }, + "endBinding": { + "elementId": "FiGf5f4dzHNrO5L3NMiwT", + "focus": 0.2798025099622999, + "gap": 11.916763305664062 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -132.71792525660123, + 185.08100179224533 + ], + [ + -362.7179252566011, + 148.41425374537033 + ] + ] + }, + { + "type": "text", + "version": 48, + "versionNonce": 304349941, + "isDeleted": false, + "id": "VoO6IQkaaomgHGzvmdk9L", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -107.00004577636719, + "y": 551.3334197998047, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 184, + "height": 19, + "seed": 2114679797, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679555887722, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 2, + "text": "WASMExportTabInstance", + "baseline": 15, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "WASMExportTabInstance" + }, + { + "type": "rectangle", + "version": 353, + "versionNonce": 340366043, + "isDeleted": false, + "id": "cfV2B-j5UbmISEWVZNm_5", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -108.33344268798828, + "y": 571.0000915527344, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 177.33331298828122, + "height": 121.00006103515625, + "seed": 2095295067, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679555887722, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 335, + "versionNonce": 393196836, + "isDeleted": false, + "id": "DJ8H7VUIn868NKonqg5gA", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -94.66675567626953, + "y": 587.0000305175781, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 117, + "height": 31, + "seed": 1950809301, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "type": "text", + "id": "kVEW0vY1bUiCqI5IpX5ML" + }, + { + "id": "xGVX08X1n0JU0OA60_t9A", + "type": "arrow" + } + ], + "updated": 1679558297772, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 346, + "versionNonce": 543989532, + "isDeleted": false, + "id": "kVEW0vY1bUiCqI5IpX5ML", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -88.66675567626953, + "y": 592.0000305175781, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 105, + "height": 21, + "seed": 357803771, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679558297776, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "char* name ", + "baseline": 14, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "DJ8H7VUIn868NKonqg5gA", + "originalText": "char* name " + }, + { + "type": "diamond", + "version": 308, + "versionNonce": 930974133, + "isDeleted": false, + "id": "gUolYbJIMeIJ_CDZqZFxE", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -77.0000991821289, + "y": 631.3333740234375, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 14.666656494140625, + "height": 17.666656494140625, + "seed": 1482332725, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679555887722, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 371, + "versionNonce": 809555995, + "isDeleted": false, + "id": "KIe-ngH8dNcYj_TNLGGa1", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -92.33344268798828, + "y": 623.6666870117188, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 128, + "height": 38, + "seed": 1675300763, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "type": "text", + "id": "NtF7gKcUrgH2P2tIg7Y1I" + } + ], + "updated": 1679555887722, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 343, + "versionNonce": 1636135076, + "isDeleted": false, + "id": "NtF7gKcUrgH2P2tIg7Y1I", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -49.83344268798828, + "y": 632.6666870117188, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 43, + "height": 21, + "seed": 651398037, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679558297777, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "table", + "baseline": 14, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "KIe-ngH8dNcYj_TNLGGa1", + "originalText": "table" + }, + { + "type": "rectangle", + "version": 236, + "versionNonce": 1212488891, + "isDeleted": false, + "id": "1vaZwH7ZrMW37Kus4v6s8", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -107.33345794677734, + "y": 691.1667327880859, + "strokeColor": "#000000", + "backgroundColor": "#fab005", + "width": 180, + "height": 32.333343505859375, + "seed": 179070011, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "type": "text", + "id": "EcHCtg-lwToZUzRwQtRqU" + } + ], + "updated": 1679555887722, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 205, + "versionNonce": 2017614748, + "isDeleted": false, + "id": "EcHCtg-lwToZUzRwQtRqU", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -28.333457946777344, + "y": 697.3334045410156, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 22, + "height": 21, + "seed": 266817781, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679558297777, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "[1]", + "baseline": 14, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "1vaZwH7ZrMW37Kus4v6s8", + "originalText": "[1]" + }, + { + "type": "text", + "version": 220, + "versionNonce": 748146011, + "isDeleted": false, + "id": "xnv1ofRPmnyf7Y75joBRd", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -32.166831970214844, + "y": 671.5001373291016, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 29, + "height": 20, + "seed": 1101669595, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679555887722, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "[0]", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "[0]" + }, + { + "type": "rectangle", + "version": 264, + "versionNonce": 1671072213, + "isDeleted": false, + "id": "WhKSAa-6xEaKbFn82X5ru", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -107.00020599365234, + "y": 724.6668090820312, + "strokeColor": "#000000", + "backgroundColor": "#fab005", + "width": 180, + "height": 32.333343505859375, + "seed": 555444821, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "type": "text", + "id": "-gxwjWzmqS5WDjuFaNKFD" + } + ], + "updated": 1679555887722, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 235, + "versionNonce": 1750580260, + "isDeleted": false, + "id": "-gxwjWzmqS5WDjuFaNKFD", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -32.500205993652344, + "y": 730.8334808349609, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 31, + "height": 21, + "seed": 543609211, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679558297778, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "[...]", + "baseline": 14, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "WhKSAa-6xEaKbFn82X5ru", + "originalText": "[...]" + }, + { + "type": "rectangle", + "version": 289, + "versionNonce": 925665308, + "isDeleted": false, + "id": "10EyNsT35ULiP_xM9qv8Y", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -106.3333969116211, + "y": 755.6668701171875, + "strokeColor": "#000000", + "backgroundColor": "#fab005", + "width": 180, + "height": 31, + "seed": 457529269, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "type": "text", + "id": "x2msRpv4tJnWtZ_hp50wB" + } + ], + "updated": 1679558297778, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 263, + "versionNonce": 97818532, + "isDeleted": false, + "id": "x2msRpv4tJnWtZ_hp50wB", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -28.833396911621094, + "y": 765.6668701171875, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 25, + "height": 21, + "seed": 673507867, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679558297782, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "[n]", + "baseline": 14, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "10EyNsT35ULiP_xM9qv8Y", + "originalText": "[n]" + }, + { + "type": "text", + "version": 76, + "versionNonce": 375904405, + "isDeleted": false, + "id": "0XlRzavkxOV0TYo3Cru6q", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -307.66673278808594, + "y": 651.0002899169922, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 171, + "height": 19, + "seed": 1584858171, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "GXMgwVG5yviwCuQz9-Jdx", + "type": "arrow" + } + ], + "updated": 1679555887722, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 2, + "text": "(WASMTableInstance *)", + "baseline": 15, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "(WASMTableInstance *)" + }, + { + "type": "arrow", + "version": 29, + "versionNonce": 1192191803, + "isDeleted": false, + "id": "GXMgwVG5yviwCuQz9-Jdx", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -67.33335876464844, + "y": 639.0001068115234, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 69.3333740234375, + "height": 18.333343505859375, + "seed": 1221178005, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1679555887722, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": { + "elementId": "0XlRzavkxOV0TYo3Cru6q", + "focus": 0.6054948422392628, + "gap": 1 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -69.3333740234375, + 18.333343505859375 + ] + ] + }, + { + "type": "arrow", + "version": 104, + "versionNonce": 1499556260, + "isDeleted": false, + "id": "xGVX08X1n0JU0OA60_t9A", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -41.0000457763672, + "y": 446.7786348431563, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 81.66662597656249, + "height": 127.22147196836715, + "seed": 1672312955, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1679558303924, + "link": null, + "locked": false, + "startBinding": { + "elementId": "kOP_SYX2hDGyTbKOLrSY7", + "focus": 1.0138390872785434, + "gap": 15.333114624023438 + }, + "endBinding": { + "elementId": "DJ8H7VUIn868NKonqg5gA", + "focus": -0.9738124716848731, + "gap": 15.333290100097656 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -81.66662597656249, + 95.22147196836715 + ], + [ + -68.99999999999999, + 127.22147196836715 + ] + ] + }, + { + "type": "text", + "version": 42, + "versionNonce": 548718555, + "isDeleted": false, + "id": "HULjVKYZds5RYxESw_kpb", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -343.66673278808594, + "y": 454.3334197998047, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 173, + "height": 19, + "seed": 2051995003, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679555887722, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 2, + "text": "WASMFunctionInstance", + "baseline": 15, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "WASMFunctionInstance" + }, + { + "type": "rectangle", + "version": 116, + "versionNonce": 130053973, + "isDeleted": false, + "id": "kgRAri5TBI6AVeJYwZ0aO", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 291.8626718521118, + "y": 615.9665649414064, + "strokeColor": "#000000", + "backgroundColor": "#ced4da", + "width": 229.3333740234375, + "height": 71.33331298828125, + "seed": 1363010869, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "type": "text", + "id": "GHvOda4nqju-pWyZr-_zS" + } + ], + "updated": 1679555887722, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 70, + "versionNonce": 1629299868, + "isDeleted": false, + "id": "GHvOda4nqju-pWyZr-_zS", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 393.02935886383057, + "y": 642.0332214355467, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 27, + "height": 21, + "seed": 1441133723, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679558297783, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "[..]", + "baseline": 14, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "kgRAri5TBI6AVeJYwZ0aO", + "originalText": "[..]" + }, + { + "type": "text", + "version": 339, + "versionNonce": 1673577653, + "isDeleted": false, + "id": "oxCwJMeoYhRvkKNPtKeha", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 292.13729763031006, + "y": 587.3669616699217, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 211, + "height": 20, + "seed": 1528133269, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "Vhva2LNBhtrohj4Y3bGV9", + "type": "arrow" + }, + { + "id": "tV8skfel8ww2IgWRNSntj", + "type": "arrow" + } + ], + "updated": 1679555887723, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "WASMFunction (per module)", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "WASMFunction (per module)" + }, + { + "type": "arrow", + "version": 77, + "versionNonce": 1227017499, + "isDeleted": false, + "id": "Vhva2LNBhtrohj4Y3bGV9", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -140.00001525878906, + "y": 499.6667022705078, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 435.3333740234375, + "height": 121, + "seed": 975356629, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1679555887723, + "link": null, + "locked": false, + "startBinding": { + "elementId": "QLOWRmBSKHUu_NrX66JPt", + "focus": -0.5172589859849054, + "gap": 7.3333587646484375 + }, + "endBinding": { + "elementId": "oxCwJMeoYhRvkKNPtKeha", + "focus": -1.2215352226224219, + "gap": 13.29974060058612 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 230, + 35.33331298828125 + ], + [ + 435.3333740234375, + 121 + ] + ] + }, + { + "type": "rectangle", + "version": 220, + "versionNonce": 1520753525, + "isDeleted": false, + "id": "kby0LOGKuGuYeMzR0L7Pt", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 602.3332366943359, + "y": 559.4166564941406, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 48, + "height": 29, + "seed": 47414645, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679555887723, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 241, + "versionNonce": 12821717, + "isDeleted": false, + "id": "J-wnUXeWDAfVNvwQHeW06", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 601.9998626708984, + "y": 592.5832824707031, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 48, + "height": 29, + "seed": 785254101, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679555887723, + "link": null, + "locked": false + }, + { + "type": "diamond", + "version": 226, + "versionNonce": 441810683, + "isDeleted": false, + "id": "qpSAJ6K0S6TvU6i2Uflep", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 625.9998626708984, + "y": 600.2499389648438, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 10.66668701171875, + "height": 17.666656494140625, + "seed": 1914322171, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "euj5CRuv6EoS2abVhp14P", + "type": "arrow" + } + ], + "updated": 1679555887723, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 229, + "versionNonce": 2130854453, + "isDeleted": false, + "id": "yCRds2HRNFQhi2l_NRv1E", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 601.6665496826172, + "y": 625.9166259765625, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 48, + "height": 29, + "seed": 24142901, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "tV8skfel8ww2IgWRNSntj", + "type": "arrow" + } + ], + "updated": 1679555887723, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 238, + "versionNonce": 451012507, + "isDeleted": false, + "id": "XQ_n6PzQRK1pjOIbTF09C", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 600.3331756591797, + "y": 653.5832824707031, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 48, + "height": 29, + "seed": 1465836955, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679555887723, + "link": null, + "locked": false + }, + { + "type": "diamond", + "version": 219, + "versionNonce": 1782985621, + "isDeleted": false, + "id": "dQpthmaEJfLeEUR4UsOsg", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 622.9998626708984, + "y": 661.9166259765625, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 10.66668701171875, + "height": 17.666656494140625, + "seed": 2124420501, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679555887723, + "link": null, + "locked": false + }, + { + "type": "diamond", + "version": 231, + "versionNonce": 1796750395, + "isDeleted": false, + "id": "lRGlqO5nnxQXGumLJpnO9", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 624.3332366943359, + "y": 630.8333282470703, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 10.66668701171875, + "height": 17.666656494140625, + "seed": 1262844475, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679555887723, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 90, + "versionNonce": 516225269, + "isDeleted": false, + "id": "bCPa9rRVzubIpa31jwl73", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 574.0000152587891, + "y": 532.0000305175781, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 98.66668701171875, + "height": 177.33334350585938, + "seed": 294820597, + "groupIds": [], + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "id": "6EZFlJGbMoYN4RDYkSEYP", + "type": "arrow" + }, + { + "id": "euj5CRuv6EoS2abVhp14P", + "type": "arrow" + } + ], + "updated": 1679555887723, + "link": null, + "locked": false + }, + { + "type": "arrow", + "version": 534, + "versionNonce": 1457192155, + "isDeleted": false, + "id": "C_HvFqwDiW4wGe01QNKFg", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 715.7036827935111, + "y": 367.61115180121527, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 70.00552481453781, + "height": 1.0071746818260863, + "seed": 1379035003, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1679555887723, + "link": null, + "locked": false, + "startBinding": { + "elementId": "SQI7khDAbJL0pLh0deiej", + "focus": 0.39512687910745115, + "gap": 12.666702270507812 + }, + "endBinding": { + "elementId": "2jRIgxhs5VlnfeDeDJXss", + "focus": 0.24394927767367422, + "gap": 2.171731894901793 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 70.00552481453781, + -1.0071746818260863 + ] + ] + }, + { + "type": "arrow", + "version": 48, + "versionNonce": 163359099, + "isDeleted": false, + "id": "tV8skfel8ww2IgWRNSntj", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 622.6667327880859, + "y": 610.3333892822266, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 105.3333740234375, + "height": 3.666656494140625, + "seed": 1040768149, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1679555887723, + "link": null, + "locked": false, + "startBinding": { + "elementId": "yCRds2HRNFQhi2l_NRv1E", + "focus": 1.968489954492859, + "gap": 15.583236694335938 + }, + "endBinding": { + "elementId": "oxCwJMeoYhRvkKNPtKeha", + "focus": 1.5212851912013483, + "gap": 14.196061134338379 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -105.3333740234375, + 3.666656494140625 + ] + ] + }, + { + "type": "rectangle", + "version": 138, + "versionNonce": 2094596021, + "isDeleted": false, + "id": "lbEH3IbUKE-BUvPaOCKOp", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 705.7037133110892, + "y": 358.277838812934, + "strokeColor": "#000000", + "backgroundColor": "#fab005", + "width": 13.33331298828125, + "height": 11.666671752929688, + "seed": 638517691, + "groupIds": [], + "roundness": { + "type": 3 + }, + "boundElements": [], + "updated": 1679555887723, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 133, + "versionNonce": 419414555, + "isDeleted": false, + "id": "dTPwE9k9B6K3ksCQBb5OL", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 535.0371958414713, + "y": 506.51877678765186, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 176, + "height": 20, + "seed": 121765525, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679555887723, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "WASMModule::functions", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "WASMModule::functions" + }, + { + "type": "rectangle", + "version": 456, + "versionNonce": 1301726907, + "isDeleted": false, + "id": "2J2sR-bPrGrF9OxiUqIF0", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 868.2591145833333, + "y": 158.1759851243761, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 70.00006103515625, + "height": 25.66668701171874, + "seed": 1128772501, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "hFcIrFVFFLvSiAWOYE-xZ", + "type": "arrow" + } + ], + "updated": 1679555887723, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 284, + "versionNonce": 154931515, + "isDeleted": false, + "id": "ZZLxhvBfAsVbp2PY6VOfR", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 851.2592061360676, + "y": 129.7593591478136, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 98.66668701171875, + "height": 153.00003051757812, + "seed": 1437253909, + "groupIds": [], + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "id": "hFcIrFVFFLvSiAWOYE-xZ", + "type": "arrow" + } + ], + "updated": 1679555887723, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 356, + "versionNonce": 1161098229, + "isDeleted": false, + "id": "FdRdG15cLuW_kygoS9kFB", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 862.5927598741318, + "y": 332.1297662523058, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 159, + "height": 20, + "seed": 1076709051, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679555887723, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "WASMModule::globals", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "WASMModule::globals" + }, + { + "type": "rectangle", + "version": 458, + "versionNonce": 196882907, + "isDeleted": false, + "id": "ev_sIxuEomRo18wQcVOAi", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 863.5926411946614, + "y": 195.926084306505, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 70.00006103515625, + "height": 25.66668701171874, + "seed": 1597294293, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "hFcIrFVFFLvSiAWOYE-xZ", + "type": "arrow" + } + ], + "updated": 1679555887723, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 469, + "versionNonce": 1119661397, + "isDeleted": false, + "id": "2AbM31Y4eYzNJdn6ccO7X", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 870.2593892415364, + "y": 231.25939729478625, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 70.00006103515625, + "height": 25.66668701171874, + "seed": 1887403259, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "6EZFlJGbMoYN4RDYkSEYP", + "type": "arrow" + } + ], + "updated": 1679555887723, + "link": null, + "locked": false + }, + { + "type": "ellipse", + "version": 193, + "versionNonce": 499530421, + "isDeleted": false, + "id": "2jRIgxhs5VlnfeDeDJXss", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 787.7037285698783, + "y": 359.277838812934, + "strokeColor": "#000000", + "backgroundColor": "#7950f2", + "width": 16, + "height": 19.000091552734375, + "seed": 1552112411, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [ + { + "id": "C_HvFqwDiW4wGe01QNKFg", + "type": "arrow" + } + ], + "updated": 1679555887723, + "link": null, + "locked": false + }, + { + "type": "arrow", + "version": 445, + "versionNonce": 1861688341, + "isDeleted": false, + "id": "hFcIrFVFFLvSiAWOYE-xZ", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 797.8519422743055, + "y": 365.2778930664062, + "strokeColor": "#000000", + "backgroundColor": "#7950f2", + "width": 60.463513970850386, + "height": 155.0348750393585, + "seed": 1134283957, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1679555887723, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": { + "elementId": "ev_sIxuEomRo18wQcVOAi", + "focus": 0.8021785743382612, + "gap": 5.277184949505454 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 26.18546210394959, + -121.94443088107656 + ], + [ + 60.463513970850386, + -155.0348750393585 + ] + ] + }, + { + "type": "rectangle", + "version": 485, + "versionNonce": 1957174203, + "isDeleted": false, + "id": "qGE55eCk3NIsUQpSP-g6Y", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 888.4441562228732, + "y": 390.84254328409827, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 70.00006103515625, + "height": 25.66668701171874, + "seed": 983648475, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679555887723, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 316, + "versionNonce": 507826549, + "isDeleted": false, + "id": "c3AswZE8rY-ZsD8gGAzgg", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 871.4442477756076, + "y": 362.42591730753577, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 98.66668701171875, + "height": 153.00003051757812, + "seed": 832079445, + "groupIds": [], + "roundness": { + "type": 3 + }, + "boundElements": [], + "updated": 1679555887723, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 343, + "versionNonce": 1916988507, + "isDeleted": false, + "id": "6YL2S8HdLuD8PaiWGA-vU", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 829.5925801595051, + "y": 102.42615678575305, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 156, + "height": 20, + "seed": 920221051, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679555887723, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "WASMModule::tables", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "WASMModule::tables" + }, + { + "type": "rectangle", + "version": 542, + "versionNonce": 2029312725, + "isDeleted": false, + "id": "50mTV_vbZA4UToji5TAhb", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 882.0739339192708, + "y": 431.5186000400119, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 70.00006103515625, + "height": 25.66668701171874, + "seed": 1438577589, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "OjoiFuv7ZOtNkq4SpgOL-", + "type": "arrow" + } + ], + "updated": 1679555887723, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 553, + "versionNonce": 1635428603, + "isDeleted": false, + "id": "Aa3QPT7Ps924J0klBEGMw", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 888.7406819661458, + "y": 466.85191302829315, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 70.00006103515625, + "height": 25.66668701171874, + "seed": 547556891, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679555887723, + "link": null, + "locked": false + }, + { + "type": "diamond", + "version": 424, + "versionNonce": 1473368475, + "isDeleted": false, + "id": "WMOLdrP9c0TFV1JLcmfzK", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 233.66656494140625, + "y": 236.33336639404277, + "strokeColor": "#000000", + "backgroundColor": "#12b886", + "width": 17.3333740234375, + "height": 13.000015258789062, + "seed": 1272865237, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679555887723, + "link": null, + "locked": false + }, + { + "type": "diamond", + "version": 442, + "versionNonce": 606202261, + "isDeleted": false, + "id": "XVo2iBeciuaFiIrP3DUw5", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 235.66656494140625, + "y": 252.66669464111305, + "strokeColor": "#000000", + "backgroundColor": "#12b886", + "width": 17.3333740234375, + "height": 13.000015258789062, + "seed": 823202299, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "6EZFlJGbMoYN4RDYkSEYP", + "type": "arrow" + } + ], + "updated": 1679555887723, + "link": null, + "locked": false + }, + { + "type": "diamond", + "version": 427, + "versionNonce": 377153083, + "isDeleted": false, + "id": "InatpictpQQa0Op1qByFJ", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 235.66656494140625, + "y": 268.33336639404274, + "strokeColor": "#000000", + "backgroundColor": "#12b886", + "width": 17.3333740234375, + "height": 13.000015258789062, + "seed": 682826293, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "6EZFlJGbMoYN4RDYkSEYP", + "type": "arrow" + } + ], + "updated": 1679555887723, + "link": null, + "locked": false + }, + { + "type": "arrow", + "version": 609, + "versionNonce": 1207751547, + "isDeleted": false, + "id": "6EZFlJGbMoYN4RDYkSEYP", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 257.1755919962603, + "y": 432.4837343704476, + "strokeColor": "#000000", + "backgroundColor": "#12b886", + "width": 350.4818452518821, + "height": 113.7944575139108, + "seed": 1046151995, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1679555887723, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": { + "elementId": "bCPa9rRVzubIpa31jwl73", + "focus": 0.6467798007705062, + "gap": 1 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -33.87912050646, + 40.47938005012526 + ], + [ + 316.60272474542205, + 113.7944575139108 + ] + ] + }, + { + "type": "text", + "version": 380, + "versionNonce": 1636332981, + "isDeleted": false, + "id": "qUXi_zQbiA8lmV5c_r8ta", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 875.0742831759982, + "y": 534.6482721964519, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 172, + "height": 20, + "seed": 2104268027, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679555887723, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "WASMModule::memories", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "WASMModule::memories" + }, + { + "type": "rectangle", + "version": 511, + "versionNonce": 833268763, + "isDeleted": false, + "id": "rfTE9QxqtEjzOzoCNZT01", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 900.9256795247394, + "y": 593.3610492282444, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 70.00006103515625, + "height": 25.66668701171874, + "seed": 1292864565, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "4NjPz6Olqru3m83OxGXGX", + "type": "arrow" + } + ], + "updated": 1679555887723, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 342, + "versionNonce": 347731733, + "isDeleted": false, + "id": "RzznX4k1tfSt8AyuJuF2D", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 883.9257710774738, + "y": 564.9444232516819, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 98.66668701171875, + "height": 153.00003051757812, + "seed": 1990606235, + "groupIds": [], + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "id": "4NjPz6Olqru3m83OxGXGX", + "type": "arrow" + } + ], + "updated": 1679555887723, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 566, + "versionNonce": 626290875, + "isDeleted": false, + "id": "GEQFwoUvMYOSit62JGwLM", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 894.5554572211371, + "y": 634.037105984158, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 70.00006103515625, + "height": 25.66668701171874, + "seed": 1545223573, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679555887723, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 578, + "versionNonce": 1559514229, + "isDeleted": false, + "id": "IvFYTMyYUBhJe6Ob5YAGg", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 901.2222052680121, + "y": 669.3704189724392, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 70.00006103515625, + "height": 25.66668701171874, + "seed": 937546299, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679555887723, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 43, + "versionNonce": 1419551067, + "isDeleted": false, + "id": "ZMwf8VnKqa7gp45PnuQWi", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 780.3335876464843, + "y": 45.92599826388881, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 286.66666666666686, + "height": 707.0370313856337, + "seed": 876902971, + "groupIds": [], + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "id": "YidAloK-3ikBBzvuu-S22", + "type": "arrow" + } + ], + "updated": 1679555887723, + "link": null, + "locked": false + }, + { + "type": "arrow", + "version": 138, + "versionNonce": 1241314773, + "isDeleted": false, + "id": "2NQmRBF_NE2Myp3-jqLfT", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 418.1839375016565, + "y": 222.9630296495223, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 351.7376685654755, + "height": 202.59258694118918, + "seed": 1011740277, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1679555887723, + "link": null, + "locked": false, + "startBinding": { + "elementId": "TOmX9MwwNOgbfjNJ8V8j7", + "focus": 0.48971428325717553, + "gap": 11.018498738606851 + }, + "endBinding": { + "elementId": "7MNv-pmgV4-8yJ5lIFY1U", + "focus": 1.3268339026620566, + "gap": 13.16658528645857 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 82.8903795827618, + -202.59258694118918 + ], + [ + 351.7376685654755, + -175.99734962527606 + ] + ] + }, + { + "type": "arrow", + "version": 58, + "versionNonce": 416660987, + "isDeleted": false, + "id": "OjoiFuv7ZOtNkq4SpgOL-", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 796.6298048231338, + "y": 366.6667785644529, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 82.96305338541652, + "height": 65.92593722873261, + "seed": 275987509, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1679555887723, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": { + "elementId": "50mTV_vbZA4UToji5TAhb", + "focus": -0.4434608130384178, + "gap": 2.481075710720461 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 82.96305338541652, + 65.92593722873261 + ] + ] + }, + { + "type": "arrow", + "version": 131, + "versionNonce": 1458139957, + "isDeleted": false, + "id": "4NjPz6Olqru3m83OxGXGX", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 796.6298726399739, + "y": 372.96306355794246, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 98.51854112413207, + "height": 227.77777777777777, + "seed": 1888354747, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1679555887723, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": { + "elementId": "rfTE9QxqtEjzOzoCNZT01", + "focus": -0.6184957089704255, + "gap": 5.7772657606334406 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 46.66673448350696, + 191.48159450954864 + ], + [ + 98.51854112413207, + 227.77777777777777 + ] + ] + }, + { + "type": "arrow", + "version": 105, + "versionNonce": 2097301147, + "isDeleted": false, + "id": "euj5CRuv6EoS2abVhp14P", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 792.9261237250435, + "y": 375.55566745334175, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 140, + "height": 233.33346896701386, + "seed": 856817851, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1679555887723, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": { + "elementId": "qpSAJ6K0S6TvU6i2Uflep", + "focus": 1.8857122566967692, + "gap": 14.01957438916057 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -30.37034776475707, + 147.77781168619794 + ], + [ + -140, + 233.33346896701386 + ] + ] + }, + { + "type": "text", + "version": 404, + "versionNonce": 2049173, + "isDeleted": false, + "id": "0836mka_gP8EntAw7Pvzh", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 285.4076097276477, + "y": 424.0742221408418, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 198, + "height": 19, + "seed": 1302236763, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679555887724, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 2, + "text": "WASMFunction **functions;", + "baseline": 15, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "WASMFunction **functions;" + }, + { + "type": "rectangle", + "version": 385, + "versionNonce": 131382075, + "isDeleted": false, + "id": "Fv3xwjCOvQ9-pJ5ui2sV2", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 239.7409837510852, + "y": 409.4075961642793, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 216, + "height": 42.6666259765625, + "seed": 1276926165, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679555887724, + "link": null, + "locked": false + }, + { + "type": "diamond", + "version": 350, + "versionNonce": 424929781, + "isDeleted": false, + "id": "IibWA_jM89ndxmrceQLmE", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 254.4077317979602, + "y": 420.07428317599806, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 15.33331298828125, + "height": 22.66668701171875, + "seed": 1427245819, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679555887724, + "link": null, + "locked": false + }, + { + "type": "arrow", + "version": 133, + "versionNonce": 1169136603, + "isDeleted": false, + "id": "OdDm5a5O_NIoZbF3u0c0H", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 442.5558098687066, + "y": 370.37052747938344, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 138.34606629993374, + "height": 88.15863628949046, + "seed": 967352763, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1679555887724, + "link": null, + "locked": false, + "startBinding": { + "elementId": "FPUGB-iP7ep91gfoTuV2d", + "focus": 0.6557614629211577, + "gap": 3.7962053087022696 + }, + "endBinding": { + "elementId": "blxQLl_yf7DMD76qHC5rc", + "focus": -0.24942508137542688, + "gap": 9.870619032117872 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 61.48149278428815, + -72.22222222222217 + ], + [ + 138.34606629993374, + -88.15863628949046 + ] + ] + }, + { + "type": "text", + "version": 35, + "versionNonce": 1670177621, + "isDeleted": false, + "id": "armvxVMuT0bX77T30wPV4", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -39.66648017035561, + "y": 230.37051052517361, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 165, + "height": 20, + "seed": 587722005, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679555887724, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "export_global_count", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "export_global_count" + }, + { + "type": "rectangle", + "version": 502, + "versionNonce": 312830075, + "isDeleted": false, + "id": "nUlAmf5jmsJoZ2lStTbBw", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": -52.18503146701369, + "y": 226.01867336697043, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 174.66668701171875, + "height": 25.37032402886292, + "seed": 1476753525, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679555887724, + "link": null, + "locked": false + }, + { + "id": "Mznw_08SMS746JVePQe3h", + "type": "text", + "x": -55.747947692871094, + "y": 396.450114440918, + "width": 174, + "height": 20, + "angle": 0, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "roundness": null, + "seed": 1392475036, + "version": 62, + "versionNonce": 452856732, + "isDeleted": false, + "boundElements": null, + "updated": 1679558398355, + "link": null, + "locked": false, + "text": "export_memory_count", + "fontSize": 16, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "baseline": 14, + "containerId": null, + "originalText": "export_memory_count" + }, + { + "id": "wyGG1OIhy3X499IvtJM3Z", + "type": "rectangle", + "x": -58.081260681152344, + "y": 394.9499618530274, + "width": 182.33331298828125, + "height": 25, + "angle": 0, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "roundness": null, + "seed": 611257380, + "version": 32, + "versionNonce": 1973769116, + "isDeleted": false, + "boundElements": null, + "updated": 1679558406221, + "link": null, + "locked": false + }, + { + "id": "Gk4JYjHayAFkRDbQWId6b", + "type": "text", + "x": -42.081260681152344, + "y": 463.28327484130864, + "width": 162, + "height": 20, + "angle": 0, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "roundness": null, + "seed": 804003748, + "version": 47, + "versionNonce": 591391772, + "isDeleted": false, + "boundElements": null, + "updated": 1679558418472, + "link": null, + "locked": false, + "text": "export_table_count", + "fontSize": 16, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "baseline": 14, + "containerId": null, + "originalText": "export_table_count" + }, + { + "id": "Xb-aggFXlG4Dh_LtxGJ7l", + "type": "rectangle", + "x": -49.414573669433594, + "y": 462.28330535888676, + "width": 174.33331298828125, + "height": 24.33343505859375, + "angle": 0, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "roundness": null, + "seed": 572093348, + "version": 30, + "versionNonce": 1840351132, + "isDeleted": false, + "boundElements": null, + "updated": 1679558423043, + "link": null, + "locked": false + } + ], + "appState": { + "gridSize": null, + "viewBackgroundColor": "#ffffff" + }, + "files": {} +} \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/doc/images/stack_format_ci.excalidraw b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/doc/images/stack_format_ci.excalidraw new file mode 100644 index 00000000000..f2ade3b2058 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/doc/images/stack_format_ci.excalidraw @@ -0,0 +1,2643 @@ +{ + "type": "excalidraw", + "version": 2, + "source": "https://marketplace.visualstudio.com/items?itemName=pomdtr.excalidraw-editor", + "elements": [ + { + "type": "rectangle", + "version": 155, + "versionNonce": 1248561528, + "isDeleted": false, + "id": "fxSjNN3geJtdm-2MR7INN", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 583.9999694824219, + "y": 276.33331298828114, + "strokeColor": "#000000", + "backgroundColor": "#ced4da", + "width": 427.66665649414057, + "height": 468.6667785644533, + "seed": 1226571556, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "zFlCnXyCuuvj85rH8yMcR", + "type": "arrow" + }, + { + "id": "KiC12zdfqG7zXRbctXGmT", + "type": "arrow" + } + ], + "updated": 1679706874848, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 31, + "versionNonce": 726044059, + "isDeleted": false, + "id": "kKMhPpSUI7zZU0hhfGfSr", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 652, + "y": 310.5, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 91, + "height": 20, + "seed": 1323166748, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "v8qOyuaPyJmHPHCk-V90A", + "type": "arrow" + } + ], + "updated": 1679639568750, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "prev_frame", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "prev_frame" + }, + { + "type": "text", + "version": 31, + "versionNonce": 213374372, + "isDeleted": false, + "id": "97vkuGwuf9dOgnbXL4nZW", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 652, + "y": 345.5, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 84, + "height": 20, + "seed": 123433892, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679617642914, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "func_inst ", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "func_inst " + }, + { + "type": "text", + "version": 31, + "versionNonce": 34601372, + "isDeleted": false, + "id": "IaZULBLAtP-VbIpB210WT", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 652, + "y": 380.5, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 13, + "height": 20, + "seed": 1157761180, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679617674900, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "ip", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "ip" + }, + { + "type": "text", + "version": 37, + "versionNonce": 556583925, + "isDeleted": false, + "id": "H6AElOIjCOfKVDEzsEb8_", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 648.3333435058594, + "y": 415.16668701171875, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 160, + "height": 20, + "seed": 175464228, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "bzZuzwhAslOM0VOMpIFi4", + "type": "arrow" + } + ], + "updated": 1679638914768, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "opnd_stack_bottom", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "opnd_stack_bottom" + }, + { + "type": "text", + "version": 31, + "versionNonce": 2114117339, + "isDeleted": false, + "id": "InrDJwTwyP1E7lpeGu0Tb", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 652, + "y": 450.5, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 275, + "height": 20, + "seed": 158242076, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "bzZuzwhAslOM0VOMpIFi4", + "type": "arrow" + } + ], + "updated": 1679638694120, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "opnd_sp (point to opnd stack top)", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "opnd_sp (point to opnd stack top)" + }, + { + "type": "text", + "version": 31, + "versionNonce": 1005029461, + "isDeleted": false, + "id": "04QcPfm0Sc1zQpYDxmPVl", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 652, + "y": 485.5, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 163, + "height": 20, + "seed": 2051398308, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679638792159, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "label_stack_bottom", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "label_stack_bottom" + }, + { + "type": "text", + "version": 31, + "versionNonce": 1565468827, + "isDeleted": false, + "id": "GD4urgWTuYKcn7FcwA5uj", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 652, + "y": 520.5, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 280, + "height": 20, + "seed": 429232540, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "AhNgHym2Ox-2Je47FlwkG", + "type": "arrow" + } + ], + "updated": 1679638982669, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "label_sp (point to label stack top)", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "label_sp (point to label stack top)" + }, + { + "type": "text", + "version": 123, + "versionNonce": 458495496, + "isDeleted": false, + "id": "9TW8AADnHJOkmP9yPw86T", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 626, + "y": 586.1666564941406, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 125, + "height": 20, + "seed": 561702436, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679706667761, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "func arguments:", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "func arguments:" + }, + { + "type": "text", + "version": 373, + "versionNonce": 180653176, + "isDeleted": false, + "id": "ZDnffzv8Hf65ecpMemz82", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 700.6666870117188, + "y": 669.1667785644531, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 131, + "height": 20, + "seed": 1157792164, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679706543900, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "" + }, + { + "type": "rectangle", + "version": 108, + "versionNonce": 628186232, + "isDeleted": false, + "id": "10UtZNhGhQIza4PqPLKs5", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 622.6665954589844, + "y": 299.9999694824219, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 378.3334655761719, + "height": 33.66670227050781, + "seed": 1281579428, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679706899765, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 108, + "versionNonce": 1807107317, + "isDeleted": false, + "id": "lxiJENi5HY8EPwIeH7LA0", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 621.9999389648438, + "y": 343.3332977294922, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 377.6668090820312, + "height": 28.33332824707031, + "seed": 523845788, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679639010923, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 104, + "versionNonce": 114288661, + "isDeleted": false, + "id": "iBGNXVvcsdhIuK4rSyr24", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 621.333251953125, + "y": 377.9999694824219, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 380.3333129882813, + "height": 24.666656494140625, + "seed": 1117299228, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679639014926, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 141, + "versionNonce": 1756531061, + "isDeleted": false, + "id": "hwgrctAuxGaA-SGuwFgEd", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 623.6665649414062, + "y": 413.66664123535156, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 190.33331298828125, + "height": 25.333358764648438, + "seed": 1885325596, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "2yVfQUtaAnW5BuEtoXRcA", + "type": "arrow" + } + ], + "updated": 1679638734395, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 135, + "versionNonce": 138906299, + "isDeleted": false, + "id": "V6DAmN9L5JPz2B1MGfa9C", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 624.6665954589844, + "y": 445.9999694824219, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 377.6666564941406, + "height": 28.00003051757812, + "seed": 1058988452, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "bzZuzwhAslOM0VOMpIFi4", + "type": "arrow" + } + ], + "updated": 1679638756269, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 171, + "versionNonce": 755362101, + "isDeleted": false, + "id": "0m59R0bqJv_x7GbZ6hfyg", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 624.6665954589844, + "y": 485.33331298828125, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 197.33340454101562, + "height": 23.33328247070314, + "seed": 1040920092, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "bzZuzwhAslOM0VOMpIFi4", + "type": "arrow" + } + ], + "updated": 1679638908118, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 191, + "versionNonce": 944635675, + "isDeleted": false, + "id": "Itqs7rL1-S3eIrmvfrr6i", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 625.333251953125, + "y": 516.3333129882812, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 349.66674804687506, + "height": 34.66665649414062, + "seed": 498379804, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679639029205, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 169, + "versionNonce": 1525847816, + "isDeleted": false, + "id": "Yx4QpHhmHHvf267ot4QcW", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 623.333251953125, + "y": 582.6666259765625, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 352.3333740234375, + "height": 31.666748046875, + "seed": 612410396, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679706543900, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 195, + "versionNonce": 335028795, + "isDeleted": false, + "id": "sWiDv3IP9Y4zn-pQPKT59", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 585.6668090820312, + "y": 203.99998474121094, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 424.3334045410156, + "height": 70.66668701171874, + "seed": 813710748, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "v8qOyuaPyJmHPHCk-V90A", + "type": "arrow" + } + ], + "updated": 1679639568750, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 255, + "versionNonce": 1953250680, + "isDeleted": false, + "id": "gS_VbgMS5NUoHmfxH0eEO", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 752.0001525878906, + "y": 624.3333129882812, + "strokeColor": "#000000", + "backgroundColor": "#40c057", + "width": 30.6666259765625, + "height": 19.000091552734375, + "seed": 2044515484, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679706543900, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 171, + "versionNonce": 227339384, + "isDeleted": false, + "id": "m89OexiP1cw5cN304gmQ-", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 771.3336334228516, + "y": 587.8333282470703, + "strokeColor": "#000000", + "backgroundColor": "#40c057", + "width": 37.999969482421875, + "height": 19.666748046875, + "seed": 2074557348, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679706664521, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 174, + "versionNonce": 1205391112, + "isDeleted": false, + "id": "aAWksorEQDseQSDntTUKe", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 824.6669464111328, + "y": 589.1665802001953, + "strokeColor": "#000000", + "backgroundColor": "#40c057", + "width": 35.999969482421875, + "height": 15.666778564453123, + "seed": 1851711260, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679706659367, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 213, + "versionNonce": 1798283016, + "isDeleted": false, + "id": "IH4D4tHy91CnkLlP3kKJT", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 878.6669464111328, + "y": 588.8333892822266, + "strokeColor": "#000000", + "backgroundColor": "#40c057", + "width": 35.999969482421875, + "height": 16.333435058593754, + "seed": 1835107492, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679706677882, + "link": null, + "locked": false + }, + { + "type": "diamond", + "version": 28, + "versionNonce": 1189712156, + "isDeleted": false, + "id": "OGXe0pARYj6FFaTw_LGLs", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 916.6667785644531, + "y": 348.3333435058594, + "strokeColor": "#000000", + "backgroundColor": "#40c057", + "width": 13.33331298828125, + "height": 15.66668701171875, + "seed": 703955236, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "zFlCnXyCuuvj85rH8yMcR", + "type": "arrow" + } + ], + "updated": 1679617654572, + "link": null, + "locked": false + }, + { + "type": "arrow", + "version": 90, + "versionNonce": 1752012152, + "isDeleted": false, + "id": "zFlCnXyCuuvj85rH8yMcR", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 930.9664201728779, + "y": 355.9093759200581, + "strokeColor": "#000000", + "backgroundColor": "#40c057", + "width": 97.70041942673151, + "height": 3.156306335738577, + "seed": 1652552228, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679706533823, + "link": null, + "locked": false, + "startBinding": { + "elementId": "OGXe0pARYj6FFaTw_LGLs", + "gap": 1, + "focus": -0.05520408889747474 + }, + "endBinding": { + "elementId": "fxSjNN3geJtdm-2MR7INN", + "gap": 17.000213623046875, + "focus": 0.6588609578759657 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 97.70041942673151, + 3.156306335738577 + ] + ] + }, + { + "type": "rectangle", + "version": 39, + "versionNonce": 2081828900, + "isDeleted": false, + "id": "cN9omEMJtZq2pKK3nPqeK", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1033.3334655761719, + "y": 339.0000305175781, + "strokeColor": "#000000", + "backgroundColor": "#40c057", + "width": 218, + "height": 37, + "seed": 1716587932, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "type": "text", + "id": "w-Fx4nTROv9qvnPqLigxc" + } + ], + "updated": 1679617661526, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 4, + "versionNonce": 727129976, + "isDeleted": false, + "id": "w-Fx4nTROv9qvnPqLigxc", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1051.3334655761719, + "y": 347.5000305175781, + "strokeColor": "#000000", + "backgroundColor": "#40c057", + "width": 182, + "height": 20, + "seed": 1245620124, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679706461629, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "(current func instance)", + "baseline": 14, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "cN9omEMJtZq2pKK3nPqeK", + "originalText": "(current func instance)" + }, + { + "type": "diamond", + "version": 19, + "versionNonce": 1517445412, + "isDeleted": false, + "id": "YAWb1D32tq9r2NA9BjPC0", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 917.3334655761719, + "y": 381.3333740234375, + "strokeColor": "#000000", + "backgroundColor": "#40c057", + "width": 12.6666259765625, + "height": 17.666656494140625, + "seed": 831940124, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679617681098, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 103, + "versionNonce": 437077525, + "isDeleted": false, + "id": "EUw5VCdUqXWdPh2cmFgTu", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1048.0000915527344, + "y": 390.0000305175781, + "strokeColor": "#000000", + "backgroundColor": "#40c057", + "width": 224, + "height": 52, + "seed": 122854564, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "type": "text", + "id": "sQUYAdB_aJemE8MbtfUXU" + }, + { + "id": "7cT6qctQMJuzVHVpt9gAe", + "type": "arrow" + } + ], + "updated": 1679643416466, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 89, + "versionNonce": 818328584, + "isDeleted": false, + "id": "sQUYAdB_aJemE8MbtfUXU", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1066.0000915527344, + "y": 395.0000305175781, + "strokeColor": "#000000", + "backgroundColor": "#40c057", + "width": 188, + "height": 40, + "seed": 1881253020, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679706461630, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": " (next bytecode in code\nfor return)", + "baseline": 34, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "EUw5VCdUqXWdPh2cmFgTu", + "originalText": " (next bytecode in code\nfor return)" + }, + { + "type": "arrow", + "version": 86, + "versionNonce": 44769845, + "isDeleted": false, + "id": "7cT6qctQMJuzVHVpt9gAe", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 928.0000915527344, + "y": 389.66668701171875, + "strokeColor": "#000000", + "backgroundColor": "#40c057", + "width": 118.6890752940651, + "height": 18.605575795885613, + "seed": 2073584156, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679643418552, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": { + "elementId": "EUw5VCdUqXWdPh2cmFgTu", + "gap": 1.3109247059348494, + "focus": -0.23038166167021662 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 118.6890752940651, + 18.605575795885613 + ] + ] + }, + { + "type": "rectangle", + "version": 2, + "versionNonce": 504035291, + "isDeleted": false, + "id": "6fkbi-hv-WF274Ggup6O2", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1200.0001525878906, + "y": 619.8332824707031, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 0.333251953125, + "height": 0.333343505859375, + "seed": 1881722357, + "groupIds": [], + "roundness": { + "type": 3 + }, + "boundElements": [], + "updated": 1679638527376, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 237, + "versionNonce": 103104376, + "isDeleted": false, + "id": "TBY_IOcQ1nL2SbnoH6sFO", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 627.0001373291016, + "y": 660.5000610351562, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 357.33331298828125, + "height": 30.33352661132812, + "seed": 1619080725, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "bzZuzwhAslOM0VOMpIFi4", + "type": "arrow" + }, + { + "id": "2yVfQUtaAnW5BuEtoXRcA", + "type": "arrow" + } + ], + "updated": 1679706543900, + "link": null, + "locked": false + }, + { + "type": "arrow", + "version": 304, + "versionNonce": 1231721480, + "isDeleted": false, + "id": "2yVfQUtaAnW5BuEtoXRcA", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1001.4951265607561, + "y": 435.4648501924554, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 69.86595546390652, + "height": 230.92727975758817, + "seed": 554350997, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1679706543901, + "link": null, + "locked": false, + "startBinding": { + "elementId": "Q10gr2u0Ozc3e0iafNjrU", + "focus": -0.9749635321679403, + "gap": 1 + }, + "endBinding": { + "elementId": "TBY_IOcQ1nL2SbnoH6sFO", + "gap": 11.467449077109102, + "focus": 0.9687666106437038 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 64.17172829764229, + 132.70180630168522 + ], + [ + -5.694227166264227, + 230.92727975758817 + ] + ] + }, + { + "type": "arrow", + "version": 579, + "versionNonce": 1040896776, + "isDeleted": false, + "id": "bzZuzwhAslOM0VOMpIFi4", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 637.088614263612, + "y": 428.66374830753944, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 87.42185095794798, + "height": 243.67105886528202, + "seed": 1778263445, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1679706543901, + "link": null, + "locked": false, + "startBinding": { + "elementId": "H6AElOIjCOfKVDEzsEb8_", + "focus": 1.022917371543073, + "gap": 11.244729242247331 + }, + "endBinding": { + "elementId": "zmGNXD3FjbK3cLzJQcTS7", + "focus": -0.9191849396644245, + "gap": 1.3880431063754486 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -87.42185095794798, + 127.50287766902306 + ], + [ + -10.80983302916718, + 243.67105886528202 + ] + ] + }, + { + "type": "rectangle", + "version": 146, + "versionNonce": 1195282552, + "isDeleted": false, + "id": "zmGNXD3FjbK3cLzJQcTS7", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 627.6668243408203, + "y": 662.8332824707031, + "strokeColor": "#000000", + "backgroundColor": "#868e96", + "width": 207.333251953125, + "height": 25.333343505859375, + "seed": 2075064181, + "groupIds": [], + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "id": "bzZuzwhAslOM0VOMpIFi4", + "type": "arrow" + }, + { + "id": "PtPViQVeIOLGj_fGdcXae", + "type": "arrow" + } + ], + "updated": 1679706543901, + "link": null, + "locked": false + }, + { + "type": "arrow", + "version": 252, + "versionNonce": 1380659720, + "isDeleted": false, + "id": "fdKDasbQmnSQhVWnuc6o0", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 892.2284992953181, + "y": 676.9139215503409, + "strokeColor": "#000000", + "backgroundColor": "#868e96", + "width": 46.77163803378346, + "height": 0.7472955737783877, + "seed": 2138378229, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1679706543901, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": null, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "triangle", + "points": [ + [ + 0, + 0 + ], + [ + 46.77163803378346, + -0.7472955737783877 + ] + ] + }, + { + "type": "text", + "version": 63, + "versionNonce": 2032367925, + "isDeleted": false, + "id": "ZwrESUGUwekFgJ8cot-D1", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 821.6667327880859, + "y": 414.6666259765625, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 174, + "height": 20, + "seed": 795089589, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "2yVfQUtaAnW5BuEtoXRcA", + "type": "arrow" + } + ], + "updated": 1679638757542, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "opnd_stack_boundary", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "opnd_stack_boundary" + }, + { + "type": "rectangle", + "version": 32, + "versionNonce": 132303029, + "isDeleted": false, + "id": "VOinNwnsGZVJt9RUbM5gI", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 821.3334197998047, + "y": 409.8332977294922, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 184.3333740234375, + "height": 30.333328247070312, + "seed": 1069875285, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679638823023, + "link": null, + "locked": false + }, + { + "type": "arrow", + "version": 255, + "versionNonce": 453362040, + "isDeleted": false, + "id": "PtPViQVeIOLGj_fGdcXae", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 979.6667327880859, + "y": 460.4999694824219, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 140.89037965104183, + "height": 211.49970410546382, + "seed": 472939093, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1679706543901, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": { + "elementId": "zmGNXD3FjbK3cLzJQcTS7", + "focus": 0.7843520090394333, + "gap": 6.109589831379935 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 2.33331298828125, + 145 + ], + [ + -138.55706666276058, + 211.49970410546382 + ] + ] + }, + { + "type": "diamond", + "version": 19, + "versionNonce": 987485307, + "isDeleted": false, + "id": "u7bglMSX07f5CN_SyFAmd", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 967.0000457763672, + "y": 452.1666259765625, + "strokeColor": "#000000", + "backgroundColor": "#be4bdb", + "width": 15, + "height": 15, + "seed": 764957403, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1679638777911, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 43, + "versionNonce": 115610933, + "isDeleted": false, + "id": "shh1k5OswcF57jhAKAI6G", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 830.0000457763672, + "y": 486.8332824707031, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 176, + "height": 20, + "seed": 1994374395, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679638809874, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "label_stack_boundary", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "label_stack_boundary" + }, + { + "type": "rectangle", + "version": 33, + "versionNonce": 1511042715, + "isDeleted": false, + "id": "H4lcjS3aIarViIGAHsLBU", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 827.6667327880859, + "y": 480.83331298828125, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 181, + "height": 29.666656494140625, + "seed": 1492829339, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679638816247, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 372, + "versionNonce": 1764776968, + "isDeleted": false, + "id": "B1eH_aNspf4OoiXnvWu1V", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 630.0000915527344, + "y": 705.1667175292969, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 356.66662597656256, + "height": 31.333404541015625, + "seed": 710054491, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "X76to9wjER3VzqXb7tCwb", + "type": "arrow" + }, + { + "id": "1Urs2i0MGQSQ9XbOVdbCH", + "type": "arrow" + }, + { + "id": "KiC12zdfqG7zXRbctXGmT", + "type": "arrow" + } + ], + "updated": 1679706706153, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 332, + "versionNonce": 1981566984, + "isDeleted": false, + "id": "Tu7mkiWTjNwFrOsUa35N1", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 633.3333740234375, + "y": 704.8334045410156, + "strokeColor": "#000000", + "backgroundColor": "#868e96", + "width": 250.33328247070318, + "height": 26.66656494140625, + "seed": 1201312981, + "groupIds": [], + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "id": "AhNgHym2Ox-2Je47FlwkG", + "type": "arrow" + } + ], + "updated": 1679706543901, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 250, + "versionNonce": 1696927496, + "isDeleted": false, + "id": "xQf_fS4j5XD1gPYVmnyQi", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 687, + "y": 709.8335876464844, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 108, + "height": 20, + "seed": 1671092892, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679706543901, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "" + }, + { + "type": "diamond", + "version": 19, + "versionNonce": 167262267, + "isDeleted": false, + "id": "T43dNIeAePPWy65vsVjRw", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 629.0000457763672, + "y": 420.8332977294922, + "strokeColor": "#000000", + "backgroundColor": "#12b886", + "width": 13.66668701171875, + "height": 9, + "seed": 1938681499, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679638923749, + "link": null, + "locked": false + }, + { + "type": "diamond", + "version": 26, + "versionNonce": 1796989173, + "isDeleted": false, + "id": "Q10gr2u0Ozc3e0iafNjrU", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 988.5000762939453, + "y": 431.9999542236328, + "strokeColor": "#000000", + "backgroundColor": "#12b886", + "width": 13.66668701171875, + "height": 9, + "seed": 1339643477, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "2yVfQUtaAnW5BuEtoXRcA", + "type": "arrow" + } + ], + "updated": 1679639079224, + "link": null, + "locked": false + }, + { + "type": "arrow", + "version": 160, + "versionNonce": 1562882312, + "isDeleted": false, + "id": "X76to9wjER3VzqXb7tCwb", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 633.6667327880859, + "y": 498.1665954589844, + "strokeColor": "#000000", + "backgroundColor": "#12b886", + "width": 95, + "height": 226.4773119076067, + "seed": 332801877, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1679706543901, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": { + "elementId": "B1eH_aNspf4OoiXnvWu1V", + "gap": 3.7751266782821933, + "focus": -0.9692106196282059 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -95, + 119 + ], + [ + -7.441767913633839, + 226.4773119076067 + ] + ] + }, + { + "type": "arrow", + "version": 202, + "versionNonce": 791528312, + "isDeleted": false, + "id": "1Urs2i0MGQSQ9XbOVdbCH", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 993.6667327880859, + "y": 500.833251953125, + "strokeColor": "#000000", + "backgroundColor": "#12b886", + "width": 55.58884147480535, + "height": 215.3311147859538, + "seed": 385950459, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1679706543901, + "link": null, + "locked": false, + "startBinding": { + "elementId": "_1a_M2hRRjsccFJTYD-i0", + "focus": -0.27052637703325505, + "gap": 2.7105616084241397 + }, + "endBinding": { + "elementId": "B1eH_aNspf4OoiXnvWu1V", + "focus": 0.9207393546998478, + "gap": 3.0779218308585996 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 51.666748046875, + 153.66668701171875 + ], + [ + -3.922093427930349, + 215.3311147859538 + ] + ] + }, + { + "type": "arrow", + "version": 252, + "versionNonce": 1150719096, + "isDeleted": false, + "id": "AhNgHym2Ox-2Je47FlwkG", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 941.0000457763672, + "y": 533.833251953125, + "strokeColor": "#000000", + "backgroundColor": "#12b886", + "width": 73.73891815660659, + "height": 177.63880524698254, + "seed": 17032283, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1679706543901, + "link": null, + "locked": false, + "startBinding": { + "elementId": "GD4urgWTuYKcn7FcwA5uj", + "focus": -1.0502037458670375, + "gap": 9.000045776367188 + }, + "endBinding": { + "elementId": "Tu7mkiWTjNwFrOsUa35N1", + "focus": 0.7914007600477917, + "gap": 2.5944100904637253 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 18.99993896484375, + 133.33340454101562 + ], + [ + -54.73897919176284, + 177.63880524698254 + ] + ] + }, + { + "type": "diamond", + "version": 19, + "versionNonce": 987485307, + "isDeleted": false, + "id": "C2JNNEQlhQ4cFy2h16E4l", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 630.5000457763672, + "y": 491.333251953125, + "strokeColor": "#000000", + "backgroundColor": "#be4bdb", + "width": 15, + "height": 15, + "seed": 2047712475, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1679638991963, + "link": null, + "locked": false + }, + { + "type": "diamond", + "version": 19, + "versionNonce": 987485307, + "isDeleted": false, + "id": "xsWhegnNTDUvjVk1Hl20d", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 931.5000457763672, + "y": 523.333251953125, + "strokeColor": "#000000", + "backgroundColor": "#be4bdb", + "width": 15, + "height": 15, + "seed": 751530581, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1679638994246, + "link": null, + "locked": false + }, + { + "type": "diamond", + "version": 20, + "versionNonce": 2123101557, + "isDeleted": false, + "id": "_1a_M2hRRjsccFJTYD-i0", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 987.5000457763672, + "y": 503.333251953125, + "strokeColor": "#000000", + "backgroundColor": "#be4bdb", + "width": 15, + "height": 15, + "seed": 1838893435, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [ + { + "id": "1Urs2i0MGQSQ9XbOVdbCH", + "type": "arrow" + } + ], + "updated": 1679639046142, + "link": null, + "locked": false + }, + { + "type": "arrow", + "version": 122, + "versionNonce": 918373752, + "isDeleted": false, + "id": "_FzrYgawOp32aihqUkx8N", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 937.3333587646484, + "y": 722.4999084472656, + "strokeColor": "#000000", + "backgroundColor": "#12b886", + "width": 31, + "height": 0.333343505859375, + "seed": 125027067, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1679706543901, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": null, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "triangle", + "points": [ + [ + 0, + 0 + ], + [ + 31, + 0.333343505859375 + ] + ] + }, + { + "type": "arrow", + "version": 58, + "versionNonce": 1791510299, + "isDeleted": false, + "id": "v8qOyuaPyJmHPHCk-V90A", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 640.33349609375, + "y": 318.1665954589844, + "strokeColor": "#000000", + "backgroundColor": "#12b886", + "width": 112.66668701171875, + "height": 114.41643468378521, + "seed": 1521072891, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1679639586455, + "link": null, + "locked": false, + "startBinding": { + "elementId": "kKMhPpSUI7zZU0hhfGfSr", + "focus": -0.8312315870337287, + "gap": 11.66650390625 + }, + "endBinding": { + "elementId": "sWiDv3IP9Y4zn-pQPKT59", + "focus": 1.0049483520293248, + "gap": 1 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -112.66668701171875, + -61.99995422363281 + ], + [ + -55.63497828298284, + -114.41643468378521 + ] + ] + }, + { + "type": "diamond", + "version": 23, + "versionNonce": 1760592469, + "isDeleted": false, + "id": "rizowRaNCY3sscSKdUoZ_", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 637.6668090820312, + "y": 307.49993896484375, + "strokeColor": "#000000", + "backgroundColor": "#12b886", + "width": 11.66668701171875, + "height": 17, + "seed": 599455541, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1679639578366, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 241, + "versionNonce": 1517501429, + "isDeleted": false, + "id": "Mv8lernCpH2jNrVrNfqm5", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 585.8334503173828, + "y": 130.833251953125, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 424.3334045410156, + "height": 70.66668701171874, + "seed": 1040624571, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "cl6Duxg7hC4_1chb5YNau", + "type": "arrow" + } + ], + "updated": 1679639602774, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 41, + "versionNonce": 926996117, + "isDeleted": false, + "id": "eQrRfUHvRypTcFfQ80nK5", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 647.0000610351562, + "y": 219.33328247070312, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 91, + "height": 20, + "seed": 1884598901, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "cl6Duxg7hC4_1chb5YNau", + "type": "arrow" + } + ], + "updated": 1679639602774, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "prev_frame", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "prev_frame" + }, + { + "type": "diamond", + "version": 32, + "versionNonce": 784602165, + "isDeleted": false, + "id": "w_RQs6dyVbTAM3iaX46G2", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 632.6668701171875, + "y": 216.33322143554688, + "strokeColor": "#000000", + "backgroundColor": "#12b886", + "width": 11.66668701171875, + "height": 17, + "seed": 1918737243, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1679639598842, + "link": null, + "locked": false + }, + { + "type": "arrow", + "version": 135, + "versionNonce": 1953671957, + "isDeleted": false, + "id": "cl6Duxg7hC4_1chb5YNau", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 639.0001525878906, + "y": 224.16659545898438, + "strokeColor": "#000000", + "backgroundColor": "#12b886", + "width": 80.33334350585938, + "height": 95, + "seed": 509490587, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1679639608498, + "link": null, + "locked": false, + "startBinding": { + "elementId": "eQrRfUHvRypTcFfQ80nK5", + "focus": -0.7568501325114791, + "gap": 7.999908447265625 + }, + "endBinding": { + "elementId": "Mv8lernCpH2jNrVrNfqm5", + "focus": 1.0067042515978792, + "gap": 1.666656494140625 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -80.33334350585938, + -53.66668701171875 + ], + [ + -53.66668701171875, + -95 + ] + ] + }, + { + "type": "text", + "version": 196, + "versionNonce": 1763609493, + "isDeleted": false, + "id": "7pum3cjupgQ0Fz7eY_3xD", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1026.33349609375, + "y": 123.83326721191406, + "strokeColor": "#000000", + "backgroundColor": "#12b886", + "width": 109, + "height": 20, + "seed": 1300737371, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679640276534, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "Stack bottom", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "Stack bottom" + }, + { + "type": "text", + "version": 310, + "versionNonce": 1972102043, + "isDeleted": false, + "id": "Su_2hWwLvhW5W8cNMx6hT", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1030.666748046875, + "y": 266.8333206176758, + "strokeColor": "#000000", + "backgroundColor": "#12b886", + "width": 110, + "height": 20, + "seed": 2131950293, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679640279741, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "current frame", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "current frame" + }, + { + "type": "rectangle", + "version": 181, + "versionNonce": 1099516792, + "isDeleted": false, + "id": "jCBotdnPaPF-NkuwgrLyd", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 582.3333129882812, + "y": 744.8332977294922, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 429.666748046875, + "height": 48.333343505859396, + "seed": 1136750491, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679706699607, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 167, + "versionNonce": 647398264, + "isDeleted": false, + "id": "BRMXHqjjvaWADtilYg0NV", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 784.3333740234375, + "y": 775.8333892822266, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 57, + "height": 20, + "seed": 415943189, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "KiC12zdfqG7zXRbctXGmT", + "type": "arrow" + } + ], + "updated": 1679706708714, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "Unused", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "Unused" + }, + { + "type": "text", + "version": 179, + "versionNonce": 1210985736, + "isDeleted": false, + "id": "6YoFb1tMeQkuEDMy5H4FV", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1018.6668090820312, + "y": 778.8333892822266, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 122, + "height": 20, + "seed": 1257872437, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679706711595, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "stack boundary", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "stack boundary" + }, + { + "type": "text", + "version": 174, + "versionNonce": 314437128, + "isDeleted": false, + "id": "_e0Yy4p4UD9MNJUym2U_N", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1025.6666259765625, + "y": 732.8335113525391, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 80, + "height": 20, + "seed": 521361589, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679706543901, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "stack top", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "stack top" + }, + { + "type": "rectangle", + "version": 126, + "versionNonce": 1927665272, + "isDeleted": false, + "id": "ATaMGJS9emfaD_vgxw4Wi", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 625.5619915078412, + "y": 621.4944998254441, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 358.66670227050787, + "height": 25.999969482421875, + "seed": 1247140509, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679706543901, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 268, + "versionNonce": 1190911752, + "isDeleted": false, + "id": "qlKC-UwDGQErtLa5oG6C3", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 625.3333740234375, + "y": 554.1666870117188, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 236, + "height": 20, + "seed": 1957232156, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679706639231, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "Wasm LOCALs (local.set/get):", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "Wasm LOCALs (local.set/get):" + }, + { + "type": "rectangle", + "version": 264, + "versionNonce": 500451192, + "isDeleted": false, + "id": "CnBSoD9DNI5Himd9gJXwV", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 787.8953006814252, + "y": 625.661102913823, + "strokeColor": "#000000", + "backgroundColor": "#40c057", + "width": 30.6666259765625, + "height": 19.000091552734375, + "seed": 1737116886, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679706543901, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 259, + "versionNonce": 235932680, + "isDeleted": false, + "id": "z4Ye9_zQDUab5ewn2mujX", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 827.5619876931439, + "y": 623.9944159021043, + "strokeColor": "#000000", + "backgroundColor": "#40c057", + "width": 30.6666259765625, + "height": 19.000091552734375, + "seed": 1207868746, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679706543901, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 292, + "versionNonce": 600610936, + "isDeleted": false, + "id": "V3_r6rtZsp-pFDhmttdsh", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 865.5620487283002, + "y": 625.3277594079636, + "strokeColor": "#000000", + "backgroundColor": "#40c057", + "width": 30.6666259765625, + "height": 19.000091552734375, + "seed": 974809482, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679706543901, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 266, + "versionNonce": 1061243656, + "isDeleted": false, + "id": "Tov8P7W3W8Zmma9a3S8gP", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 904.5620487283002, + "y": 626.661102913823, + "strokeColor": "#000000", + "backgroundColor": "#40c057", + "width": 30.6666259765625, + "height": 19.000091552734375, + "seed": 1423773654, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679706543901, + "link": null, + "locked": false + }, + { + "type": "arrow", + "version": 148, + "versionNonce": 1167673464, + "isDeleted": false, + "id": "KiC12zdfqG7zXRbctXGmT", + "fillStyle": "hachure", + "strokeWidth": 4, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 806.4613995527118, + "y": 748.8279119958543, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 2.161352857758061, + "height": 20.33328247070324, + "seed": 167487754, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1679706706153, + "link": null, + "locked": false, + "startBinding": { + "elementId": "B1eH_aNspf4OoiXnvWu1V", + "focus": 0.026931962058821583, + "gap": 12.327789925541765 + }, + "endBinding": { + "elementId": "fxSjNN3geJtdm-2MR7INN", + "focus": -0.06989783256192499, + "gap": 24.16110291382313 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 2.161352857758061, + 20.33328247070324 + ] + ] + }, + { + "type": "text", + "version": 151, + "versionNonce": 1430888312, + "isDeleted": false, + "id": "wBnV18_fVimstqpfPY0KR", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 631.4456683895414, + "y": 624.6666107177734, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 91, + "height": 20, + "seed": 1961347080, + "groupIds": [], + "roundness": null, + "boundElements": null, + "updated": 1679706671751, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "func locals:", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "func locals:" + }, + { + "id": "8Y0Qz7jDPtVE84-d_UHu2", + "type": "rectangle", + "x": 613.2790118954008, + "y": 575.9999542236328, + "width": 384.0000305175781, + "height": 76.66668701171875, + "angle": 0, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "roundness": { + "type": 3 + }, + "seed": 743618568, + "version": 80, + "versionNonce": 129563000, + "isDeleted": false, + "boundElements": null, + "updated": 1679706644458, + "link": null, + "locked": false + } + ], + "appState": { + "gridSize": null, + "viewBackgroundColor": "#ffffff" + }, + "files": {} +} \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/doc/images/stack_format_ci.svg b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/doc/images/stack_format_ci.svg new file mode 100644 index 00000000000..f054c4345ae --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/doc/images/stack_format_ci.svg @@ -0,0 +1,16 @@ + + + + + + + prev_framefunc_inst ipopnd_stack_bottomopnd_sp (point to opnd stack top)label_stack_bottomlabel_sp (point to label stack top)func arguments:<operand stack>(current func instance) (next bytecode in codefor return)opnd_stack_boundarylabel_stack_boundary<lable stack>prev_frameStack bottomcurrent frameUnusedstack boundarystack topWasm LOCALs (local.set/get):func locals: \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/doc/images/wasm_exports.svg b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/doc/images/wasm_exports.svg new file mode 100644 index 00000000000..573f11c3514 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/doc/images/wasm_exports.svg @@ -0,0 +1,16 @@ + + + + + + + WASMModule WASMTable *tables; WASMMemory *memories; WASMGlobal *globals;WASMExport *exports;WASMExportchar *name;uint8 kind;uint32 index;[0][1][...]WASMModuleInstanceexport_tablesexport_memoriesexport_globalsexport_functionsWASMExportFuncInstancechar* name functionname: shown to externalindex: refer to item idx for export in current kindkind: total 4 export kinds:- function- globals- memory- table[1][0][...][n](refer to function diagam)export_func_countWASMExportGlobInstancechar* name global[1][0][...][n]WASMGlobalInstanceWASMExportMemInstancechar* name memory(WASMMemoryInstance*)[1][0][...][n]WASMMemoryInstanceWASMExportTabInstancechar* name table[1][0][...][n](WASMTableInstance *)WASMFunctionInstance[..]WASMFunction (per module)WASMModule::functionsWASMModule::globalsWASMModule::tablesWASMModule::memoriesWASMFunction **functions;export_global_countexport_memory_countexport_table_count \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/doc/images/wasm_function.excalidraw b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/doc/images/wasm_function.excalidraw new file mode 100644 index 00000000000..8c59bdbca29 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/doc/images/wasm_function.excalidraw @@ -0,0 +1,7754 @@ +{ + "type": "excalidraw", + "version": 2, + "source": "https://marketplace.visualstudio.com/items?itemName=pomdtr.excalidraw-editor", + "elements": [ + { + "type": "rectangle", + "version": 215, + "versionNonce": 1880133867, + "isDeleted": false, + "id": "4o9JHPgrKQSqK-ibc0qs_", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2254.5001678466797, + "y": 1663.1666412353516, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 150.66668701171875, + "height": 43.000030517578125, + "seed": 4270136, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "PsNatrhOR918YjbmvyT9x", + "type": "arrow" + } + ], + "updated": 1679533929331, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 230, + "versionNonce": 1135445829, + "isDeleted": false, + "id": "94gfo2BctxYsRP6cuuIbI", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1297.1946105957031, + "y": 1755.6666768391929, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 214.33333333333348, + "height": 122.66668701171875, + "seed": 305330883, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "9vnyulmvSUCDWXvSKKyJ6", + "type": "arrow" + } + ], + "updated": 1679533929331, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 162, + "versionNonce": 1027947403, + "isDeleted": false, + "id": "JWlL3nHzTP4pxrEVYolFx", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2226.416498184204, + "y": 1001.3333435058594, + "strokeColor": "#000000", + "backgroundColor": "#ced4da", + "width": 278.6666259765625, + "height": 244.00003051757812, + "seed": 1502608995, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "70jp9eV1jV2_kUBbN055m", + "type": "arrow" + } + ], + "updated": 1679533929331, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 115, + "versionNonce": 291919525, + "isDeleted": false, + "id": "Cc8lshSSJ7lAY4RPjzS5A", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1289.1666717529297, + "y": 1285.8333587646484, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 178, + "height": 20, + "seed": 411108936, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929331, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "WASMFunctionInstance", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "WASMFunctionInstance" + }, + { + "type": "rectangle", + "version": 100, + "versionNonce": 1607176747, + "isDeleted": false, + "id": "onh-wm6wgKrkH94fakl6O", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1291.1666107177734, + "y": 1309.1666717529297, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 259.33331298828125, + "height": 210.3333435058593, + "seed": 2073695304, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "fltFoJAyfls8KPkBw6X_P", + "type": "arrow" + }, + { + "id": "MLVyGZQLa4jU554J6bsmJ", + "type": "arrow" + } + ], + "updated": 1679533929331, + "link": null, + "locked": false + }, + { + "type": "diamond", + "version": 113, + "versionNonce": 34486789, + "isDeleted": false, + "id": "eAtZfC7P3ZafizTDITzz-", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1363.1666717529297, + "y": 1335.500015258789, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 10, + "height": 12.333343505859375, + "seed": 136923720, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929331, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 139, + "versionNonce": 411964619, + "isDeleted": false, + "id": "GmBiArFp8A3Q9NaPWxp3Q", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1395.8332977294922, + "y": 1332.8333587646484, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 94, + "height": 20, + "seed": 258177848, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "nUF7GyfmAGZN3iZvBfYtq", + "type": "arrow" + } + ], + "updated": 1679533929331, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "func_import", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "func_import" + }, + { + "type": "text", + "version": 239, + "versionNonce": 245543269, + "isDeleted": false, + "id": "YdCXv7DFgrOOU2wowasgm", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1748.499984741211, + "y": 1142.4999237060547, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 164, + "height": 20, + "seed": 1678600520, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929331, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "WASMFunctionImport:", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "WASMFunctionImport:" + }, + { + "type": "rectangle", + "version": 254, + "versionNonce": 656884587, + "isDeleted": false, + "id": "1Oi1iFkA8pBbaQpvduCq1", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1738.499984741211, + "y": 1161.1666717529297, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 176, + "height": 200.33340454101554, + "seed": 1244990536, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "nUF7GyfmAGZN3iZvBfYtq", + "type": "arrow" + } + ], + "updated": 1679533929331, + "link": null, + "locked": false + }, + { + "type": "arrow", + "version": 701, + "versionNonce": 879836357, + "isDeleted": false, + "id": "nUF7GyfmAGZN3iZvBfYtq", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1502.280048689805, + "y": 1332.5712493918486, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 234.84228393034437, + "height": 170.17912641351631, + "seed": 213606712, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1679533929331, + "link": null, + "locked": false, + "startBinding": { + "elementId": "GmBiArFp8A3Q9NaPWxp3Q", + "focus": 0.8789861743715494, + "gap": 14.558826765976846 + }, + "endBinding": { + "elementId": "w7-3leJjFtbtDhwDpkUjF", + "focus": 0.9853865103923569, + "gap": 6.774518257019281 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 157.46964422706515, + -143.2377075217314 + ], + [ + 234.84228393034437, + -170.17912641351631 + ] + ] + }, + { + "type": "text", + "version": 197, + "versionNonce": 1944165899, + "isDeleted": false, + "id": "bM6INpWVFBvURve3zdbdf", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1396.1666717529297, + "y": 1355.5000457763672, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 34, + "height": 20, + "seed": 379599688, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "78xSb96N8EcRm2LhdCNjJ", + "type": "arrow" + } + ], + "updated": 1679533929331, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "func", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "func" + }, + { + "type": "diamond", + "version": 140, + "versionNonce": 1796693029, + "isDeleted": false, + "id": "3cBYbIbQEyvFuXBMoyida", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1364.8332977294922, + "y": 1360.3333435058594, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 10, + "height": 12.333343505859375, + "seed": 1837623096, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929331, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 310, + "versionNonce": 2042078379, + "isDeleted": false, + "id": "9KTm6XzaqX3iZ90_AL3RN", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1900.8332977294922, + "y": 1530.166732788086, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 211, + "height": 20, + "seed": 1970637640, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "Bnf72M4RGMZjNgBlzk90B", + "type": "arrow" + }, + { + "id": "78xSb96N8EcRm2LhdCNjJ", + "type": "arrow" + }, + { + "id": "S1cN82-5SoSu4e4SWfAUw", + "type": "arrow" + } + ], + "updated": 1679533929331, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "WASMFunction (per module)", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "WASMFunction (per module)" + }, + { + "type": "rectangle", + "version": 261, + "versionNonce": 1518505861, + "isDeleted": false, + "id": "0kWlc6iPzGzhrfIVEPeOM", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1902.1667938232422, + "y": 1559.6667175292969, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 225.33337402343744, + "height": 200.9999389648438, + "seed": 2020723016, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "78xSb96N8EcRm2LhdCNjJ", + "type": "arrow" + }, + { + "id": "Bnf72M4RGMZjNgBlzk90B", + "type": "arrow" + }, + { + "id": "uC3ZSm-IltHDllxDGLJ9v", + "type": "arrow" + } + ], + "updated": 1679533929331, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 675, + "versionNonce": 1884542795, + "isDeleted": false, + "id": "zzj3BPEivUiaW1sqpfx7J", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2266.8334197998047, + "y": 1673.8333282470703, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 129, + "height": 20, + "seed": 26708536, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "78xSb96N8EcRm2LhdCNjJ", + "type": "arrow" + }, + { + "id": "PsNatrhOR918YjbmvyT9x", + "type": "arrow" + } + ], + "updated": 1679533929331, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "internal function", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "internal function" + }, + { + "type": "arrow", + "version": 666, + "versionNonce": 1357928165, + "isDeleted": false, + "id": "78xSb96N8EcRm2LhdCNjJ", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1434.5331571443298, + "y": 1377.528759465866, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 458.6267427864543, + "height": 186.82387510648414, + "seed": 535299656, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1679533929331, + "link": null, + "locked": false, + "startBinding": { + "elementId": "evHonaxVjRvjwFP08UX9x", + "focus": -0.827785929496437, + "gap": 16.471286310501227 + }, + "endBinding": { + "elementId": "9KTm6XzaqX3iZ90_AL3RN", + "focus": -1.317866862333605, + "gap": 14.985901784264229 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 184.63351460859985, + 58.63791228706373 + ], + [ + 458.6267427864543, + 186.82387510648414 + ] + ] + }, + { + "type": "rectangle", + "version": 145, + "versionNonce": 907064811, + "isDeleted": false, + "id": "WfHCEtd4eDaOU42FFn9wo", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1341.1666717529297, + "y": 1321.500015258789, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 186.00006103515625, + "height": 65, + "seed": 663703880, + "groupIds": [], + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "id": "78xSb96N8EcRm2LhdCNjJ", + "type": "arrow" + } + ], + "updated": 1679533929331, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 166, + "versionNonce": 2028876357, + "isDeleted": false, + "id": "QbAKq7kA_EZo7yxdpqj6F", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1742.499984741211, + "y": 1166.8332977294922, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 158.66668701171872, + "height": 45.33337402343752, + "seed": 757681480, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929331, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 170, + "versionNonce": 2046345355, + "isDeleted": false, + "id": "w7-3leJjFtbtDhwDpkUjF", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1715.499984741211, + "y": 1169.1666412353516, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 187, + "height": 40, + "seed": 1177365064, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "nUF7GyfmAGZN3iZvBfYtq", + "type": "arrow" + }, + { + "id": "70jp9eV1jV2_kUBbN055m", + "type": "arrow" + } + ], + "updated": 1679533929331, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": " char *module_name;\n char *field_name;", + "baseline": 34, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": " char *module_name;\n char *field_name;" + }, + { + "type": "rectangle", + "version": 190, + "versionNonce": 1331274149, + "isDeleted": false, + "id": "m6kQPfRjltByoJapP3m-h", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1744.499984741211, + "y": 1234.499984741211, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 155.33337402343747, + "height": 35.666656494140625, + "seed": 613948728, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929331, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 184, + "versionNonce": 633763627, + "isDeleted": false, + "id": "IXwlC5RgaF1iJPCtg6-Er", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1768.4999237060547, + "y": 1243.499984741211, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 125, + "height": 20, + "seed": 664043080, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "l4S1IXvHmVx_wl8DPQXk3", + "type": "arrow" + } + ], + "updated": 1679533929331, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "func_ptr_linked", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "func_ptr_linked" + }, + { + "type": "rectangle", + "version": 230, + "versionNonce": 1499473157, + "isDeleted": false, + "id": "o1vzUOCoilIzaDJdTpt35", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1735.8333587646484, + "y": 932.4999542236328, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 155.33331298828125, + "height": 90.33334350585938, + "seed": 1170302520, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "l4S1IXvHmVx_wl8DPQXk3", + "type": "arrow" + }, + { + "id": "j_Tg3JOansfDRNxNBUMfi", + "type": "arrow" + } + ], + "updated": 1679533929331, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 211, + "versionNonce": 132405707, + "isDeleted": false, + "id": "Kpjtivj-7LYLq1nuvC4KS", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1742.5000457763672, + "y": 940.8332977294922, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 123, + "height": 20, + "seed": 1541878344, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "l4S1IXvHmVx_wl8DPQXk3", + "type": "arrow" + }, + { + "id": "j_Tg3JOansfDRNxNBUMfi", + "type": "arrow" + } + ], + "updated": 1679533929331, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "native function:", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "native function:" + }, + { + "type": "arrow", + "version": 755, + "versionNonce": 444546149, + "isDeleted": false, + "id": "l4S1IXvHmVx_wl8DPQXk3", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1751.6334408235434, + "y": 1247.8332977294922, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 121.88354763506686, + "height": 307.57912212433075, + "seed": 203809096, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1679533929331, + "link": null, + "locked": false, + "startBinding": { + "elementId": "OpV38MM8YOexWG_e-5_hX", + "focus": -0.4013706262952343, + "gap": 1.943772417380456 + }, + "endBinding": { + "elementId": "Kpjtivj-7LYLq1nuvC4KS", + "focus": 1.1040701980735919, + "gap": 6.6751580517609455 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -121.88354763506686, + -191.16677856445312 + ], + [ + -15.808553098937182, + -307.57912212433075 + ] + ] + }, + { + "type": "rectangle", + "version": 185, + "versionNonce": 1030547563, + "isDeleted": false, + "id": "5EDlNHzjVbZ3Rx8ny3SUe", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1742.6665802001953, + "y": 1279.1666412353516, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 165.16677856445304, + "height": 73.666748046875, + "seed": 202955336, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929331, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 241, + "versionNonce": 1250191301, + "isDeleted": false, + "id": "wc-s6ecXMbmh2ViGrkOa4", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1757.8332977294922, + "y": 1289.5000457763672, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 152, + "height": 40, + "seed": 1536408648, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "S1cN82-5SoSu4e4SWfAUw", + "type": "arrow" + } + ], + "updated": 1679533929331, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "import_module;\nimport_func_linked;", + "baseline": 34, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "import_module;\nimport_func_linked;" + }, + { + "type": "arrow", + "version": 788, + "versionNonce": 1546298123, + "isDeleted": false, + "id": "S1cN82-5SoSu4e4SWfAUw", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1741.963485458681, + "y": 1322.4954523286892, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 248.14874440629774, + "height": 238.16542426722026, + "seed": 1657735240, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1679533929331, + "link": null, + "locked": false, + "startBinding": { + "elementId": "-vw33v9u2Ko2ayilI0CXG", + "focus": 2.0635763351494516, + "gap": 4.200185998866319 + }, + "endBinding": { + "elementId": "9KTm6XzaqX3iZ90_AL3RN", + "focus": -1.1514950968199016, + "gap": 11.294143807823616 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -88.79684422332912, + 88.33793695353734 + ], + [ + 159.35190018296862, + 238.16542426722026 + ] + ] + }, + { + "type": "text", + "version": 234, + "versionNonce": 1267541797, + "isDeleted": false, + "id": "jF8UBxFom2hco1NronB-_", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1639.2142922537669, + "y": 1510.404782976423, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 137, + "height": 20, + "seed": 548488008, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929331, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "(WASMFunction *)", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "(WASMFunction *)" + }, + { + "type": "diamond", + "version": 76, + "versionNonce": 1553467819, + "isDeleted": false, + "id": "jJOCFAslIe3JYgWsRnIKx", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1915.8334197998047, + "y": 1577.1667022705078, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 17.33331298828125, + "height": 15.666656494140625, + "seed": 1470386504, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [ + { + "id": "PsNatrhOR918YjbmvyT9x", + "type": "arrow" + } + ], + "updated": 1679533929331, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 88, + "versionNonce": 1611070085, + "isDeleted": false, + "id": "V1RSJPoudlOhc-GaAxPSa", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1947.8334197998047, + "y": 1577.500015258789, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 37, + "height": 20, + "seed": 1209849672, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "PsNatrhOR918YjbmvyT9x", + "type": "arrow" + } + ], + "updated": 1679533929331, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "code", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "code" + }, + { + "type": "rectangle", + "version": 217, + "versionNonce": 1138728011, + "isDeleted": false, + "id": "tXHmR9TBkCnxMdo_pd0XG", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2255.833480834961, + "y": 1603.1666412353516, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 149.3333740234375, + "height": 114.33340454101562, + "seed": 321892664, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929331, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 182, + "versionNonce": 548364773, + "isDeleted": false, + "id": "Zsg-OsrfZ2doJiTuOOpPu", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2277.166793823242, + "y": 1576.1666107177734, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 70, + "height": 20, + "seed": 40194872, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929331, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "bytecode", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "bytecode" + }, + { + "type": "arrow", + "version": 545, + "versionNonce": 232512235, + "isDeleted": false, + "id": "PsNatrhOR918YjbmvyT9x", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1990.5000762939453, + "y": 1589.1666717529297, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 264.9616597351928, + "height": 70.73153780068333, + "seed": 1716226360, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1679533929331, + "link": null, + "locked": false, + "startBinding": { + "elementId": "V1RSJPoudlOhc-GaAxPSa", + "focus": -0.13746287298855567, + "gap": 7.9146728515625 + }, + "endBinding": { + "elementId": "4o9JHPgrKQSqK-ibc0qs_", + "focus": 0.060950944035830956, + "gap": 3.268431681738548 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 149.9165802001953, + 22.1666259765625 + ], + [ + 191.24952507019043, + 48.83355712890625 + ], + [ + 264.9616597351928, + 70.73153780068333 + ] + ] + }, + { + "type": "diamond", + "version": 79, + "versionNonce": 848551237, + "isDeleted": false, + "id": "sWaZg1Dcn3g0Qfdc7onW_", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1916.5001068115234, + "y": 1629.8333892822266, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 18.6666259765625, + "height": 15, + "seed": 238700600, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929331, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 84, + "versionNonce": 1461142923, + "isDeleted": false, + "id": "U5NUD0rdNNDuY14J1ZRMu", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1954.8333587646484, + "y": 1628.8333892822266, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 110, + "height": 20, + "seed": 744475464, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929331, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "code_compiled", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "code_compiled" + }, + { + "type": "rectangle", + "version": 431, + "versionNonce": 1024584869, + "isDeleted": false, + "id": "gk39IBXF-F8MrwhzL35C6", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2462.5001068115234, + "y": 1639.5001373291016, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 114.66674804687503, + "height": 119.33334350585936, + "seed": 201839672, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929331, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 444, + "versionNonce": 1187798059, + "isDeleted": false, + "id": "ZRckuyHrC8P5etlpd8MWT", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2443.166793823242, + "y": 1616.833480834961, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 161, + "height": 20, + "seed": 2016979784, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929331, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "precompiled-bytecode", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "precompiled-bytecode" + }, + { + "type": "rectangle", + "version": 437, + "versionNonce": 534188037, + "isDeleted": false, + "id": "qGjmy62MZbL7zALsNU2dL", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2463.166793823242, + "y": 1699.5001373291016, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 114.00006103515625, + "height": 43.000030517578125, + "seed": 1165004088, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "iqe6U9xOE6ECb18moJnw-", + "type": "arrow" + } + ], + "updated": 1679533929331, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 68, + "versionNonce": 954572491, + "isDeleted": false, + "id": "SiZHwNA9YKd93iwc74wxB", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1942.4999542236328, + "y": 1667.833480834961, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 175, + "height": 20, + "seed": 1708294472, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "HCvGV6j45DG_BGeI3J7ut", + "type": "arrow" + } + ], + "updated": 1679533929331, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "fast_jit_jitted_code", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "fast_jit_jitted_code" + }, + { + "type": "diamond", + "version": 85, + "versionNonce": 1759561573, + "isDeleted": false, + "id": "ODI38iO5_5uu6RobQgkVa", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1912.499984741211, + "y": 1672.3333892822266, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 18.6666259765625, + "height": 15, + "seed": 297387080, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929332, + "link": null, + "locked": false + }, + { + "type": "diamond", + "version": 93, + "versionNonce": 670928235, + "isDeleted": false, + "id": "gNxfqnpn5KEfZX8dL5GX3", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1913.499984741211, + "y": 1717.666732788086, + "strokeColor": "#000000", + "backgroundColor": "#ced4da", + "width": 18.6666259765625, + "height": 15, + "seed": 1391035448, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929332, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 99, + "versionNonce": 175936197, + "isDeleted": false, + "id": "sYSDwbrpZl0692xpkcG4z", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1946.499984741211, + "y": 1713.166763305664, + "strokeColor": "#000000", + "backgroundColor": "#ced4da", + "width": 143, + "height": 20, + "seed": 1305637176, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "RckpORzYftIA2k4VSkTaW", + "type": "arrow" + } + ], + "updated": 1679533929332, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "llvm_jit_func_ptr", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "llvm_jit_func_ptr" + }, + { + "type": "text", + "version": 450, + "versionNonce": 1465821195, + "isDeleted": false, + "id": "1iUf8pP_YoM8qCPpSEahX", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2383.0000762939453, + "y": 1788.8333129882812, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 142, + "height": 20, + "seed": 68451128, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929332, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "fast jitted coode", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "fast jitted coode" + }, + { + "type": "rectangle", + "version": 501, + "versionNonce": 1363669541, + "isDeleted": false, + "id": "qVsRlSPxTl9a8XrnRMl2a", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2405.6665802001953, + "y": 1827.4999389648438, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 103.33337402343747, + "height": 29.2, + "seed": 1374549064, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "HCvGV6j45DG_BGeI3J7ut", + "type": "arrow" + }, + { + "id": "BF2h7Ub5gAf2yYxLfQSFh", + "type": "arrow" + } + ], + "updated": 1679533929332, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 447, + "versionNonce": 1023635115, + "isDeleted": false, + "id": "bu6GnR96DeCSFWu3DhMIJ", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2419.499954223633, + "y": 1890.1666870117188, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 133, + "height": 20, + "seed": 713214264, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "RckpORzYftIA2k4VSkTaW", + "type": "arrow" + }, + { + "id": "kjpM2qWJqDrV-jr9XK8QR", + "type": "arrow" + } + ], + "updated": 1679533929332, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "llvm jitted coode", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "llvm jitted coode" + }, + { + "type": "rectangle", + "version": 395, + "versionNonce": 439379333, + "isDeleted": false, + "id": "Z9cJSNSjDvW2uPNthdOW9", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2406.1666412353516, + "y": 1916.1666870117188, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 150.66668701171875, + "height": 43.000030517578125, + "seed": 1255376456, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "4E9MghnYo6hn8E82pmPMe", + "type": "arrow" + } + ], + "updated": 1679533929332, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 266, + "versionNonce": 731275595, + "isDeleted": false, + "id": "evHonaxVjRvjwFP08UX9x", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1335.1666259765625, + "y": 1394.0000457763672, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 187.33343505859372, + "height": 73.666748046875, + "seed": 873572680, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "78xSb96N8EcRm2LhdCNjJ", + "type": "arrow" + } + ], + "updated": 1679533929332, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 258, + "versionNonce": 1215524069, + "isDeleted": false, + "id": "4R5zAaFl-qG-PwNUPfyXq", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1360.4999389648438, + "y": 1404.6667022705078, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 157, + "height": 40, + "seed": 237924152, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929332, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "import_module_inst;\nimport_func_inst;", + "baseline": 34, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "import_module_inst;\nimport_func_inst;" + }, + { + "type": "diamond", + "version": 132, + "versionNonce": 1014104043, + "isDeleted": false, + "id": "-cXxAxf0DBRaXH85Wn82G", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1341.4998168945312, + "y": 1408.6666564941406, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 10, + "height": 12.333343505859375, + "seed": 1993562680, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "MLVyGZQLa4jU554J6bsmJ", + "type": "arrow" + }, + { + "id": "9vnyulmvSUCDWXvSKKyJ6", + "type": "arrow" + } + ], + "updated": 1679533929332, + "link": null, + "locked": false + }, + { + "type": "diamond", + "version": 136, + "versionNonce": 2073987141, + "isDeleted": false, + "id": "V3cEII-BWPnk8MmO8v9Hw", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1342.8331909179688, + "y": 1431.6666564941406, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 10, + "height": 12.333343505859375, + "seed": 374375752, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "MLVyGZQLa4jU554J6bsmJ", + "type": "arrow" + }, + { + "id": "9vnyulmvSUCDWXvSKKyJ6", + "type": "arrow" + } + ], + "updated": 1679533929332, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 196, + "versionNonce": 2040580747, + "isDeleted": false, + "id": "jccHI4GP5zADwZpJ6_F0e", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1020.4999542236328, + "y": 1294.5002899169922, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 132.66668701171866, + "height": 34.3333740234375, + "seed": 1209325128, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "type": "text", + "id": "eyNKBEqdZDGI0jikxT-7-" + } + ], + "updated": 1679533929332, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 28, + "versionNonce": 1577034445, + "isDeleted": false, + "id": "eyNKBEqdZDGI0jikxT-7-", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1050.8332977294922, + "y": 1302.066976928711, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 72, + "height": 20, + "seed": 13177699, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679537247195, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "functions", + "baseline": 14, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "jccHI4GP5zADwZpJ6_F0e", + "originalText": "functions" + }, + { + "type": "diamond", + "version": 157, + "versionNonce": 1205682475, + "isDeleted": false, + "id": "DpQKmgYqIbva-oudQDKVA", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1029.8332977294922, + "y": 1302.8336334228516, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 10.66668701171875, + "height": 17.666656494140625, + "seed": 1787304760, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "0dTwoTnwCJUbyz3e0bm1O", + "type": "arrow" + } + ], + "updated": 1679533929332, + "link": null, + "locked": false + }, + { + "type": "arrow", + "version": 460, + "versionNonce": 544406277, + "isDeleted": false, + "id": "fltFoJAyfls8KPkBw6X_P", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1152.0382824623548, + "y": 1307.393701716202, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 140.3213191272912, + "height": 0.8215748529805751, + "seed": 1890946120, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929332, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": { + "elementId": "onh-wm6wgKrkH94fakl6O", + "focus": 1.0244280280971265, + "gap": 2.5945448897082315 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 140.3213191272912, + -0.8215748529805751 + ] + ] + }, + { + "type": "rectangle", + "version": 245, + "versionNonce": 277996491, + "isDeleted": false, + "id": "BpsyACMObLF20Fkti2Uqq", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1020.8332061767578, + "y": 1339.000228881836, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 130.00000000000009, + "height": 31, + "seed": 1664170040, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "type": "text", + "id": "22kjCR2ZOQmZQXYgnarEF" + } + ], + "updated": 1679533929332, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 50, + "versionNonce": 1029340291, + "isDeleted": false, + "id": "22kjCR2ZOQmZQXYgnarEF", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "dotted", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1058.3332061767578, + "y": 1344.900228881836, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 55, + "height": 20, + "seed": 1753405955, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679537247196, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "globals", + "baseline": 14, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "BpsyACMObLF20Fkti2Uqq", + "originalText": "globals" + }, + { + "type": "diamond", + "version": 201, + "versionNonce": 735654507, + "isDeleted": false, + "id": "66O-4o40vS3pLIeBqwFBW", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1030.1665802001953, + "y": 1344.000228881836, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 10.66668701171875, + "height": 17.666656494140625, + "seed": 231180104, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929332, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 336, + "versionNonce": 2136587717, + "isDeleted": false, + "id": "l2Sz8ohFcHQT7gWys1M9D", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 751.1665802001953, + "y": 1311.6668853759766, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 158, + "height": 32, + "seed": 1571295288, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "type": "text", + "id": "o-cON41NQVHvHqkgeW_6m" + }, + { + "id": "0dTwoTnwCJUbyz3e0bm1O", + "type": "arrow" + } + ], + "updated": 1679533929332, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 115, + "versionNonce": 956023085, + "isDeleted": false, + "id": "o-cON41NQVHvHqkgeW_6m", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 824.6665802001953, + "y": 1317.1668853759766, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 11, + "height": 20, + "seed": 1939939267, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679537247196, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "e", + "baseline": 14, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "l2Sz8ohFcHQT7gWys1M9D", + "originalText": "e" + }, + { + "type": "diamond", + "version": 340, + "versionNonce": 659012901, + "isDeleted": false, + "id": "_eiwTSAQSXB8P2k-PDhNa", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 769.8332061767578, + "y": 1323.6668548583984, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 10.66668701171875, + "height": 17.666656494140625, + "seed": 1019883336, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "0dTwoTnwCJUbyz3e0bm1O", + "type": "arrow" + } + ], + "updated": 1679533929332, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 238, + "versionNonce": 536466347, + "isDeleted": false, + "id": "OLHiYmF0KqdbZBgecyb7T", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1017.1665802001953, + "y": 1430.6669158935547, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 131.33337402343759, + "height": 32.33331298828125, + "seed": 1564507192, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929332, + "link": null, + "locked": false + }, + { + "type": "diamond", + "version": 172, + "versionNonce": 1409208453, + "isDeleted": false, + "id": "qUAVJJGhHiEU00yvj5Xwy", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1041.1665802001953, + "y": 1438.3335723876953, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 10.66668701171875, + "height": 17.666656494140625, + "seed": 1916699464, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929332, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 170, + "versionNonce": 209200715, + "isDeleted": false, + "id": "ZzKApm4TYPqV3EGJbMuQ3", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1001.6664886474609, + "y": 1253.9168853759766, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 214, + "height": 20, + "seed": 1061991496, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929332, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "WASMModuleInstanceExtra", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "WASMModuleInstanceExtra" + }, + { + "type": "rectangle", + "version": 195, + "versionNonce": 859600869, + "isDeleted": false, + "id": "SWgPVXvgjtN7AVlTfBUDR", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1009.2498474121094, + "y": 1279.9169082641602, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 155, + "height": 200.41667938232422, + "seed": 1419979080, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "0dTwoTnwCJUbyz3e0bm1O", + "type": "arrow" + } + ], + "updated": 1679533929332, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 389, + "versionNonce": 114500843, + "isDeleted": false, + "id": "3rcvtpnHrIvCrE__yw5GU", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1339.5831756591797, + "y": 1031.000186920166, + "strokeColor": "#d9480f", + "backgroundColor": "transparent", + "width": 174, + "height": 40, + "seed": 1610110792, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "AuwWYqGK5XChc2C2ZDCOd", + "type": "arrow" + } + ], + "updated": 1679533929332, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "WASMModuleInstance::\nimport_func_ptrs", + "baseline": 34, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "WASMModuleInstance::\nimport_func_ptrs" + }, + { + "type": "rectangle", + "version": 137, + "versionNonce": 1594766149, + "isDeleted": false, + "id": "IK-a-uPI373j3VM1YHdKy", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1390.1666870117188, + "y": 1107.625286102295, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 48, + "height": 29, + "seed": 1938455864, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "dA4sHNYw9NqC0yRSl1ByC", + "type": "arrow" + }, + { + "id": "AuwWYqGK5XChc2C2ZDCOd", + "type": "arrow" + } + ], + "updated": 1679533929332, + "link": null, + "locked": false + }, + { + "type": "diamond", + "version": 123, + "versionNonce": 110448523, + "isDeleted": false, + "id": "xEmeSz_qg3vcIV0Kjo_4r", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1414.1666870117188, + "y": 1115.2919425964355, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 10.66668701171875, + "height": 17.666656494140625, + "seed": 1045500488, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "AuwWYqGK5XChc2C2ZDCOd", + "type": "arrow" + }, + { + "id": "j_Tg3JOansfDRNxNBUMfi", + "type": "arrow" + } + ], + "updated": 1679533929332, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 158, + "versionNonce": 1406239397, + "isDeleted": false, + "id": "u6aTea5vKrjtv4E0SAr_D", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1389.8333129882812, + "y": 1140.7919120788574, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 48, + "height": 29, + "seed": 1488328248, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "j_Tg3JOansfDRNxNBUMfi", + "type": "arrow" + } + ], + "updated": 1679533929332, + "link": null, + "locked": false + }, + { + "type": "diamond", + "version": 144, + "versionNonce": 771302955, + "isDeleted": false, + "id": "6petv8iQ_6W4RCCyGVs86", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1413.8333129882812, + "y": 1148.458568572998, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 10.66668701171875, + "height": 17.666656494140625, + "seed": 1174899016, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "j_Tg3JOansfDRNxNBUMfi", + "type": "arrow" + } + ], + "updated": 1679533929332, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 146, + "versionNonce": 640935429, + "isDeleted": false, + "id": "HWwjwJX9MC7vOni7CdfwU", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1389.5, + "y": 1174.1252555847168, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 48, + "height": 29, + "seed": 654741304, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "j_Tg3JOansfDRNxNBUMfi", + "type": "arrow" + } + ], + "updated": 1679533929332, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 158, + "versionNonce": 1944660171, + "isDeleted": false, + "id": "3V6VqEBHUeHRXm4rtMN9P", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1388.1666259765625, + "y": 1201.7919120788574, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 48, + "height": 29, + "seed": 652208184, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929332, + "link": null, + "locked": false + }, + { + "type": "diamond", + "version": 138, + "versionNonce": 2033376613, + "isDeleted": false, + "id": "s3LweJMlqb3u8zFFOtRWC", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1410.8333129882812, + "y": 1210.1252555847168, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 10.66668701171875, + "height": 17.666656494140625, + "seed": 630970184, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929332, + "link": null, + "locked": false + }, + { + "type": "arrow", + "version": 748, + "versionNonce": 234870635, + "isDeleted": false, + "id": "j_Tg3JOansfDRNxNBUMfi", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1423.3266279235036, + "y": 1116.6584335466105, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 310.5923414580757, + "height": 177.73696684706545, + "seed": 561180216, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1679533929332, + "link": null, + "locked": false, + "startBinding": { + "elementId": "xEmeSz_qg3vcIV0Kjo_4r", + "focus": -0.6524247058306003, + "gap": 2.5695135809208747 + }, + "endBinding": { + "elementId": "Kpjtivj-7LYLq1nuvC4KS", + "focus": 1.1530360747961412, + "gap": 8.581076394787942 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 125.75645618294175, + -55.99185334641493 + ], + [ + 310.5923414580757, + -177.73696684706545 + ] + ] + }, + { + "type": "diamond", + "version": 115, + "versionNonce": 874244293, + "isDeleted": false, + "id": "SosCUEMFvN64e8eYhtj4S", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1748.0836486816406, + "y": 1289.8335762023926, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 8.333282470703125, + "height": 13.75, + "seed": 1668126536, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "S1cN82-5SoSu4e4SWfAUw", + "type": "arrow" + } + ], + "updated": 1679533929332, + "link": null, + "locked": false + }, + { + "type": "diamond", + "version": 119, + "versionNonce": 445100555, + "isDeleted": false, + "id": "-vw33v9u2Ko2ayilI0CXG", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1745.5836486816406, + "y": 1319.8335762023926, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 10.833282470703125, + "height": 9.583320617675781, + "seed": 2012578120, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "S1cN82-5SoSu4e4SWfAUw", + "type": "arrow" + } + ], + "updated": 1679533929332, + "link": null, + "locked": false + }, + { + "type": "arrow", + "version": 648, + "versionNonce": 2022475813, + "isDeleted": false, + "id": "MLVyGZQLa4jU554J6bsmJ", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1347.8331909179688, + "y": 1415.2017225151058, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 179.41659545898438, + "height": 304.1667256414903, + "seed": 1591654456, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1679533929332, + "link": null, + "locked": false, + "startBinding": { + "elementId": "V3cEII-BWPnk8MmO8v9Hw", + "focus": 3.669987091693772, + "gap": 10.369642504898593 + }, + "endBinding": { + "elementId": "Rcref7JZ-AhlcXLLdwY5D", + "focus": -0.4568695235814372, + "gap": 6.321478788304148 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -179.41659545898438, + 169.4649187202458 + ], + [ + -89.48586426600582, + 304.1667256414903 + ] + ] + }, + { + "type": "text", + "version": 807, + "versionNonce": 175847595, + "isDeleted": false, + "id": "tUs9waDW6sL0AbyoZYJ5Q", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 867.8295186360679, + "y": 823.9724260965983, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 672, + "height": 160, + "seed": 709576760, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929332, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "this is the one actually referred during executing opcode\n\nduring model load, if import can be solved through the native api registeration,\nthe pointer of native function will be filled.\n\nc-api could change the pointer later, then it will point to a different native function\n\nNULL: means multi-module import, go to \"import_func_inst\" field for target function", + "baseline": 154, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "this is the one actually referred during executing opcode\n\nduring model load, if import can be solved through the native api registeration,\nthe pointer of native function will be filled.\n\nc-api could change the pointer later, then it will point to a different native function\n\nNULL: means multi-module import, go to \"import_func_inst\" field for target function" + }, + { + "type": "rectangle", + "version": 410, + "versionNonce": 1483881349, + "isDeleted": false, + "id": "kARKLR5va5hDwe-2JCl7d", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 855.623291015625, + "y": 824.4128579639253, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 691.1904471261159, + "height": 170.05954742431626, + "seed": 1355113288, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "AuwWYqGK5XChc2C2ZDCOd", + "type": "arrow" + }, + { + "id": "j_Tg3JOansfDRNxNBUMfi", + "type": "arrow" + } + ], + "updated": 1679533929332, + "link": null, + "locked": false + }, + { + "type": "arrow", + "version": 1427, + "versionNonce": 1267002187, + "isDeleted": false, + "id": "AuwWYqGK5XChc2C2ZDCOd", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1132.2583561737392, + "y": 997.6315427986297, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 188.93306844281233, + "height": 54.67370578283135, + "seed": 1524992312, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929332, + "link": null, + "locked": false, + "startBinding": { + "elementId": "kARKLR5va5hDwe-2JCl7d", + "gap": 3.1591374103880994, + "focus": 0.5842950344963632 + }, + "endBinding": { + "elementId": "3rcvtpnHrIvCrE__yw5GU", + "gap": 18.39175104262814, + "focus": -0.7039875993615579 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 188.93306844281233, + 54.67370578283135 + ] + ] + }, + { + "type": "text", + "version": 363, + "versionNonce": 1275757285, + "isDeleted": false, + "id": "_pYmb7H1lxRLE4Qw_MajA", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1034.3336715698242, + "y": 1680.4170036315918, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 176, + "height": 20, + "seed": 764509256, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929332, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "WASMModuleInstance*", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "WASMModuleInstance*" + }, + { + "type": "text", + "version": 314, + "versionNonce": 838814187, + "isDeleted": false, + "id": "GBXnnFKM_76tjt1WAlYnV", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1250.0279070536296, + "y": 1605.2504641215007, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 198, + "height": 20, + "seed": 1630119496, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "9vnyulmvSUCDWXvSKKyJ6", + "type": "arrow" + } + ], + "updated": 1679533929332, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "(WASMFunctionInstance*)", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "(WASMFunctionInstance*)" + }, + { + "type": "arrow", + "version": 881, + "versionNonce": 1742921285, + "isDeleted": false, + "id": "9vnyulmvSUCDWXvSKKyJ6", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1347.3662637658592, + "y": 1437.871212796838, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 109.83801974730454, + "height": 307.7636946939249, + "seed": 422577480, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1679533929332, + "link": null, + "locked": false, + "startBinding": { + "elementId": "-cXxAxf0DBRaXH85Wn82G", + "focus": -3.9115852992052806, + "gap": 11.29853538112821 + }, + "endBinding": { + "elementId": "94gfo2BctxYsRP6cuuIbI", + "gap": 10.033975741878294, + "focus": -0.6520703073991437 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -109.83801974730454, + 135.3790961936404 + ], + [ + -51.493209521376, + 307.7636946939249 + ] + ] + }, + { + "type": "diamond", + "version": 207, + "versionNonce": 2116029227, + "isDeleted": false, + "id": "kliwot061_yUhDMDbVbQe", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1354.3614679972331, + "y": 1779.417065938314, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 10, + "height": 12.333343505859375, + "seed": 82951992, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929332, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 233, + "versionNonce": 2082066693, + "isDeleted": false, + "id": "mvfNSPpLgMxaEaQuXYPrl", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1387.0280939737956, + "y": 1776.7504094441733, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 94, + "height": 20, + "seed": 1266085960, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929332, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "func_import", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "func_import" + }, + { + "type": "text", + "version": 265, + "versionNonce": 1206611403, + "isDeleted": false, + "id": "Oe13Ts1dEazuz8ilwnZiL", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1398.6947809855144, + "y": 1806.7504094441733, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 34, + "height": 20, + "seed": 2145720376, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929332, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "func", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "func" + }, + { + "type": "diamond", + "version": 230, + "versionNonce": 287533157, + "isDeleted": false, + "id": "nyquujDKZGyYvDs-a_GQ-", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1356.0280939737956, + "y": 1811.5837071736655, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 10, + "height": 12.333343505859375, + "seed": 784443208, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929332, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 252, + "versionNonce": 326204523, + "isDeleted": false, + "id": "cGQYK5rXelrtuGolytFol", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1332.3614679972331, + "y": 1765.417065938314, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 154.00006103515616, + "height": 79, + "seed": 1426411832, + "groupIds": [], + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "id": "9vnyulmvSUCDWXvSKKyJ6", + "type": "arrow" + } + ], + "updated": 1679533929332, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 521, + "versionNonce": 868422597, + "isDeleted": false, + "id": "VRweEUgFB9qqzjdTwpHnK", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1323.694574991862, + "y": 1739.194897969564, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 117, + "height": 20, + "seed": 155802936, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929332, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "WASMFunction ", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "WASMFunction " + }, + { + "type": "arrow", + "version": 621, + "versionNonce": 746370827, + "isDeleted": false, + "id": "CUEfVWpVIuIHc_5h3VskN", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1459.8716446745273, + "y": 1829.1380187988277, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 394.2706533635544, + "height": 82.19527893066447, + "seed": 1854588984, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1679533929333, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": { + "elementId": "epVvbDyPF40MaERFnDDJy", + "focus": 0.2506598246466399, + "gap": 9.849883651733307 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 153.21163779617586, + 82.19527893066447 + ], + [ + 394.2706533635544, + 27.990782200797412 + ] + ] + }, + { + "type": "text", + "version": 309, + "versionNonce": 1880511269, + "isDeleted": false, + "id": "OTP338ttAjF_rIJwNKA1S", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1298.416748046875, + "y": 1343.3333587646484, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 38, + "height": 20, + "seed": 1994699981, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929333, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "union", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "union" + }, + { + "type": "rectangle", + "version": 62, + "versionNonce": 25664939, + "isDeleted": false, + "id": "7kmKkWcfD2eeTgLmci_TA", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1289.75, + "y": 1517.3333282470703, + "strokeColor": "#000000", + "backgroundColor": "#fab005", + "width": 260.66668701171875, + "height": 61.333343505859375, + "seed": 1810842211, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "type": "text", + "id": "fr9-3bNKWz24759an1jPs" + } + ], + "updated": 1679533929333, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 13, + "versionNonce": 914224163, + "isDeleted": false, + "id": "fr9-3bNKWz24759an1jPs", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "dotted", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1404.5833435058594, + "y": 1538.4, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 31, + "height": 20, + "seed": 1884299875, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679537247200, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "[...]", + "baseline": 14, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "7kmKkWcfD2eeTgLmci_TA", + "originalText": "[...]" + }, + { + "type": "line", + "version": 176, + "versionNonce": 1373083019, + "isDeleted": false, + "id": "pYd8BNqe32DQ1BK15gl1X", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "dotted", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1607.7500610351565, + "y": 911.2331604003898, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 2.2737367544323206e-13, + "height": 1207.7780151367188, + "seed": 1889947117, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533932559, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": null, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": null, + "points": [ + [ + 0, + 0 + ], + [ + -2.2737367544323206e-13, + 1207.7780151367188 + ] + ] + }, + { + "type": "text", + "version": 58, + "versionNonce": 2111671781, + "isDeleted": false, + "id": "-EA8TtLR5unZFdjT-k9mq", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "dotted", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1404.4167785644531, + "y": 1492.6665802001953, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 29, + "height": 20, + "seed": 1174452173, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929333, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "[0]", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "[0]" + }, + { + "type": "text", + "version": 225, + "versionNonce": 49704683, + "isDeleted": false, + "id": "al3s0Ce-XZ_FiU84jmv0f", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 729.2799504597981, + "y": 1209.9554656982423, + "strokeColor": "#e67700", + "backgroundColor": "transparent", + "width": 171, + "height": 19, + "seed": 1330045933, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929333, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 3, + "text": "WASMModuleInstance", + "baseline": 15, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "WASMModuleInstance" + }, + { + "type": "rectangle", + "version": 102, + "versionNonce": 555518277, + "isDeleted": false, + "id": "TxSoCCktw7hU7jU0cN2he", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 723.0834655761719, + "y": 1240.9998931884766, + "strokeColor": "#d9480f", + "backgroundColor": "transparent", + "width": 210.66668701171875, + "height": 305.33334350585943, + "seed": 598232163, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929333, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 113, + "versionNonce": 1941920139, + "isDeleted": false, + "id": "uyhu5MiXRFgQansSAKgbz", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1858.638671875, + "y": 1857.11110941569, + "strokeColor": "#000000", + "backgroundColor": "#ced4da", + "width": 229.3333740234375, + "height": 71.33331298828125, + "seed": 1064313101, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "type": "text", + "id": "4W7-B8UsG2Kp0-6eEN0-h" + }, + { + "id": "CUEfVWpVIuIHc_5h3VskN", + "type": "arrow" + } + ], + "updated": 1679533929333, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 67, + "versionNonce": 1873089421, + "isDeleted": false, + "id": "4W7-B8UsG2Kp0-6eEN0-h", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1959.8053588867188, + "y": 1883.1777659098307, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 27, + "height": 20, + "seed": 1206387267, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679537247203, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "[..]", + "baseline": 14, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "uyhu5MiXRFgQansSAKgbz", + "originalText": "[..]" + }, + { + "type": "arrow", + "version": 335, + "versionNonce": 1028780075, + "isDeleted": false, + "id": "0dTwoTnwCJUbyz3e0bm1O", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 780.7038274166374, + "y": 1329.8562414550568, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 227.1615634556406, + "height": 49.895659740248675, + "seed": 1282951939, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929333, + "link": null, + "locked": false, + "startBinding": { + "elementId": "_eiwTSAQSXB8P2k-PDhNa", + "focus": -0.16162303890895813, + "gap": 1.5411549516792498 + }, + "endBinding": { + "elementId": "SWgPVXvgjtN7AVlTfBUDR", + "focus": 1.0022214255263049, + "gap": 1.3844565398313762 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 227.1615634556406, + -49.895659740248675 + ] + ] + }, + { + "type": "rectangle", + "version": 380, + "versionNonce": 1831123973, + "isDeleted": false, + "id": "EjfvS52mTJV_ntE7FAmqi", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 749.41650390625, + "y": 1265.500015258789, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 163, + "height": 38.333343505859375, + "seed": 908455875, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "0dTwoTnwCJUbyz3e0bm1O", + "type": "arrow" + } + ], + "updated": 1679533929333, + "link": null, + "locked": false + }, + { + "type": "diamond", + "version": 372, + "versionNonce": 395899749, + "isDeleted": false, + "id": "0n8DknkuWXlRynFJmYm-N", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 760.0831298828125, + "y": 1276.500015258789, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 10.66668701171875, + "height": 17.666656494140625, + "seed": 1140391779, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "dA4sHNYw9NqC0yRSl1ByC", + "type": "arrow" + } + ], + "updated": 1679533929333, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 131, + "versionNonce": 169804459, + "isDeleted": false, + "id": "xwVumJFL4-d-8BM7nSKzG", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1406.5276896158855, + "y": 1849.9999745686848, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 25, + "height": 20, + "seed": 813534477, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929333, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "[n]", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "[n]" + }, + { + "type": "arrow", + "version": 164, + "versionNonce": 1833439621, + "isDeleted": false, + "id": "dA4sHNYw9NqC0yRSl1ByC", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 767.0830841064453, + "y": 1278.6665496826172, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 617.3333435058594, + "height": 168.00003051757812, + "seed": 1360269091, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1679533929333, + "link": null, + "locked": false, + "startBinding": { + "elementId": "0n8DknkuWXlRynFJmYm-N", + "focus": -0.6970200254594874, + "gap": 1 + }, + "endBinding": { + "elementId": "IK-a-uPI373j3VM1YHdKy", + "focus": 0.91934006004951, + "gap": 5.7502593994140625 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 283.33331298828125, + -86.66671752929688 + ], + [ + 617.3333435058594, + -168.00003051757812 + ] + ] + }, + { + "type": "text", + "version": 370, + "versionNonce": 2015327563, + "isDeleted": false, + "id": "1uhr4l-w9t4eVo0gQ06SH", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1628.0831146240234, + "y": 1047.333236694336, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 60, + "height": 20, + "seed": 2127932547, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "70jp9eV1jV2_kUBbN055m", + "type": "arrow" + } + ], + "updated": 1679533929333, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "(void *)", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "(void *)" + }, + { + "type": "diamond", + "version": 110, + "versionNonce": 867539173, + "isDeleted": false, + "id": "OpV38MM8YOexWG_e-5_hX", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1751.5831604003906, + "y": 1244.7915496826172, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 8.333282470703125, + "height": 13.75, + "seed": 1876974509, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "l4S1IXvHmVx_wl8DPQXk3", + "type": "arrow" + } + ], + "updated": 1679533929333, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 201, + "versionNonce": 1052283883, + "isDeleted": false, + "id": "0VYDhNUTpNaSbemsP54Zy", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 982.6778793334961, + "y": 1174.3998931884767, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 68, + "height": 20, + "seed": 2080172771, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929333, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "(void **)", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "(void **)" + }, + { + "type": "text", + "version": 52, + "versionNonce": 364590149, + "isDeleted": false, + "id": "mEKNbQ7XuwA2N2CRqO86h", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1395.7501068115234, + "y": 1178.6665954589844, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 43, + "height": 20, + "seed": 95270211, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929333, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "NULL", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "NULL" + }, + { + "type": "rectangle", + "version": 348, + "versionNonce": 306207333, + "isDeleted": false, + "id": "FKonkUbaqKFXKyt5VSiGE", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 743.0831654866537, + "y": 1476.5000508626301, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 174.66668701171875, + "height": 31.666625976562507, + "seed": 710825357, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "0dTwoTnwCJUbyz3e0bm1O", + "type": "arrow" + } + ], + "updated": 1679533956228, + "link": null, + "locked": false + }, + { + "type": "diamond", + "version": 376, + "versionNonce": 1951705707, + "isDeleted": false, + "id": "xNodTFHQFtS6jmRfbZDpo", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 748.4164784749349, + "y": 1484.1667073567708, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 10.66668701171875, + "height": 17.666656494140625, + "seed": 1417026541, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533956228, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 82, + "versionNonce": 678544837, + "isDeleted": false, + "id": "8i8vmtgsTLeEQt_E_hLrk", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 768.4165089925131, + "y": 1481.0000508626301, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 149, + "height": 20, + "seed": 1944091203, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "yu3un9i0kAGrZ8bAnVMa3", + "type": "arrow" + } + ], + "updated": 1679533956228, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "func_type_indexes", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "func_type_indexes" + }, + { + "type": "rectangle", + "version": 210, + "versionNonce": 1441855435, + "isDeleted": false, + "id": "IwrJYgHbhcHGM-MPt77v3", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 907.3989664713541, + "y": 1609.9723409016926, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 48, + "height": 29, + "seed": 919532995, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929333, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 230, + "versionNonce": 2006154853, + "isDeleted": false, + "id": "XRMQmYFkm-FtbS8PBuF_X", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 907.0655924479166, + "y": 1643.1389668782551, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 48, + "height": 29, + "seed": 361842019, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929333, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 218, + "versionNonce": 473286251, + "isDeleted": false, + "id": "nsMfEXFd6IeqB7fL4ngUa", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 906.7322794596354, + "y": 1676.4723103841145, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 48, + "height": 29, + "seed": 1923653891, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929333, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 227, + "versionNonce": 1069574597, + "isDeleted": false, + "id": "R5ioSAhKEdUlCurXbrHuN", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 905.3989054361979, + "y": 1704.1389668782551, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 48, + "height": 29, + "seed": 1469286563, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929333, + "link": null, + "locked": false + }, + { + "type": "arrow", + "version": 323, + "versionNonce": 617227531, + "isDeleted": false, + "id": "yu3un9i0kAGrZ8bAnVMa3", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 753.0831654866537, + "y": 1487.6672379829788, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 200.16657758128372, + "height": 153.3329247774377, + "seed": 1439562723, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1679533956229, + "link": null, + "locked": false, + "startBinding": { + "elementId": "8i8vmtgsTLeEQt_E_hLrk", + "focus": 1.0014597510870404, + "gap": 15.333343505859375 + }, + "endBinding": { + "elementId": "p5TPteQC3PraRMJtt4XsT", + "focus": 0.36261877029011863, + "gap": 3.9746450546211918 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -60.000050862630246, + 26.332884087333696 + ], + [ + -40.88889567057288, + 105.11070594605758 + ], + [ + 62.88881429036462, + 153.3329247774377 + ], + [ + 140.16652671865347, + 150.58490939994954 + ] + ] + }, + { + "type": "text", + "version": 99, + "versionNonce": 2113464613, + "isDeleted": false, + "id": "a8gv4R6T3PYjKJhay9vMv", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 802.4165191650391, + "y": 1604.7780354817708, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 70, + "height": 20, + "seed": 453646061, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929333, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "uint32 *", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "uint32 *" + }, + { + "type": "text", + "version": 97, + "versionNonce": 692152235, + "isDeleted": false, + "id": "eNJLe1mhF_AWRUyt9lO6k", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2227.083185195923, + "y": 955.9999694824219, + "strokeColor": "#1864ab", + "backgroundColor": "transparent", + "width": 96, + "height": 19, + "seed": 1711184323, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929333, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 3, + "text": "WASMModule", + "baseline": 15, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "WASMModule" + }, + { + "type": "rectangle", + "version": 247, + "versionNonce": 329940101, + "isDeleted": false, + "id": "25KRboddeZem953trnn-R", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2216.416498184204, + "y": 985.9999389648438, + "strokeColor": "#1864ab", + "backgroundColor": "transparent", + "width": 308, + "height": 568, + "seed": 847170787, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929333, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 135, + "versionNonce": 799881803, + "isDeleted": false, + "id": "NnvrV9DcfaaiOCGPUdP78", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2229.083246231079, + "y": 1003.3333129882812, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 263, + "height": 224, + "seed": 2117157197, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929333, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 2, + "text": " WASMImport *import_tables;\n WASMImport *import_memories;\n WASMImport *import_globals;\n\n WASMType **types;\n WASMImport *imports;\n WASMTable *tables;\n WASMMemory *memories;\n WASMGlobal *globals;\n WASMExport *exports;\n WASMTableSeg *table_segments;\n WASMDataSeg **data_segments;", + "baseline": 220, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": " WASMImport *import_tables;\n WASMImport *import_memories;\n WASMImport *import_globals;\n\n WASMType **types;\n WASMImport *imports;\n WASMTable *tables;\n WASMMemory *memories;\n WASMGlobal *globals;\n WASMExport *exports;\n WASMTableSeg *table_segments;\n WASMDataSeg **data_segments;" + }, + { + "type": "rectangle", + "version": 123, + "versionNonce": 1486005221, + "isDeleted": false, + "id": "O5y5oOsgUB5ue4vWSQB0i", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2232.4165592193604, + "y": 1301.3332824707031, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 273.3333740234375, + "height": 44, + "seed": 1988414157, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929333, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 145, + "versionNonce": 709212395, + "isDeleted": false, + "id": "6xufIeHeKpvDChXCTeKSb", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2294.4165592193604, + "y": 1314.6665954589844, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 198, + "height": 19, + "seed": 2026661485, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929333, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 2, + "text": "WASMFunction **functions;", + "baseline": 15, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "WASMFunction **functions;" + }, + { + "type": "diamond", + "version": 108, + "versionNonce": 1354686277, + "isDeleted": false, + "id": "s4lQvHIN1eAAubp7DkNrk", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2245.083246231079, + "y": 1318, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 26.6666259765625, + "height": 19.333343505859375, + "seed": 1489582509, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "Bnf72M4RGMZjNgBlzk90B", + "type": "arrow" + } + ], + "updated": 1679533929333, + "link": null, + "locked": false + }, + { + "type": "arrow", + "version": 354, + "versionNonce": 1184195467, + "isDeleted": false, + "id": "Bnf72M4RGMZjNgBlzk90B", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2250.416437149048, + "y": 1332.0000305175781, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 163.1120623945253, + "height": 15.460472501937602, + "seed": 1550987139, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929333, + "link": null, + "locked": false, + "startBinding": { + "elementId": "s4lQvHIN1eAAubp7DkNrk", + "focus": -0.36983487209914556, + "gap": 1 + }, + "endBinding": { + "elementId": "swt6lb3ztkUJAvM41XHBK", + "focus": -0.7544161254824635, + "gap": 5.555002272222737 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -163.1120623945253, + 15.460472501937602 + ] + ] + }, + { + "type": "text", + "version": 138, + "versionNonce": 579645093, + "isDeleted": false, + "id": "TfktbM2ODt0uHXCbkJtbX", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2277.4166202545166, + "y": 1269.3333435058594, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 229, + "height": 19, + "seed": 2140950979, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929333, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 2, + "text": "WASMImport *import_functions;", + "baseline": 15, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "WASMImport *import_functions;" + }, + { + "type": "rectangle", + "version": 99, + "versionNonce": 483834411, + "isDeleted": false, + "id": "sIxEmRk_EPaTumCGaxM6t", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2231.749994277954, + "y": 1254.6667175292969, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 276, + "height": 42.6666259765625, + "seed": 2140310499, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929333, + "link": null, + "locked": false + }, + { + "type": "diamond", + "version": 86, + "versionNonce": 1286181381, + "isDeleted": false, + "id": "_er3JaiUwljITdxfog0w_", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2246.416742324829, + "y": 1265.3334045410156, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 15.33331298828125, + "height": 22.66668701171875, + "seed": 568056877, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929333, + "link": null, + "locked": false + }, + { + "type": "arrow", + "version": 453, + "versionNonce": 1509178571, + "isDeleted": false, + "id": "70jp9eV1jV2_kUBbN055m", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2253.0103282895525, + "y": 1275.9391811320388, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 323.49287390894006, + "height": 187.53914675447618, + "seed": 638625069, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1679533929333, + "link": null, + "locked": false, + "startBinding": { + "elementId": "JWlL3nHzTP4pxrEVYolFx", + "focus": -1.0762119763220488, + "gap": 30.60580710860131 + }, + "endBinding": { + "elementId": "1rZk-xFL82XSp5Mpcqy4f", + "focus": -1.2708836305762516, + "gap": 14.434116596798958 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -146.59352492956714, + -83.93927268477319 + ], + [ + -323.49287390894006, + -187.53914675447618 + ] + ] + }, + { + "type": "rectangle", + "version": 145, + "versionNonce": 471009637, + "isDeleted": false, + "id": "4BwxH9WndrjsXga95YTvm", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1705.7500858306885, + "y": 1086.6665954589844, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 222.6666259765625, + "height": 303.33331298828125, + "seed": 803769283, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "70jp9eV1jV2_kUBbN055m", + "type": "arrow" + }, + { + "id": "nUF7GyfmAGZN3iZvBfYtq", + "type": "arrow" + } + ], + "updated": 1679533929333, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 270, + "versionNonce": 696806251, + "isDeleted": false, + "id": "RR6mIlX4wkxcfcv6RQ8Wa", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1708.416711807251, + "y": 1062.6665954589844, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 97, + "height": 19, + "seed": 2042686211, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929333, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 2, + "text": "WASMImport", + "baseline": 15, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "WASMImport" + }, + { + "type": "rectangle", + "version": 191, + "versionNonce": 1645647045, + "isDeleted": false, + "id": "1rZk-xFL82XSp5Mpcqy4f", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1745.749963760376, + "y": 1097.3333129882812, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 169.3333740234375, + "height": 31, + "seed": 176484109, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "type": "text", + "id": "qkiSeaixB8ivmpNxhvY6l" + }, + { + "id": "70jp9eV1jV2_kUBbN055m", + "type": "arrow" + } + ], + "updated": 1679533929333, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 162, + "versionNonce": 395409347, + "isDeleted": false, + "id": "qkiSeaixB8ivmpNxhvY6l", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1750.749963760376, + "y": 1102.3333129882812, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 79, + "height": 20, + "seed": 2146735565, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679537247208, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "uint8 kind", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "middle", + "containerId": "1rZk-xFL82XSp5Mpcqy4f", + "originalText": "uint8 kind" + }, + { + "type": "rectangle", + "version": 175, + "versionNonce": 1783739429, + "isDeleted": false, + "id": "R_f4RWhd20C8JXmaJofMm", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1706.7500247955322, + "y": 1390.6665954589844, + "strokeColor": "#000000", + "backgroundColor": "#ced4da", + "width": 221, + "height": 31, + "seed": 691699363, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "type": "text", + "id": "jXOu2RGl7KTvcY3-hwIj2" + } + ], + "updated": 1679533929333, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 56, + "versionNonce": 2117409261, + "isDeleted": false, + "id": "jXOu2RGl7KTvcY3-hwIj2", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1806.2500247955322, + "y": 1396.0665954589845, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 22, + "height": 20, + "seed": 776900557, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679537247209, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "[1]", + "baseline": 14, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "R_f4RWhd20C8JXmaJofMm", + "originalText": "[1]" + }, + { + "type": "text", + "version": 51, + "versionNonce": 816965509, + "isDeleted": false, + "id": "JvLqnDwgx42bo19rINn18", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1807.083490371704, + "y": 1371.9998474121094, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 29, + "height": 20, + "seed": 2020174093, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929333, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "[0]", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "[0]" + }, + { + "type": "rectangle", + "version": 185, + "versionNonce": 1499856715, + "isDeleted": false, + "id": "Xj5n84LklLY7rIUbMpV30", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1708.2501163482666, + "y": 1422.3332061767578, + "strokeColor": "#000000", + "backgroundColor": "#ced4da", + "width": 221, + "height": 31, + "seed": 1499618403, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "type": "text", + "id": "LOWTAqc1KaVYNxnLkXHB4" + } + ], + "updated": 1679533929333, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 61, + "versionNonce": 2125694819, + "isDeleted": false, + "id": "LOWTAqc1KaVYNxnLkXHB4", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1803.2501163482666, + "y": 1427.733206176758, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 31, + "height": 20, + "seed": 701124429, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679537247210, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "[...]", + "baseline": 14, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "Xj5n84LklLY7rIUbMpV30", + "originalText": "[...]" + }, + { + "type": "rectangle", + "version": 50, + "versionNonce": 178118123, + "isDeleted": false, + "id": "qd-T97QOO_xa4SGTgkrAj", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1363.083200454712, + "y": 1076.0001373291016, + "strokeColor": "#d9480f", + "backgroundColor": "transparent", + "width": 96, + "height": 170.66668701171875, + "seed": 215655011, + "groupIds": [], + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "id": "AuwWYqGK5XChc2C2ZDCOd", + "type": "arrow" + } + ], + "updated": 1679533929333, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 169, + "versionNonce": 1562872389, + "isDeleted": false, + "id": "EAEAQzFaB6T9-rCB0X-61", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2303.749662399292, + "y": 1418.0001983642578, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 160, + "height": 20, + "seed": 1651418499, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929333, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "fast_jit_func_ptrs", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "fast_jit_func_ptrs" + }, + { + "type": "rectangle", + "version": 195, + "versionNonce": 312535179, + "isDeleted": false, + "id": "n3LUTZSRU6GJ4nfF98WsH", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2233.7496013641357, + "y": 1409.6669158935547, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 273.3333740234375, + "height": 44, + "seed": 1123016931, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929333, + "link": null, + "locked": false + }, + { + "type": "diamond", + "version": 173, + "versionNonce": 312998309, + "isDeleted": false, + "id": "SOlRVdTv-nHYKomLm0-Lr", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2246.749662399292, + "y": 1421.000244140625, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 26.6666259765625, + "height": 19.333343505859375, + "seed": 381478531, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929333, + "link": null, + "locked": false + }, + { + "type": "arrow", + "version": 61, + "versionNonce": 1193910059, + "isDeleted": false, + "id": "RckpORzYftIA2k4VSkTaW", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2093.082914352417, + "y": 1731.3334503173828, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 314.6666564941406, + "height": 191.3333740234375, + "seed": 1221862445, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1679533929334, + "link": null, + "locked": false, + "startBinding": { + "elementId": "sYSDwbrpZl0692xpkcG4z", + "focus": -0.8132904069013918, + "gap": 6.05506706237793 + }, + "endBinding": { + "elementId": "bu6GnR96DeCSFWu3DhMIJ", + "focus": -1.5131314965155, + "gap": 13.30013732910163 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 150.66665649414062, + 128.66668701171875 + ], + [ + 314.6666564941406, + 191.3333740234375 + ] + ] + }, + { + "type": "arrow", + "version": 66, + "versionNonce": 1361280261, + "isDeleted": false, + "id": "HCvGV6j45DG_BGeI3J7ut", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2116.4162578582764, + "y": 1692.6667938232422, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 288.25032234191895, + "height": 141.39862277829707, + "seed": 298119629, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1679533929334, + "link": null, + "locked": false, + "startBinding": { + "elementId": "SiZHwNA9YKd93iwc74wxB", + "focus": -0.7153529191190878, + "gap": 5.633312988281318 + }, + "endBinding": { + "elementId": "qVsRlSPxTl9a8XrnRMl2a", + "focus": -0.10195339456743455, + "gap": 1 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 125.33331298828125, + 108.66665649414062 + ], + [ + 288.25032234191895, + 141.39862277829707 + ] + ] + }, + { + "type": "arrow", + "version": 81, + "versionNonce": 1654817227, + "isDeleted": false, + "id": "iqe6U9xOE6ECb18moJnw-", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2083.0828227996826, + "y": 1640.0001068115234, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 380, + "height": 114.66668701171875, + "seed": 1655019469, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1679533929334, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": { + "elementId": "qGjmy62MZbL7zALsNU2dL", + "focus": 0.8815432234830397, + "gap": 1 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 202.66668701171875, + 114.66668701171875 + ], + [ + 380, + 64 + ] + ] + }, + { + "type": "rectangle", + "version": 196, + "versionNonce": 1880593509, + "isDeleted": false, + "id": "pWu_lwlXIT6mrZDyT6QkK", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2690.0828075408936, + "y": 1522.750244140625, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 48, + "height": 29, + "seed": 162247299, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "NSz4yfxdToa5c5At8YYeR", + "type": "arrow" + } + ], + "updated": 1679533929334, + "link": null, + "locked": false + }, + { + "type": "diamond", + "version": 181, + "versionNonce": 1847988331, + "isDeleted": false, + "id": "rBPIesLQ3_hwRCCEZDo_K", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2714.0828075408936, + "y": 1530.4169006347656, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 10.66668701171875, + "height": 17.666656494140625, + "seed": 2113989421, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929334, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 216, + "versionNonce": 2068955077, + "isDeleted": false, + "id": "1nU3Tx2BdlitDqcIjhR6O", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2689.749433517456, + "y": 1555.9168701171875, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 48, + "height": 29, + "seed": 255355427, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929334, + "link": null, + "locked": false + }, + { + "type": "diamond", + "version": 202, + "versionNonce": 1803471627, + "isDeleted": false, + "id": "qPuFVkGJxscoxDIlxjxO7", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2713.749433517456, + "y": 1563.5835266113281, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 10.66668701171875, + "height": 17.666656494140625, + "seed": 1853160845, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929334, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 205, + "versionNonce": 686784293, + "isDeleted": false, + "id": "ijtdWkKxrTh4Pnlp14iE0", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2689.416120529175, + "y": 1589.2502136230469, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 48, + "height": 29, + "seed": 495791555, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "BF2h7Ub5gAf2yYxLfQSFh", + "type": "arrow" + } + ], + "updated": 1679533929334, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 215, + "versionNonce": 1059533227, + "isDeleted": false, + "id": "jFcNDR-eUAEW7pedWkAdo", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2688.0827465057373, + "y": 1616.9168701171875, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 48, + "height": 29, + "seed": 796378093, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929334, + "link": null, + "locked": false + }, + { + "type": "diamond", + "version": 196, + "versionNonce": 257839749, + "isDeleted": false, + "id": "q4AkedYi9svz1WOMHGyiP", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2710.749433517456, + "y": 1625.2502136230469, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 10.66668701171875, + "height": 17.666656494140625, + "seed": 2009628003, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929334, + "link": null, + "locked": false + }, + { + "type": "arrow", + "version": 195, + "versionNonce": 1514783819, + "isDeleted": false, + "id": "NSz4yfxdToa5c5At8YYeR", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2491.7495250701904, + "y": 1437.3335571289062, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 199.43811857564833, + "height": 81.5190719332436, + "seed": 909964067, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1679533929334, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": { + "elementId": "pWu_lwlXIT6mrZDyT6QkK", + "focus": 0.37183947794184286, + "gap": 3.8976150784751553 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 199.43811857564833, + 81.5190719332436 + ] + ] + }, + { + "type": "arrow", + "version": 222, + "versionNonce": 458996197, + "isDeleted": false, + "id": "BF2h7Ub5gAf2yYxLfQSFh", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2718.826031777619, + "y": 1626.7287320369785, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 207.0765067074285, + "height": 202.09118637438291, + "seed": 358411853, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1679533929334, + "link": null, + "locked": false, + "startBinding": { + "elementId": "D0065Oo1uIjEqNG6iDJjn", + "focus": -2.935287320516118, + "gap": 14.961736017351072 + }, + "endBinding": { + "elementId": "qVsRlSPxTl9a8XrnRMl2a", + "focus": 0.3455990175110858, + "gap": 2.749570846557617 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -84.40981969570976, + 140.60479457434963 + ], + [ + -207.0765067074285, + 202.09118637438291 + ] + ] + }, + { + "type": "diamond", + "version": 207, + "versionNonce": 616628971, + "isDeleted": false, + "id": "D0065Oo1uIjEqNG6iDJjn", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2712.0828075408936, + "y": 1594.1669158935547, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 10.66668701171875, + "height": 17.666656494140625, + "seed": 1454945635, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "BF2h7Ub5gAf2yYxLfQSFh", + "type": "arrow" + } + ], + "updated": 1679533929334, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 61, + "versionNonce": 1173697861, + "isDeleted": false, + "id": "OI5mleCPF3WYtCzvosMk1", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2661.7495861053467, + "y": 1495.3336181640625, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 98.66668701171875, + "height": 177.33334350585938, + "seed": 617283619, + "groupIds": [], + "roundness": { + "type": 3 + }, + "boundElements": [], + "updated": 1679533929334, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 81, + "versionNonce": 655846795, + "isDeleted": false, + "id": "4Q_PdspTfAcKBYqfwEOrl", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2534.4162731170654, + "y": 1478.0003051757812, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 68, + "height": 20, + "seed": 468048995, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929334, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "(void **)", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "(void **)" + }, + { + "type": "text", + "version": 215, + "versionNonce": 176702629, + "isDeleted": false, + "id": "zEBN6RuZylHRtnzhMAsfm", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2302.082899093628, + "y": 1367.6669006347656, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 80, + "height": 20, + "seed": 1726260589, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929334, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "func_ptrs", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "func_ptrs" + }, + { + "type": "rectangle", + "version": 240, + "versionNonce": 1955038251, + "isDeleted": false, + "id": "Q1RbJ8FG5PuoKZ0jGW-AG", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2232.0828380584717, + "y": 1359.3336181640625, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 273.3333740234375, + "height": 44, + "seed": 1664381923, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929334, + "link": null, + "locked": false + }, + { + "type": "diamond", + "version": 218, + "versionNonce": 482502661, + "isDeleted": false, + "id": "lKOq2jf5D0WXwfNx9mwVb", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2245.082899093628, + "y": 1370.6669464111328, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 26.6666259765625, + "height": 19.333343505859375, + "seed": 1869049805, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929334, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 197, + "versionNonce": 1425786571, + "isDeleted": false, + "id": "5_VLE0dE94H4gwxL9iUpC", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2851.4160289764404, + "y": 1432.750228881836, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 48, + "height": 29, + "seed": 1330766563, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "8jHbZMq4zvKK9AxPUw9Qf", + "type": "arrow" + } + ], + "updated": 1679533929334, + "link": null, + "locked": false + }, + { + "type": "diamond", + "version": 181, + "versionNonce": 1587617637, + "isDeleted": false, + "id": "k1p6Nabm5uz-_RQk8vKUy", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2875.4160289764404, + "y": 1440.4168853759766, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 10.66668701171875, + "height": 17.666656494140625, + "seed": 1901883597, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929334, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 216, + "versionNonce": 789493099, + "isDeleted": false, + "id": "BH3ZK-RnoIcnosroWZ9_J", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2851.082654953003, + "y": 1465.9168548583984, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 48, + "height": 29, + "seed": 897158787, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929334, + "link": null, + "locked": false + }, + { + "type": "diamond", + "version": 202, + "versionNonce": 376564421, + "isDeleted": false, + "id": "cAmZfC7YbkEqrmByhjjHI", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2875.082654953003, + "y": 1473.583511352539, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 10.66668701171875, + "height": 17.666656494140625, + "seed": 596561709, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929334, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 205, + "versionNonce": 839569419, + "isDeleted": false, + "id": "yAeZ1rNDP97dzjt5edJvJ", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2850.7493419647217, + "y": 1499.2501983642578, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 48, + "height": 29, + "seed": 1022019107, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929334, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 215, + "versionNonce": 1691503141, + "isDeleted": false, + "id": "h_AbFbWb_N0KfOV68sJf6", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2849.415967941284, + "y": 1526.9168548583984, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 48, + "height": 29, + "seed": 1889952141, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929334, + "link": null, + "locked": false + }, + { + "type": "diamond", + "version": 196, + "versionNonce": 1072338603, + "isDeleted": false, + "id": "OKOuC260x6EDIVInqBKer", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2872.082654953003, + "y": 1535.2501983642578, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 10.66668701171875, + "height": 17.666656494140625, + "seed": 479463875, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929334, + "link": null, + "locked": false + }, + { + "type": "diamond", + "version": 208, + "versionNonce": 2058337669, + "isDeleted": false, + "id": "zQXps3l6_CULfrKz0sxFV", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2873.4160289764404, + "y": 1504.1669006347656, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 10.66668701171875, + "height": 17.666656494140625, + "seed": 769435629, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "4E9MghnYo6hn8E82pmPMe", + "type": "arrow" + } + ], + "updated": 1679533929334, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 61, + "versionNonce": 391678283, + "isDeleted": false, + "id": "4EdLS1fcNDOsz52Mf7ATN", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2823.0828075408936, + "y": 1405.3336029052734, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 98.66668701171875, + "height": 177.33334350585938, + "seed": 697555299, + "groupIds": [], + "roundness": { + "type": 3 + }, + "boundElements": [], + "updated": 1679533929334, + "link": null, + "locked": false + }, + { + "type": "arrow", + "version": 108, + "versionNonce": 256361701, + "isDeleted": false, + "id": "8jHbZMq4zvKK9AxPUw9Qf", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2495.082899093628, + "y": 1376.0003051757812, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 355.3333740234375, + "height": 55.999969482421875, + "seed": 424364771, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1679533929334, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": { + "elementId": "5_VLE0dE94H4gwxL9iUpC", + "focus": 0.6186308498480104, + "gap": 1 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 355.3333740234375, + 55.999969482421875 + ] + ] + }, + { + "type": "text", + "version": 44, + "versionNonce": 1034889195, + "isDeleted": false, + "id": "PamsTN-BPmxTRCvWvz1kZ", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2636.5496044158936, + "y": 1377.7335876464845, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 68, + "height": 20, + "seed": 508079075, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929334, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "(void **)", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "(void **)" + }, + { + "type": "arrow", + "version": 101, + "versionNonce": 371712069, + "isDeleted": false, + "id": "4E9MghnYo6hn8E82pmPMe", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2877.7495250701904, + "y": 1546.6669921875, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 317.33331298828125, + "height": 370, + "seed": 625293229, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1679533929334, + "link": null, + "locked": false, + "startBinding": { + "elementId": "zQXps3l6_CULfrKz0sxFV", + "focus": -3.2298254921305025, + "gap": 13.691591814926234 + }, + "endBinding": { + "elementId": "Z9cJSNSjDvW2uPNthdOW9", + "focus": 0.3950527937625778, + "gap": 3.582883834838867 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -144, + 266 + ], + [ + -317.33331298828125, + 370 + ] + ] + }, + { + "type": "rectangle", + "version": 219, + "versionNonce": 687403659, + "isDeleted": false, + "id": "swt6lb3ztkUJAvM41XHBK", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2033.7493724822998, + "y": 1348.4170532226562, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 48, + "height": 29, + "seed": 177857187, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "Bnf72M4RGMZjNgBlzk90B", + "type": "arrow" + } + ], + "updated": 1679533929334, + "link": null, + "locked": false + }, + { + "type": "diamond", + "version": 203, + "versionNonce": 892178341, + "isDeleted": false, + "id": "MlaoCVMw-5S2Yi8P1HjDR", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2057.7493724823, + "y": 1356.0837097167969, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 10.66668701171875, + "height": 17.666656494140625, + "seed": 1852132621, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929334, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 238, + "versionNonce": 703621419, + "isDeleted": false, + "id": "TiGonLf-juzwJEoH9VSZD", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2033.4159984588623, + "y": 1381.5836791992188, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 48, + "height": 29, + "seed": 254514755, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929334, + "link": null, + "locked": false + }, + { + "type": "diamond", + "version": 224, + "versionNonce": 2055623429, + "isDeleted": false, + "id": "3YRJV9k9ywr0i4pEZkHkN", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2057.4159984588623, + "y": 1389.2503356933594, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 10.66668701171875, + "height": 17.666656494140625, + "seed": 2075272045, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929334, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 227, + "versionNonce": 369101771, + "isDeleted": false, + "id": "33dfOgt2KTLk3Q5NBImFr", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2033.082685470581, + "y": 1414.9170227050781, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 48, + "height": 29, + "seed": 1787155939, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929334, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 237, + "versionNonce": 1387244133, + "isDeleted": false, + "id": "92FFROdmhjPmxEpXFFQ5M", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2031.7493114471436, + "y": 1442.5836791992188, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 48, + "height": 29, + "seed": 1238707661, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929334, + "link": null, + "locked": false + }, + { + "type": "diamond", + "version": 218, + "versionNonce": 826432107, + "isDeleted": false, + "id": "QULGDwKUKXLejiOFZCB88", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2054.4159984588623, + "y": 1450.9170227050781, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 10.66668701171875, + "height": 17.666656494140625, + "seed": 1270292867, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929334, + "link": null, + "locked": false + }, + { + "type": "diamond", + "version": 230, + "versionNonce": 1047991749, + "isDeleted": false, + "id": "-dLa28cPs8d1YMU273D-q", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2055.7493724823, + "y": 1419.833724975586, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 10.66668701171875, + "height": 17.666656494140625, + "seed": 1206381613, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "uC3ZSm-IltHDllxDGLJ9v", + "type": "arrow" + } + ], + "updated": 1679533929334, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 83, + "versionNonce": 1484903691, + "isDeleted": false, + "id": "diotVPud8Nk4qCzgu2hJi", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2005.416151046753, + "y": 1321.0004272460938, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 98.66668701171875, + "height": 177.33334350585938, + "seed": 2080241955, + "groupIds": [], + "roundness": { + "type": 3 + }, + "boundElements": [], + "updated": 1679533929334, + "link": null, + "locked": false + }, + { + "type": "arrow", + "version": 89, + "versionNonce": 1224348965, + "isDeleted": false, + "id": "uC3ZSm-IltHDllxDGLJ9v", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2061.749616622925, + "y": 1459.3337860107422, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 103.33331298828125, + "height": 104.66668701171875, + "seed": 687885357, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1679533929334, + "link": null, + "locked": false, + "startBinding": { + "elementId": "-dLa28cPs8d1YMU273D-q", + "focus": 3.424460294999428, + "gap": 11.855942213284369 + }, + "endBinding": { + "elementId": "0kWlc6iPzGzhrfIVEPeOM", + "focus": 0.1363752482649436, + "gap": 1.5828227996826172 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 103.33331298828125, + 64.66668701171875 + ], + [ + 67.3333740234375, + 104.66668701171875 + ] + ] + }, + { + "type": "text", + "version": 107, + "versionNonce": 1798896555, + "isDeleted": false, + "id": "Ba0bmo-eQQnhNNi6zcCzg", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2259.0828075408936, + "y": 1502.6670684814453, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 177, + "height": 40, + "seed": 1174246765, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929334, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": " uint8 *load_addr;\n uint64 load_size;", + "baseline": 34, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": " uint8 *load_addr;\n uint64 load_size;" + }, + { + "type": "rectangle", + "version": 43, + "versionNonce": 1034299525, + "isDeleted": false, + "id": "SOEOh6pxx-gC9L5EGGFZb", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2247.082929611206, + "y": 1502.6670684814453, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 256, + "height": 38, + "seed": 1478394307, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929334, + "link": null, + "locked": false + }, + { + "type": "diamond", + "version": 17, + "versionNonce": 1972522571, + "isDeleted": false, + "id": "KcLwCwuZF-_XQTvbSOePf", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2267.7495555877686, + "y": 1506.6670684814453, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 17.3333740234375, + "height": 13.333343505859375, + "seed": 1278561005, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929334, + "link": null, + "locked": false + }, + { + "type": "arrow", + "version": 58, + "versionNonce": 507039717, + "isDeleted": false, + "id": "f7JIg_N3m3yBHDkQvlpUn", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2275.7495555877686, + "y": 1510.6670684814453, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 63.33331298828125, + "height": 94.00003051757812, + "seed": 646153155, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1679533929334, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": null, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -63.33331298828125, + 70 + ], + [ + -19.33331298828125, + 94.00003051757812 + ] + ] + }, + { + "type": "text", + "version": 331, + "versionNonce": 443043051, + "isDeleted": false, + "id": "epVvbDyPF40MaERFnDDJy", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1858.9132976531982, + "y": 1828.5115061442057, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 238, + "height": 20, + "seed": 2133258755, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "CUEfVWpVIuIHc_5h3VskN", + "type": "arrow" + } + ], + "updated": 1679533929334, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "WASMFunction (second module)", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "WASMFunction (second module)" + }, + { + "type": "text", + "version": 36, + "versionNonce": 1488948037, + "isDeleted": false, + "id": "iSNS4LqcpEqsBWT3JrhTG", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1985.4163494110107, + "y": 1302.0003509521484, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 176, + "height": 20, + "seed": 895067437, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929334, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "WASMModule::functions", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "WASMModule::functions" + }, + { + "type": "text", + "version": 58, + "versionNonce": 1027962763, + "isDeleted": false, + "id": "zzptLpjImiiG1vPCDIGPS", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2788.5657176971436, + "y": 1386.4003204345704, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 185, + "height": 20, + "seed": 510558371, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929334, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "WASMModule::func_ptrs", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "WASMModule::func_ptrs" + }, + { + "type": "text", + "version": 84, + "versionNonce": 1033362085, + "isDeleted": false, + "id": "QPiZaCnPYGIz7ApGqrktI", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 2629.160482406616, + "y": 1451.7336334228517, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 160, + "height": 40, + "seed": 1301033645, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929334, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "WASMModule::\nfast_jit_func_ptrs", + "baseline": 34, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "WASMModule::\nfast_jit_func_ptrs" + }, + { + "type": "rectangle", + "version": 444, + "versionNonce": 1818512939, + "isDeleted": false, + "id": "bGS26pMiud1SV_QZasA4k", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 753.6687545776367, + "y": 1354.399984741211, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 140.66668701171875, + "height": 32.33331298828126, + "seed": 1104978987, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "type": "text", + "id": "E9Lf0GGwiMXE7OEKmLBD0" + } + ], + "updated": 1679533929334, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 223, + "versionNonce": 498422861, + "isDeleted": false, + "id": "E9Lf0GGwiMXE7OEKmLBD0", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 784.0020980834961, + "y": 1360.0666412353517, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 80, + "height": 20, + "seed": 1389316101, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679537247214, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "func_ptrs", + "baseline": 14, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "bGS26pMiud1SV_QZasA4k", + "originalText": "func_ptrs" + }, + { + "type": "diamond", + "version": 480, + "versionNonce": 179261643, + "isDeleted": false, + "id": "3V5jOnV9GBHrydrWDjdlN", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 764.3353805541992, + "y": 1366.7332977294923, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 10.66668701171875, + "height": 17.666656494140625, + "seed": 2058151627, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929334, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 64, + "versionNonce": 927151461, + "isDeleted": false, + "id": "Ej1XTEhuVY9wBpKERi-1L", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 772.668815612793, + "y": 1274.0665191650392, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 140, + "height": 20, + "seed": 1144833349, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929334, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "import_func_ptrs", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "import_func_ptrs" + }, + { + "type": "rectangle", + "version": 521, + "versionNonce": 50715531, + "isDeleted": false, + "id": "OFyAqRR6a69cDApnQUNYF", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 735.2243474324545, + "y": 1412.3998321533204, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 185.3334045410156, + "height": 34.99996948242188, + "seed": 1243189643, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533960843, + "link": null, + "locked": false + }, + { + "type": "diamond", + "version": 511, + "versionNonce": 2105521829, + "isDeleted": false, + "id": "Nv_mYV9MitkgQQoVIZJ9H", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 737.8910039265951, + "y": 1424.3998321533204, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 10.66668701171875, + "height": 17.666656494140625, + "seed": 1000679467, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533960843, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 85, + "versionNonce": 1685598763, + "isDeleted": false, + "id": "sB-lDN4LgjZtFuvGEHopU", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 753.8910039265951, + "y": 1421.2331756591798, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 160, + "height": 20, + "seed": 967892165, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "WmAyzG_eOk5gu9ag2e4NN", + "type": "arrow" + } + ], + "updated": 1679533960843, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "fast_jit_func_ptrs", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "fast_jit_func_ptrs" + }, + { + "type": "rectangle", + "version": 247, + "versionNonce": 1175609515, + "isDeleted": false, + "id": "bEyCLX9k_ShKiQzS-ZFKc", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 871.6685104370117, + "y": 1862.1498245239259, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 48, + "height": 29, + "seed": 1755598347, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929334, + "link": null, + "locked": false + }, + { + "type": "diamond", + "version": 231, + "versionNonce": 591500165, + "isDeleted": false, + "id": "mz6MyUFqd-cTtlX0HmAqX", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 895.6685104370117, + "y": 1869.8164810180665, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 10.66668701171875, + "height": 17.666656494140625, + "seed": 488090661, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929335, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 266, + "versionNonce": 1509364555, + "isDeleted": false, + "id": "i6UWgN6SrSs9asopho9X_", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 871.3351364135742, + "y": 1895.3164505004884, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 48, + "height": 29, + "seed": 581194923, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929335, + "link": null, + "locked": false + }, + { + "type": "diamond", + "version": 252, + "versionNonce": 858708709, + "isDeleted": false, + "id": "OxO-Lw3MtI3B3_yxI_9BQ", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 895.3351364135742, + "y": 1902.983106994629, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 10.66668701171875, + "height": 17.666656494140625, + "seed": 133750661, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929335, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 255, + "versionNonce": 2146202091, + "isDeleted": false, + "id": "Av0IXtuoDwPzsT4d4ZD9r", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 871.001823425293, + "y": 1928.6497940063477, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 48, + "height": 29, + "seed": 942311243, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929335, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 265, + "versionNonce": 414987845, + "isDeleted": false, + "id": "zsHPiP1O3kL8Jo_YTK1SB", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 869.6684494018555, + "y": 1956.3164505004884, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 48, + "height": 29, + "seed": 454862565, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929335, + "link": null, + "locked": false + }, + { + "type": "diamond", + "version": 246, + "versionNonce": 150797451, + "isDeleted": false, + "id": "QkKoENHz9noDS00xsmwGp", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 892.3351364135742, + "y": 1964.6497940063477, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 10.66668701171875, + "height": 17.666656494140625, + "seed": 798057963, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929335, + "link": null, + "locked": false + }, + { + "type": "diamond", + "version": 258, + "versionNonce": 1321674149, + "isDeleted": false, + "id": "8h3LnYKSejC6NlmCDjN_T", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 893.6685104370117, + "y": 1933.5664962768556, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 10.66668701171875, + "height": 17.666656494140625, + "seed": 1494254149, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929335, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 127, + "versionNonce": 1469009605, + "isDeleted": false, + "id": "8FJ9nE4COwUuKYB0Fjze2", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 843.3352890014648, + "y": 1851.0666336059571, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 98.66668701171875, + "height": 160.99990844726562, + "seed": 1608741003, + "groupIds": [], + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "id": "WmAyzG_eOk5gu9ag2e4NN", + "type": "arrow" + }, + { + "id": "Xr0h90XMpFNQFRcVNp-Qb", + "type": "arrow" + } + ], + "updated": 1679534054366, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 103, + "versionNonce": 410855685, + "isDeleted": false, + "id": "xkXUNjzkhjNlrNaWU9GPX", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 826.6688613891602, + "y": 1811.3999618530274, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 174, + "height": 40, + "seed": 380760485, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929335, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "WASMModuleInstance::\nfast_jit_func_ptrs", + "baseline": 34, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "WASMModuleInstance::\nfast_jit_func_ptrs" + }, + { + "type": "arrow", + "version": 98, + "versionNonce": 1677433349, + "isDeleted": false, + "id": "WmAyzG_eOk5gu9ag2e4NN", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 742.8910344441732, + "y": 1433.2344728128833, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 187.33331298828125, + "height": 431.9987943990309, + "seed": 471597803, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1679533960844, + "link": null, + "locked": false, + "startBinding": { + "elementId": "sB-lDN4LgjZtFuvGEHopU", + "focus": 1.017117824752581, + "gap": 10.999969482421875 + }, + "endBinding": { + "elementId": "8FJ9nE4COwUuKYB0Fjze2", + "focus": 0.09986159259017957, + "gap": 1 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -87.5555318196615, + 110.66535934043713 + ], + [ + -41.555531819661496, + 281.99876388145276 + ], + [ + 99.77778116861975, + 431.9987943990309 + ] + ] + }, + { + "type": "rectangle", + "version": 261, + "versionNonce": 227189867, + "isDeleted": false, + "id": "AXS2auzqFNZS35F2ixu8Z", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1039.001808166504, + "y": 1963.98309173584, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 48, + "height": 29, + "seed": 1019623493, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929335, + "link": null, + "locked": false + }, + { + "type": "diamond", + "version": 245, + "versionNonce": 1630563269, + "isDeleted": false, + "id": "cjLfuQX8dFdgByjdkn0sY", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1063.001808166504, + "y": 1971.6497482299806, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 10.66668701171875, + "height": 17.666656494140625, + "seed": 67902091, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929335, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 280, + "versionNonce": 1496375051, + "isDeleted": false, + "id": "O8ko0NdUbnEnqQSXbDcTn", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1038.6684341430664, + "y": 1997.1497177124024, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 48, + "height": 29, + "seed": 641787813, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929335, + "link": null, + "locked": false + }, + { + "type": "diamond", + "version": 266, + "versionNonce": 907586341, + "isDeleted": false, + "id": "MK_yFDygTjEm7c4A1RI_A", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1062.6684341430664, + "y": 2004.816374206543, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 10.66668701171875, + "height": 17.666656494140625, + "seed": 140415275, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929335, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 269, + "versionNonce": 1433847211, + "isDeleted": false, + "id": "IpQhaQLL8LX1JsLCZTqHR", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1038.3351211547852, + "y": 2030.4830612182618, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 48, + "height": 29, + "seed": 527346437, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929335, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 279, + "versionNonce": 1988230789, + "isDeleted": false, + "id": "G_B8CuUKKojKnmDg-blQS", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1037.0017471313477, + "y": 2058.1497177124024, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 48, + "height": 29, + "seed": 1416180683, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929335, + "link": null, + "locked": false + }, + { + "type": "diamond", + "version": 261, + "versionNonce": 696703051, + "isDeleted": false, + "id": "bubXHX2zzv6QsRGmmBlvp", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1059.6684341430664, + "y": 2066.483061218262, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 10.66668701171875, + "height": 17.666656494140625, + "seed": 1758265957, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "kjpM2qWJqDrV-jr9XK8QR", + "type": "arrow" + } + ], + "updated": 1679533929335, + "link": null, + "locked": false + }, + { + "type": "diamond", + "version": 272, + "versionNonce": 959047141, + "isDeleted": false, + "id": "p2Ps7ouZR4NFea5dxTpPY", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1061.001808166504, + "y": 2035.3997634887696, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 10.66668701171875, + "height": 17.666656494140625, + "seed": 407274091, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929335, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 142, + "versionNonce": 161780453, + "isDeleted": false, + "id": "PZQU4Sc5stYlZLaGSiYZg", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1010.668586730957, + "y": 1952.8999008178712, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 98.66668701171875, + "height": 160.99990844726562, + "seed": 1462332869, + "groupIds": [], + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "id": "eXEUtswyqJzZHgjz8P_J5", + "type": "arrow" + }, + { + "id": "BcRoQEkrTOTzUxX-Uw8S8", + "type": "arrow" + } + ], + "updated": 1679534050516, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 119, + "versionNonce": 1629348165, + "isDeleted": false, + "id": "RolknO7AhmdfdQTNiXJ8F", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 994.0021591186523, + "y": 1913.2332290649415, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 174, + "height": 40, + "seed": 482409739, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "eXEUtswyqJzZHgjz8P_J5", + "type": "arrow" + } + ], + "updated": 1679533929335, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "WASMModuleInstance::\nfunc_ptrs", + "baseline": 34, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "WASMModuleInstance::\nfunc_ptrs" + }, + { + "type": "rectangle", + "version": 222, + "versionNonce": 824148363, + "isDeleted": false, + "id": "p5TPteQC3PraRMJtt4XsT", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 897.2243372599283, + "y": 1585.9554707845052, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 74.666748046875, + "height": 160.99990844726562, + "seed": 727269189, + "groupIds": [], + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "id": "yu3un9i0kAGrZ8bAnVMa3", + "type": "arrow" + } + ], + "updated": 1679533929335, + "link": null, + "locked": false + }, + { + "type": "arrow", + "version": 444, + "versionNonce": 841297547, + "isDeleted": false, + "id": "eXEUtswyqJzZHgjz8P_J5", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 771.3355026245117, + "y": 1374.8998474121095, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 384.88897705078125, + "height": 633.6667022705078, + "seed": 539008875, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1679533948630, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": { + "elementId": "PZQU4Sc5stYlZLaGSiYZg", + "focus": 0.2318272147781851, + "gap": 3.3330230712890625 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -148.888916015625, + 184.1111602783203 + ], + [ + 15.555613199869754, + 612.4444732666016 + ], + [ + 236.00006103515625, + 633.6667022705078 + ] + ] + }, + { + "type": "arrow", + "version": 83, + "versionNonce": 745347115, + "isDeleted": false, + "id": "kjpM2qWJqDrV-jr9XK8QR", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1063.3354822794595, + "y": 2044.0108703613284, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 1343.333333333333, + "height": 143.33333333333326, + "seed": 738327429, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1679533929335, + "link": null, + "locked": false, + "startBinding": { + "elementId": "bubXHX2zzv6QsRGmmBlvp", + "focus": -3.5383188444895577, + "gap": 13.041657453315548 + }, + "endBinding": { + "elementId": "bu6GnR96DeCSFWu3DhMIJ", + "focus": -0.1414139865892621, + "gap": 14.399755859375318 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 790, + 23.888905843098883 + ], + [ + 1343.333333333333, + -119.44442749023438 + ] + ] + }, + { + "type": "text", + "version": 258, + "versionNonce": 1857033221, + "isDeleted": false, + "id": "VCjoZw1mwV4c94ES2JChm", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 708.2243372599285, + "y": 1804.0109212239581, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 68, + "height": 20, + "seed": 1329151115, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929335, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "(void **)", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "(void **)" + }, + { + "type": "text", + "version": 317, + "versionNonce": 588176075, + "isDeleted": false, + "id": "8pDOO3W9GlOqpH8OfM3H_", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1274.502098083496, + "y": 1674.5109720865876, + "strokeColor": "#e67700", + "backgroundColor": "transparent", + "width": 246, + "height": 19, + "seed": 73971563, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679533929335, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 3, + "text": "WASMModuleInstance(second)", + "baseline": 15, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "WASMModuleInstance(second)" + }, + { + "type": "rectangle", + "version": 271, + "versionNonce": 2113489765, + "isDeleted": false, + "id": "Rcref7JZ-AhlcXLLdwY5D", + "fillStyle": "solid", + "strokeWidth": 4, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1264.668805440267, + "y": 1697.4554453531891, + "strokeColor": "#d9480f", + "backgroundColor": "transparent", + "width": 270.66663614908845, + "height": 194.22224934895837, + "seed": 635278027, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "MLVyGZQLa4jU554J6bsmJ", + "type": "arrow" + } + ], + "updated": 1679533929335, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 226, + "versionNonce": 1289066309, + "isDeleted": false, + "id": "CZNopRssr82fjSim4TRBD", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 601.1133956909175, + "y": 2080.3445597330715, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 335, + "height": 20, + "seed": 556524395, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679534038146, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "function pointer arrays for faster access", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "function pointer arrays for faster access" + }, + { + "type": "rectangle", + "version": 45, + "versionNonce": 815465317, + "isDeleted": false, + "id": "J2L3EeElp1XhI1X3IbanK", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 578.8910547892249, + "y": 2055.122269694009, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 364.4444274902344, + "height": 58.33338419596339, + "seed": 1181100939, + "groupIds": [], + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "id": "BcRoQEkrTOTzUxX-Uw8S8", + "type": "arrow" + }, + { + "id": "Xr0h90XMpFNQFRcVNp-Qb", + "type": "arrow" + } + ], + "updated": 1679534054366, + "link": null, + "locked": false + }, + { + "type": "arrow", + "version": 33, + "versionNonce": 57793355, + "isDeleted": false, + "id": "BcRoQEkrTOTzUxX-Uw8S8", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 944.4466272989905, + "y": 2095.1223205566394, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 63.33333333333326, + "height": 19.444478352864735, + "seed": 132937093, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1679534050516, + "link": null, + "locked": false, + "startBinding": { + "elementId": "J2L3EeElp1XhI1X3IbanK", + "focus": 0.788606211312463, + "gap": 1.11114501953125 + }, + "endBinding": { + "elementId": "PZQU4Sc5stYlZLaGSiYZg", + "focus": -0.2743956700481259, + "gap": 2.8886260986332672 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 63.33333333333326, + -19.444478352864735 + ] + ] + }, + { + "type": "arrow", + "version": 24, + "versionNonce": 2098532715, + "isDeleted": false, + "id": "Xr0h90XMpFNQFRcVNp-Qb", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 786.6688156127926, + "y": 2054.011175537108, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 55.555572509765625, + "height": 45.00000000000023, + "seed": 1053702635, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1679534054366, + "link": null, + "locked": false, + "startBinding": { + "elementId": "J2L3EeElp1XhI1X3IbanK", + "focus": -0.054183297415777855, + "gap": 1.1110941569011175 + }, + "endBinding": { + "elementId": "8FJ9nE4COwUuKYB0Fjze2", + "focus": -0.3037089268567984, + "gap": 1.110900878906591 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 55.555572509765625, + -45.00000000000023 + ] + ] + } + ], + "appState": { + "gridSize": null, + "viewBackgroundColor": "#ffffff" + }, + "files": {} +} \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/doc/images/wasm_function.svg b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/doc/images/wasm_function.svg new file mode 100644 index 00000000000..86fdf78adea --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/doc/images/wasm_function.svg @@ -0,0 +1,16 @@ + + + + + + + WASMFunctionInstancefunc_importWASMFunctionImport:funcWASMFunction (per module)internal function char *module_name; char *field_name;func_ptr_linkednative function:import_module;import_func_linked;(WASMFunction *)codebytecodecode_compiledprecompiled-bytecodefast_jit_jitted_codellvm_jit_func_ptrfast jitted coodellvm jitted coodeimport_module_inst;import_func_inst;functionsglobalseWASMModuleInstanceExtraWASMModuleInstance::import_func_ptrsthis is the one actually referred during executing opcodeduring model load, if import can be solved through the native api registeration,the pointer of native function will be filled.c-api could change the pointer later, then it will point to a different native functionNULL: means multi-module import, go to "import_func_inst" field for target functionWASMModuleInstance*(WASMFunctionInstance*)func_importfuncWASMFunction union[...][0]WASMModuleInstance[..][n](void *)(void **)NULLfunc_type_indexesuint32 *WASMModule WASMImport *import_tables; WASMImport *import_memories; WASMImport *import_globals; WASMType **types; WASMImport *imports; WASMTable *tables; WASMMemory *memories; WASMGlobal *globals; WASMExport *exports; WASMTableSeg *table_segments; WASMDataSeg **data_segments;WASMFunction **functions;WASMImport *import_functions;WASMImportuint8 kind[1][0][...]fast_jit_func_ptrs(void **)func_ptrs(void **) uint8 *load_addr; uint64 load_size;WASMFunction (second module)WASMModule::functionsWASMModule::func_ptrsWASMModule::fast_jit_func_ptrsfunc_ptrsimport_func_ptrsfast_jit_func_ptrsWASMModuleInstance::fast_jit_func_ptrsWASMModuleInstance::func_ptrs(void **)WASMModuleInstance(second)function pointer arrays for faster access \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/doc/images/wasm_globals.excalidraw b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/doc/images/wasm_globals.excalidraw new file mode 100644 index 00000000000..94715352013 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/doc/images/wasm_globals.excalidraw @@ -0,0 +1,2313 @@ +{ + "type": "excalidraw", + "version": 2, + "source": "https://marketplace.visualstudio.com/items?itemName=pomdtr.excalidraw-editor", + "elements": [ + { + "type": "rectangle", + "version": 381, + "versionNonce": 2068900405, + "isDeleted": false, + "id": "D5Ay5TxydaAe4f80l_79L", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 982.833251953125, + "y": 298.00006103515625, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 99.666748046875, + "height": 211.00007629394523, + "seed": 1123866381, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "5S0qe2-BjQRPwuEEQ_UsU", + "type": "arrow" + } + ], + "updated": 1679660991439, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 317, + "versionNonce": 1880855285, + "isDeleted": false, + "id": "4JTzPDASWmnx1PVSabO3A", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 914.833251953125, + "y": 236.3333282470703, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 103, + "height": 20, + "seed": 422161475, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679661135316, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "global_data:", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "global_data:" + }, + { + "type": "text", + "version": 183, + "versionNonce": 1437992789, + "isDeleted": false, + "id": "HQjUeFzLlihuH1Lf8XZQq", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 528.1666870117188, + "y": 324.00001525878906, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 274, + "height": 20, + "seed": 2018585571, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679661163124, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "WASMModuleInstanceExtra::globals", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "WASMModuleInstanceExtra::globals" + }, + { + "type": "arrow", + "version": 453, + "versionNonce": 92905717, + "isDeleted": false, + "id": "I86Qg5wzdmE77J5SbA7HP", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 759.0470523835444, + "y": 472.4753157819668, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 223.44867715016005, + "height": 152.25013181880155, + "seed": 661894701, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "type": "text", + "id": "Qm7oDN7yJzVFQrCa0EE1G" + } + ], + "updated": 1679660991440, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": { + "elementId": "Sd34CflTFN9Elv1dedCI1", + "focus": 0.9595350520837825, + "gap": 4.004209431139316 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 223.44867715016005, + -152.25013181880155 + ] + ] + }, + { + "type": "text", + "version": 4, + "versionNonce": 2089047221, + "isDeleted": false, + "id": "Qm7oDN7yJzVFQrCa0EE1G", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 844.2713909586244, + "y": 386.350249872566, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 53, + "height": 20, + "seed": 1720249052, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679661201718, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "offset", + "baseline": 14, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "I86Qg5wzdmE77J5SbA7HP", + "originalText": "offset" + }, + { + "type": "rectangle", + "version": 213, + "versionNonce": 1454183483, + "isDeleted": false, + "id": "Sd34CflTFN9Elv1dedCI1", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 986.4999389648438, + "y": 315.6666564941406, + "strokeColor": "#000000", + "backgroundColor": "#868e96", + "width": 91.66668701171875, + "height": 27.999999999999996, + "seed": 357984397, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "I86Qg5wzdmE77J5SbA7HP", + "type": "arrow" + } + ], + "updated": 1679660991440, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 192, + "versionNonce": 706008283, + "isDeleted": false, + "id": "X5nXXDxRcZputNDZp2WfW", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 984.4998779296875, + "y": 350.83333587646484, + "strokeColor": "#000000", + "backgroundColor": "#868e96", + "width": 94.3333740234375, + "height": 19.333358764648438, + "seed": 1611395779, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "PFkOKGbMOcdhcpcv4DutQ", + "type": "arrow" + } + ], + "updated": 1679660991442, + "link": null, + "locked": false + }, + { + "type": "arrow", + "version": 369, + "versionNonce": 1307818581, + "isDeleted": false, + "id": "PFkOKGbMOcdhcpcv4DutQ", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 753.8716651262948, + "y": 690.3334503173828, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 220.3341412661283, + "height": 341.60985534904495, + "seed": 1747362403, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "type": "text", + "id": "MPb6tVMlSBtnXhUTpZvIC" + } + ], + "updated": 1679660991442, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": { + "elementId": "X5nXXDxRcZputNDZp2WfW", + "gap": 5.794568769140314, + "focus": 1.2182487723741706 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 220.3341412661283, + -341.60985534904495 + ] + ] + }, + { + "type": "text", + "version": 4, + "versionNonce": 1008745755, + "isDeleted": false, + "id": "MPb6tVMlSBtnXhUTpZvIC", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 837.538735759359, + "y": 509.52852264286037, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 53, + "height": 20, + "seed": 1880081892, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679661201719, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "offset", + "baseline": 14, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "PFkOKGbMOcdhcpcv4DutQ", + "originalText": "offset" + }, + { + "type": "text", + "version": 429, + "versionNonce": 147921333, + "isDeleted": false, + "id": "5GnY6Vq9qPDS0ntZW3UOE", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 917.166748046875, + "y": 259.3333282470703, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 197, + "height": 20, + "seed": 1179957165, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679661138960, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "hold values of GLOBALs", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "hold values of GLOBALs" + }, + { + "type": "rectangle", + "version": 234, + "versionNonce": 339097851, + "isDeleted": false, + "id": "FcG2LCAdKxw_z2SzLhPPr", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 548.3333129882812, + "y": 351.666748046875, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 228.66668701171866, + "height": 299.66668701171875, + "seed": 407083364, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "_acaSZ2N5FSiuPGQjH8RA", + "type": "arrow" + } + ], + "updated": 1679660870990, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 182, + "versionNonce": 1735336804, + "isDeleted": false, + "id": "OdBdX2K4Kcn9Hq7vInwKA", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 571, + "y": 387.3333740234375, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 190, + "height": 30, + "seed": 175211612, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "type": "text", + "id": "OZDTfM4SDGXEVbxgCAbsx" + } + ], + "updated": 1679643912221, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 135, + "versionNonce": 1695691996, + "isDeleted": false, + "id": "OZDTfM4SDGXEVbxgCAbsx", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 621.5, + "y": 392.3333740234375, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 89, + "height": 20, + "seed": 1994750564, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679643912221, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "uint8 type;", + "baseline": 14, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "OdBdX2K4Kcn9Hq7vInwKA", + "originalText": "uint8 type;" + }, + { + "type": "text", + "version": 174, + "versionNonce": 2063524661, + "isDeleted": false, + "id": "w5el7zqw5vcK9RGIcDlFZ", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 580.9999389648438, + "y": 357.8333435058594, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 171, + "height": 19, + "seed": 1831729636, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "_acaSZ2N5FSiuPGQjH8RA", + "type": "arrow" + } + ], + "updated": 1679660882880, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 3, + "text": "WASMGlobalInstance", + "baseline": 15, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "WASMGlobalInstance" + }, + { + "type": "rectangle", + "version": 147, + "versionNonce": 1194277212, + "isDeleted": false, + "id": "gd9UxDYh5XZYBG_P0f0c2", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 568.3333129882812, + "y": 424.666748046875, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 195, + "height": 30, + "seed": 1018791012, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "type": "text", + "id": "YeoEjoPWRnxxyB2DjNi3g" + } + ], + "updated": 1679643912221, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 104, + "versionNonce": 1904253540, + "isDeleted": false, + "id": "YeoEjoPWRnxxyB2DjNi3g", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 600.8333129882812, + "y": 429.666748046875, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 130, + "height": 20, + "seed": 839439588, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679643912221, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "bool is_mutable;", + "baseline": 14, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "gd9UxDYh5XZYBG_P0f0c2", + "originalText": "bool is_mutable;" + }, + { + "type": "rectangle", + "version": 91, + "versionNonce": 1480043996, + "isDeleted": false, + "id": "MB23InQWKES3OnYie8bbP", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 569.6666870117188, + "y": 460.666748046875, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 195, + "height": 30, + "seed": 1468762332, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "type": "text", + "id": "--vP8lM62PEnMBhgFRqTM" + } + ], + "updated": 1679643912221, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 63, + "versionNonce": 717729252, + "isDeleted": false, + "id": "--vP8lM62PEnMBhgFRqTM", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 582.6666870117188, + "y": 465.666748046875, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 169, + "height": 20, + "seed": 695551844, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679643912221, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "uint32 data_offset;", + "baseline": 14, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "MB23InQWKES3OnYie8bbP", + "originalText": "uint32 data_offset;" + }, + { + "type": "rectangle", + "version": 111, + "versionNonce": 155030108, + "isDeleted": false, + "id": "pUUma4amJviNKdfn5otpb", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 577.6666870117188, + "y": 497.33338928222656, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 180.33331298828125, + "height": 30, + "seed": 1550527844, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "type": "text", + "id": "JybtW1PyDYQa00JaSYsuo" + } + ], + "updated": 1679643912221, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 63, + "versionNonce": 1625313636, + "isDeleted": false, + "id": "JybtW1PyDYQa00JaSYsuo", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 618.8333435058594, + "y": 502.33338928222656, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 98, + "height": 20, + "seed": 1952693084, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679643912221, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "initial_value", + "baseline": 14, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "pUUma4amJviNKdfn5otpb", + "originalText": "initial_value" + }, + { + "type": "rectangle", + "version": 91, + "versionNonce": 1494410972, + "isDeleted": false, + "id": "CewuQtNj0ZC6Ogsq68ite", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 569.6666870117188, + "y": 546.6667022705078, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 191, + "height": 30, + "seed": 10317668, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "type": "text", + "id": "4xSFF2vFZIoA0G7GTeC8-" + } + ], + "updated": 1679643912221, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 63, + "versionNonce": 588809444, + "isDeleted": false, + "id": "4xSFF2vFZIoA0G7GTeC8-", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 588.1666870117188, + "y": 551.6667022705078, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 154, + "height": 20, + "seed": 1109403492, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679643912221, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "import_module_inst", + "baseline": 14, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "CewuQtNj0ZC6Ogsq68ite", + "originalText": "import_module_inst" + }, + { + "type": "rectangle", + "version": 123, + "versionNonce": 474590044, + "isDeleted": false, + "id": "AuHfz77U4KxNTCmKvW6bJ", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 573, + "y": 589.3333892822266, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 184, + "height": 30, + "seed": 2058570588, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "type": "text", + "id": "h7MfnIO2f08rV_U7840Zp" + } + ], + "updated": 1679643912221, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 75, + "versionNonce": 1727940708, + "isDeleted": false, + "id": "h7MfnIO2f08rV_U7840Zp", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 591, + "y": 594.3333892822266, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 148, + "height": 20, + "seed": 1917882340, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679643912221, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "import_global_inst", + "baseline": 14, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "AuHfz77U4KxNTCmKvW6bJ", + "originalText": "import_global_inst" + }, + { + "type": "text", + "version": 134, + "versionNonce": 1361481211, + "isDeleted": false, + "id": "Clf1NqZqRXJuRl-CQgx_u", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 232.6667175292969, + "y": 454.6668395996094, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 237, + "height": 20, + "seed": 1711793252, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "_acaSZ2N5FSiuPGQjH8RA", + "type": "arrow" + } + ], + "updated": 1679661000688, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "WASMGlobalInstance *globals;", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "WASMGlobalInstance *globals;" + }, + { + "type": "text", + "version": 30, + "versionNonce": 1504826724, + "isDeleted": false, + "id": "Mj7l2FOHQ7NNAkTiGq7T_", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 641, + "y": 631.0001373291016, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 29, + "height": 20, + "seed": 1401608924, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679643959727, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "[0]", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "[0]" + }, + { + "type": "rectangle", + "version": 52, + "versionNonce": 894397020, + "isDeleted": false, + "id": "CGwcN3BpsJaehLlHjEn6l", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 548.6666259765625, + "y": 653.0000457763672, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 227, + "height": 87, + "seed": 253331684, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679644065258, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 107, + "versionNonce": 1424372828, + "isDeleted": false, + "id": "YjTAPKLSA0k-ml5j0Ho59", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 565.1666259765625, + "y": 671.6667327880859, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 195, + "height": 30, + "seed": 192441436, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "type": "text", + "id": "jmlAM3nHo1CJVxGKppt1O" + } + ], + "updated": 1679643968867, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 78, + "versionNonce": 2064306020, + "isDeleted": false, + "id": "jmlAM3nHo1CJVxGKppt1O", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 578.1666259765625, + "y": 676.6667327880859, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 169, + "height": 20, + "seed": 1473779556, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679643968868, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "uint32 data_offset;", + "baseline": 14, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "YjTAPKLSA0k-ml5j0Ho59", + "originalText": "uint32 data_offset;" + }, + { + "type": "text", + "version": 32, + "versionNonce": 1512962780, + "isDeleted": false, + "id": "QnLh-KZNv_MoD4Ak5RsLk", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 636.1666259765625, + "y": 719.0000457763672, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 22, + "height": 20, + "seed": 927449564, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679643979051, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "[1]", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "[1]" + }, + { + "type": "rectangle", + "version": 62, + "versionNonce": 626330844, + "isDeleted": false, + "id": "F26JZDrwDBDSk5o5kcV_E", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 547.3333129882812, + "y": 739.6667327880859, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 227.666748046875, + "height": 60.666656494140625, + "seed": 725179740, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679644057644, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 71, + "versionNonce": 1658992100, + "isDeleted": false, + "id": "H6cL4L0PUBLB5An3KDf-i", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 636.6666259765625, + "y": 784.0003204345703, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 31, + "height": 20, + "seed": 83711068, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679644496025, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "[...]", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "[...]" + }, + { + "type": "rectangle", + "version": 158, + "versionNonce": 208125412, + "isDeleted": false, + "id": "M6cl8S-GRJkkRSQrUxzJV", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 566.833251953125, + "y": 747.6667327880859, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 195, + "height": 30, + "seed": 997959652, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "type": "text", + "id": "DrpXGgZIT2RAhz4L6EM2n" + } + ], + "updated": 1679644019993, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 128, + "versionNonce": 493257308, + "isDeleted": false, + "id": "DrpXGgZIT2RAhz4L6EM2n", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 579.833251953125, + "y": 752.6667327880859, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 169, + "height": 20, + "seed": 157169756, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679644019993, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "uint32 data_offset;", + "baseline": 14, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "M6cl8S-GRJkkRSQrUxzJV", + "originalText": "uint32 data_offset;" + }, + { + "type": "rectangle", + "version": 223, + "versionNonce": 680765365, + "isDeleted": false, + "id": "nPxM8HePICecTvRXbdEeU", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 983.333251953125, + "y": 378.1666793823242, + "strokeColor": "#000000", + "backgroundColor": "#868e96", + "width": 97.66668701171875, + "height": 30.000015258789062, + "seed": 1516156124, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "Y_Dw9hCEvutA3MjjHfyJK", + "type": "arrow" + } + ], + "updated": 1679660991443, + "link": null, + "locked": false + }, + { + "type": "arrow", + "version": 165, + "versionNonce": 430152219, + "isDeleted": false, + "id": "Y_Dw9hCEvutA3MjjHfyJK", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 756.6666259765625, + "y": 766.3333892822266, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 217.14296385054604, + "height": 385.92617569738337, + "seed": 703298780, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "type": "text", + "id": "MraNxq38RWxCBOb3EhIue" + } + ], + "updated": 1679660991443, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": { + "elementId": "nPxM8HePICecTvRXbdEeU", + "gap": 9.523662126016394, + "focus": 1.1442737969660202 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 217.14296385054604, + -385.92617569738337 + ] + ] + }, + { + "type": "text", + "version": 4, + "versionNonce": 1122104853, + "isDeleted": false, + "id": "MraNxq38RWxCBOb3EhIue", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 838.7381079018355, + "y": 563.3703014335349, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 53, + "height": 20, + "seed": 1058889828, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679661201730, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "offset", + "baseline": 14, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "Y_Dw9hCEvutA3MjjHfyJK", + "originalText": "offset" + }, + { + "type": "text", + "version": 239, + "versionNonce": 551950564, + "isDeleted": false, + "id": "O5mHltv55Fs4-vM6wNcf-", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 226.99996948242188, + "y": 655.0000457763672, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 164, + "height": 20, + "seed": 352849508, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "1QAmzR8Zkk8scUA3tqI0k", + "type": "arrow" + } + ], + "updated": 1679644753215, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "WASMGlobalInstance", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "WASMGlobalInstance" + }, + { + "type": "rectangle", + "version": 104, + "versionNonce": 219644132, + "isDeleted": false, + "id": "CpOJESdMD1E9wBe2Gkkvf", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 216.66665649414062, + "y": 681.6666412353516, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 180.33331298828125, + "height": 46.666778564453125, + "seed": 705788380, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679644728661, + "link": null, + "locked": false + }, + { + "type": "arrow", + "version": 153, + "versionNonce": 296383867, + "isDeleted": false, + "id": "1QAmzR8Zkk8scUA3tqI0k", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 583.9999694824219, + "y": 602.3333587646484, + "strokeColor": "#000000", + "backgroundColor": "#15aabf", + "width": 179.2173434297432, + "height": 75.12469349055664, + "seed": 869061340, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "type": "text", + "id": "N9fS0DKeDh1d_Ueyopb9v" + } + ], + "updated": 1679661068533, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": { + "elementId": "O5mHltv55Fs4-vM6wNcf-", + "focus": 1.1855962422681312, + "gap": 14.0001220703125 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -179.2173434297432, + 75.12469349055664 + ] + ] + }, + { + "id": "N9fS0DKeDh1d_Ueyopb9v", + "type": "text", + "x": 449.39129776755027, + "y": 629.8957055099268, + "width": 90, + "height": 20, + "angle": 0, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "roundness": null, + "seed": 339183189, + "version": 24, + "versionNonce": 270159573, + "isDeleted": false, + "boundElements": null, + "updated": 1679661092509, + "link": null, + "locked": false, + "text": "when import", + "fontSize": 16, + "fontFamily": 1, + "textAlign": "center", + "verticalAlign": "middle", + "baseline": 14, + "containerId": "1QAmzR8Zkk8scUA3tqI0k", + "originalText": "when import" + }, + { + "type": "rectangle", + "version": 59, + "versionNonce": 96174172, + "isDeleted": false, + "id": "oDs6sXYd2cCCUTlDuFyfK", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 199.66659545898438, + "y": 599.9999847412109, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 236.33343505859375, + "height": 196.3333740234375, + "seed": 1531972708, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679644717838, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 72, + "versionNonce": 1711293284, + "isDeleted": false, + "id": "Gyz12ttmraGX-CaCTWl3h", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 191.99990844726562, + "y": 576.3333892822266, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 239, + "height": 20, + "seed": 683171044, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "957MNrV_zCOsf-ssBBkla", + "type": "arrow" + } + ], + "updated": 1679644717838, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "WASMModuleInstance (second)", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "WASMModuleInstance (second)" + }, + { + "type": "text", + "version": 185, + "versionNonce": 1644000405, + "isDeleted": false, + "id": "7TYuQ_yCiwRN4oz8zkdGb", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 38.33337402343753, + "y": 248.66676330566406, + "strokeColor": "#d9480f", + "backgroundColor": "transparent", + "width": 171, + "height": 19, + "seed": 1694546652, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679661000688, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 3, + "text": "WASMModuleInstance", + "baseline": 15, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "WASMModuleInstance" + }, + { + "type": "rectangle", + "version": 151, + "versionNonce": 1152705621, + "isDeleted": false, + "id": "DN3tWnhyoeDPQR_-BYeYI", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 36.666656494140625, + "y": 269.00010681152344, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 202.00003051757815, + "height": 124.66665649414062, + "seed": 693300324, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "-n6vwSfIOzGpAxjpRyuNZ", + "type": "arrow" + } + ], + "updated": 1679661004485, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 150, + "versionNonce": 458299605, + "isDeleted": false, + "id": "K0JMv-qZGU4i9Or0Xz4Gg", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 246.33328247070315, + "y": 399.33343505859375, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 218, + "height": 19, + "seed": 881476572, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679661029361, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 3, + "text": "WASMModuleInstanceExtra", + "baseline": 15, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "WASMModuleInstanceExtra" + }, + { + "type": "rectangle", + "version": 169, + "versionNonce": 769392085, + "isDeleted": false, + "id": "CERoUCjzlaXjrdr4PSxtB", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 225.33328247070312, + "y": 428.00010681152344, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 256.3333740234375, + "height": 91.33331298828128, + "seed": 1750838620, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "-n6vwSfIOzGpAxjpRyuNZ", + "type": "arrow" + } + ], + "updated": 1679661027326, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 88, + "versionNonce": 1947089019, + "isDeleted": false, + "id": "H3BkjBVeDYM2F429PxOI9", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 233.0000915527344, + "y": 447.00010681152344, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 243.00006103515625, + "height": 31, + "seed": 258806116, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "-n6vwSfIOzGpAxjpRyuNZ", + "type": "arrow" + } + ], + "updated": 1679661000688, + "link": null, + "locked": false + }, + { + "type": "arrow", + "version": 257, + "versionNonce": 314119835, + "isDeleted": false, + "id": "_acaSZ2N5FSiuPGQjH8RA", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 463.97668298272777, + "y": 453.66683959960943, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 80.59006409386518, + "height": 100.23285752369344, + "seed": 1866235612, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679661000688, + "link": null, + "locked": false, + "startBinding": { + "elementId": "Clf1NqZqRXJuRl-CQgx_u", + "focus": 0.8216444271084713, + "gap": 1 + }, + "endBinding": { + "elementId": "FcG2LCAdKxw_z2SzLhPPr", + "focus": 1.009989878742988, + "gap": 3.7665659116883603 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 80.59006409386518, + -100.23285752369344 + ] + ] + }, + { + "type": "rectangle", + "version": 63, + "versionNonce": 1164697781, + "isDeleted": false, + "id": "NIObCr2apYl6JLLzA37G2", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 232.66665649414065, + "y": 486.66676330566406, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 244.33331298828125, + "height": 30, + "seed": 1813909212, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "type": "text", + "id": "sYEF77zbpRw-pcdX1ass6" + } + ], + "updated": 1679661000688, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 24, + "versionNonce": 4682011, + "isDeleted": false, + "id": "sYEF77zbpRw-pcdX1ass6", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 272.33331298828125, + "y": 491.66676330566406, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 165, + "height": 20, + "seed": 382274908, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679661000688, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "uint32 global_count;", + "baseline": 14, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "NIObCr2apYl6JLLzA37G2", + "originalText": "uint32 global_count;" + }, + { + "type": "rectangle", + "version": 142, + "versionNonce": 519569941, + "isDeleted": false, + "id": "7jX0wgP7v4HHkuITKOf89", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 94.3333435058594, + "y": 344.33351135253906, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 115, + "height": 30.333358764648438, + "seed": 1226666212, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "type": "text", + "id": "sK7ecOoz_3QIduVF0nHd7" + } + ], + "updated": 1679661000688, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 116, + "versionNonce": 1846580667, + "isDeleted": false, + "id": "sK7ecOoz_3QIduVF0nHd7", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 146.3333435058594, + "y": 349.5001907348633, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 11, + "height": 20, + "seed": 1178170724, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679661000688, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "e", + "baseline": 14, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "7jX0wgP7v4HHkuITKOf89", + "originalText": "e" + }, + { + "type": "diamond", + "version": 135, + "versionNonce": 691599221, + "isDeleted": false, + "id": "yTfoj623sdm1eh4Eusmvt", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 174.66665649414065, + "y": 352.0001983642578, + "strokeColor": "#000000", + "backgroundColor": "#be4bdb", + "width": 13.66668701171875, + "height": 12.333328247070312, + "seed": 559414236, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679661000688, + "link": null, + "locked": false + }, + { + "type": "arrow", + "version": 324, + "versionNonce": 1197545819, + "isDeleted": false, + "id": "-n6vwSfIOzGpAxjpRyuNZ", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 182.00003051757815, + "y": 356.66676330566406, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 45.12566323463764, + "height": 69.66665649414062, + "seed": 1850539876, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679661027326, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": { + "elementId": "CERoUCjzlaXjrdr4PSxtB", + "gap": 1, + "focus": -0.6072997775389923 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 45.12566323463764, + 69.66665649414062 + ] + ] + }, + { + "type": "arrow", + "version": 68, + "versionNonce": 732107996, + "isDeleted": false, + "id": "957MNrV_zCOsf-ssBBkla", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 578.0000305175781, + "y": 557.6666717529297, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 144.0692777412945, + "height": 39.30743410761045, + "seed": 1605267676, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679644717838, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": { + "elementId": "Gyz12ttmraGX-CaCTWl3h", + "focus": 1.0338080600507247, + "gap": 3.00006103515625 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -144.0692777412945, + 39.30743410761045 + ] + ] + }, + { + "type": "diamond", + "version": 20, + "versionNonce": 825681252, + "isDeleted": false, + "id": "pKw8fr7S6f80J93nrJtkQ", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 575.8333129882812, + "y": 553.5000076293945, + "strokeColor": "#000000", + "backgroundColor": "#be4bdb", + "width": 13.66668701171875, + "height": 12.333328247070312, + "seed": 222063588, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679644481683, + "link": null, + "locked": false + }, + { + "type": "diamond", + "version": 20, + "versionNonce": 825681252, + "isDeleted": false, + "id": "XKwLDKrjsXcSogvJHSY-e", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 573.8333129882812, + "y": 597.5000076293945, + "strokeColor": "#000000", + "backgroundColor": "#be4bdb", + "width": 13.66668701171875, + "height": 12.333328247070312, + "seed": 1140569180, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679644483164, + "link": null, + "locked": false + }, + { + "type": "rectangle", + "version": 215, + "versionNonce": 510935253, + "isDeleted": false, + "id": "oPjebDyI5NP26BNK4PLtX", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 50.33343505859378, + "y": 290.33338928222656, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 180, + "height": 31, + "seed": 727213156, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "type": "text", + "id": "ZK3cjtpUxVpruHBkbgevo" + } + ], + "updated": 1679661000688, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 175, + "versionNonce": 1653383931, + "isDeleted": false, + "id": "ZK3cjtpUxVpruHBkbgevo", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 58.33343505859378, + "y": 295.83338928222656, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 164, + "height": 20, + "seed": 1130592356, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679661000688, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "uint8 * global_data", + "baseline": 14, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "oPjebDyI5NP26BNK4PLtX", + "originalText": "uint8 * global_data" + }, + { + "type": "arrow", + "version": 159, + "versionNonce": 345149237, + "isDeleted": false, + "id": "5S0qe2-BjQRPwuEEQ_UsU", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 228.00003051757812, + "y": 299.9999694824219, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 754.7517447227082, + "height": 17.8331298828125, + "seed": 1256331620, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1679661008047, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": { + "elementId": "D5Ay5TxydaAe4f80l_79L", + "focus": 0.9720307648275319, + "gap": 1 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 385.0834503173828, + -17.8331298828125 + ], + [ + 754.7517447227082, + -2.996583692902334 + ] + ] + }, + { + "type": "diamond", + "version": 89, + "versionNonce": 1413439029, + "isDeleted": false, + "id": "szV9RT3yAJ51dUnP5JYMS", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 220.1667175292969, + "y": 294.50000762939453, + "strokeColor": "#000000", + "backgroundColor": "#be4bdb", + "width": 13.66668701171875, + "height": 12.333328247070312, + "seed": 1642184284, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679661000688, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 160, + "versionNonce": 715957468, + "isDeleted": false, + "id": "DuwilIDd-fhNUxybFRKva", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 255.16659545898438, + "y": 750.6665496826172, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 99, + "height": 20, + "seed": 121250780, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679644739787, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "global_data", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "global_data" + }, + { + "type": "rectangle", + "version": 143, + "versionNonce": 2046173532, + "isDeleted": false, + "id": "6CMun9I8IOX876t85IJ2X", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 215.83328247070312, + "y": 738.6664733886719, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 180.33331298828125, + "height": 46.666778564453125, + "seed": 2113088100, + "groupIds": [], + "roundness": null, + "boundElements": [ + { + "id": "igqxFPh3AgDb1kYMsORSZ", + "type": "arrow" + } + ], + "updated": 1679644784578, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 34, + "versionNonce": 1198703204, + "isDeleted": false, + "id": "cbSo4pUG_J3a4Pnk3ODCA", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 276.6665954589844, + "y": 693.3332366943359, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 55, + "height": 20, + "seed": 328242020, + "groupIds": [], + "roundness": null, + "boundElements": [], + "updated": 1679644771096, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 1, + "text": "globals", + "baseline": 14, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "globals" + }, + { + "type": "arrow", + "version": 81, + "versionNonce": 311117156, + "isDeleted": false, + "id": "igqxFPh3AgDb1kYMsORSZ", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 247.33328247070312, + "y": 706.3332366943359, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "width": 71.66665649414062, + "height": 58.33343505859375, + "seed": 1345639908, + "groupIds": [], + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1679644787747, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": { + "elementId": "6CMun9I8IOX876t85IJ2X", + "focus": -0.8452179527426857, + "gap": 1.499908447265625 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -71.66665649414062, + 15.66668701171875 + ], + [ + -32.999908447265625, + 58.33343505859375 + ] + ] + }, + { + "type": "diamond", + "version": 135, + "versionNonce": 691599221, + "isDeleted": false, + "id": "koTtnTl85TIGelUbfKlR9", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 459.58338928222656, + "y": 446.0001754760742, + "strokeColor": "#000000", + "backgroundColor": "#be4bdb", + "width": 13.66668701171875, + "height": 12.333328247070312, + "seed": 626707637, + "groupIds": [], + "roundness": null, + "boundElements": null, + "updated": 1679661018823, + "link": null, + "locked": false + } + ], + "appState": { + "gridSize": null, + "viewBackgroundColor": "#ffffff" + }, + "files": {} +} \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/doc/images/wasm_globals.svg b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/doc/images/wasm_globals.svg new file mode 100644 index 00000000000..fa3461732a6 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/doc/images/wasm_globals.svg @@ -0,0 +1,16 @@ + + + + + + + global_data:WASMModuleInstanceExtra::globalsoffsetoffsethold values of GLOBALsuint8 type;WASMGlobalInstancebool is_mutable;uint32 data_offset;initial_valueimport_module_instimport_global_instWASMGlobalInstance *globals;[0]uint32 data_offset;[1][...]uint32 data_offset;offsetWASMGlobalInstancewhen importWASMModuleInstance (second)WASMModuleInstanceWASMModuleInstanceExtrauint32 global_count;euint8 * global_dataglobal_dataglobals \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/doc/wasm_exports.MD b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/doc/wasm_exports.MD new file mode 100644 index 00000000000..70708cde31f --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/doc/wasm_exports.MD @@ -0,0 +1,22 @@ +# Wasm exports +The internal data structure for Wasm exports: +![](./images/wasm_exports.svg) + +## Setup exports for Module +The array data structure pointed by `WASMModule::exports` is setup during loading a module. Basically the runtime will load the exports sections from the module file content, and construct an array of C struct `WASMExport`. + +A `WASMExport` item contains three elements that map the Wasm file exports section structure: +- name: the name shown to external +- kind: total 4 export types: function, globals, memory, table +- index: As all the 4 export types are organized in array, this refers to index in target export type + +## Function exports +### use function exports +function exports are often used in two situations: + 1. **call by host**: runtime API `wasm_runtime_lookup_function` will walk through the array of `WASMModuleInstance::export_functions` and compare the exported name with given target symbol name in the function parameter. If any array item matches the name, it then returns the value of field `function` which points to associated function instance (WASMFunctionInstance) + 2. **import by another module**: During linking multiple modules, the runtime saves the pointer of exported WASMFunctionInstance in the local WASMFunctionInstance of importing module. + +### setup for instance +The data structure pointed by `WASMModuleInstance::export_functions` is set up during instantiating module instance. + +The runtime will walk through the `WASMModule::exports` array and find all the item with kind equal to "function". Create a node of `WASMExportFuncInstance` for each matching, find the associated `WASMFunctionInstance` object and save its address in the field `function`. diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/doc/wasm_function.MD b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/doc/wasm_function.MD new file mode 100644 index 00000000000..da4dac23999 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/doc/wasm_function.MD @@ -0,0 +1,47 @@ +# Wasm Function + +## Internal data structure + +![](./images/wasm_function.svg) + +## Module level data (function) +**WASMModule**: Data structure created for loading a module. +- `WASMImport *import_functions`: initialized from the Wasm file function section +- `WASMImport *import_functions`: initialized from the Wasm file import section. The runtime will try to solve the imports from the native API registration, refer to [Export native API to WASM application](../../../doc/export_native_api.md). + +**WASMFunction**: represent a Wasm function located in Wasm file code section. Track the links to the compiled function body. +**WASMImport**: represent a imported Wasm function which can be a solved as a native function or another Wasm module exported function. + +## Instance level data (function) +**WASMModuleInstance**: Data structure created for instantiating a module +- `WASMModuleInstanceExtra::functions`: combined the imported and internal functions into single array of structure `WASMFunctionInstance` +- `WASMModuleInstance::import_func_ptrs`: pointer array for solved function imports. This array is referred during calling imported native function. Note it is initialzed with the module level solved imports, but may points to different native function later due to c-api calls. + +## Execution paths +**Interpreter**: +- Execute internal bytecode function: + ``` + WASMModuleInstance::e + -> WASMModuleInstanceExtra::functions[..] + -> WASMFunctionInstance::func + -> WASMFunction::code + ``` + +- Execute imported function from other module: + ``` + WASMModuleInstance::e + -> WASMModuleInstanceExtra::functions[..] + (WASMFunctionInstance flag indicates an import) + -> WASMFunctionInstance::import_func_inst + -> WASMModuleInstance(second)::func + -> WASMFunction (second module)::code + ``` + +- Execute imported native function: + ``` + WASMModuleInstance::e + -> WASMModuleInstanceExtra::functions[..] + (flag indicates imported native) + WASMModuleInstance::import_func_ptrs[..] + -> native function + ``` \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/doc/wasm_globals.MD b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/doc/wasm_globals.MD new file mode 100644 index 00000000000..e5019a9fc57 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/doc/wasm_globals.MD @@ -0,0 +1,4 @@ +# Wasm globals + +![](./images/wasm_globals.svg) + diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/asmjit_sgx_patch.diff b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/asmjit_sgx_patch.diff similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/asmjit_sgx_patch.diff rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/asmjit_sgx_patch.diff diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/cg/LICENSE_ASMJIT b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/cg/LICENSE_ASMJIT similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/cg/LICENSE_ASMJIT rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/cg/LICENSE_ASMJIT diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/cg/LICENSE_ZYDIS b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/cg/LICENSE_ZYDIS similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/cg/LICENSE_ZYDIS rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/cg/LICENSE_ZYDIS diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/cg/x86-64/jit_codegen_x86_64.cpp b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/cg/x86-64/jit_codegen_x86_64.cpp similarity index 67% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/cg/x86-64/jit_codegen_x86_64.cpp rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/cg/x86-64/jit_codegen_x86_64.cpp index 34bd5af301a..e28acf98a62 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/cg/x86-64/jit_codegen_x86_64.cpp +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/cg/x86-64/jit_codegen_x86_64.cpp @@ -6,6 +6,7 @@ #include "jit_codegen.h" #include "jit_codecache.h" #include "jit_compiler.h" +#include "jit_frontend.h" #include "jit_dump.h" #include @@ -21,6 +22,31 @@ using namespace asmjit; static char *code_block_switch_to_jitted_from_interp = NULL; static char *code_block_return_to_interp_from_jitted = NULL; +#if WASM_ENABLE_LAZY_JIT != 0 +static char *code_block_compile_fast_jit_and_then_call = NULL; +#endif + +typedef enum { + REG_BPL_IDX = 0, + REG_AXL_IDX, + REG_BXL_IDX, + REG_CXL_IDX, + REG_DXL_IDX, + REG_DIL_IDX, + REG_SIL_IDX, + REG_I8_FREE_IDX = REG_SIL_IDX +} RegIndexI8; + +typedef enum { + REG_BP_IDX = 0, + REG_AX_IDX, + REG_BX_IDX, + REG_CX_IDX, + REG_DX_IDX, + REG_DI_IDX, + REG_SI_IDX, + REG_I16_FREE_IDX = REG_SI_IDX +} RegIndexI16; typedef enum { REG_EBP_IDX = 0, @@ -107,16 +133,17 @@ x86::Xmm regs_float[] = { int jit_codegen_interp_jitted_glue(void *exec_env, JitInterpSwitchInfo *info, - void *target) + uint32 func_idx, void *target) { - typedef int32 (*F)(const void *exec_env, void *info, const void *target); + typedef int32 (*F)(const void *exec_env, void *info, uint32 func_idx, + const void *target); union { F f; void *v; } u; u.v = code_block_switch_to_jitted_from_interp; - return u.f(exec_env, info, target); + return u.f(exec_env, info, func_idx, target); } #define PRINT_LINE() LOG_VERBOSE("\n", __LINE__) @@ -257,6 +284,13 @@ jit_codegen_interp_jitted_glue(void *exec_env, JitInterpSwitchInfo *info, r3 = *jit_insn_opnd(insn, 3); \ CHECK_NCONST(r0) +/* Load five operands from insn and check if r0 is non-const */ +#define LOAD_4ARGS_NO_ASSIGN() \ + r0 = *jit_insn_opnd(insn, 0); \ + r1 = *jit_insn_opnd(insn, 1); \ + r2 = *jit_insn_opnd(insn, 2); \ + r3 = *jit_insn_opnd(insn, 3); + class JitErrorHandler : public ErrorHandler { public: @@ -848,6 +882,47 @@ mov_imm_to_m(x86::Assembler &a, x86::Mem &m_dst, Imm imm_src, uint32 bytes_dst) return true; } +#if WASM_ENABLE_SHARED_MEMORY != 0 +/** + * Encode exchange register with memory + * + * @param a the assembler to emit the code + * @param bytes_dst the bytes number of the data, + * could be 1(byte), 2(short), 4(int32), 8(int64), + * skipped by float and double + * @param kind_dst the kind of data to move, could only be I32 or I64 + * @param m_dst the dest memory operand + * @param reg_no_src the index of dest register + * + * @return true if success, false otherwise + */ +static bool +xchg_r_to_m(x86::Assembler &a, uint32 bytes_dst, uint32 kind_dst, + x86::Mem &m_dst, int32 reg_no_src) +{ + bh_assert((kind_dst == JIT_REG_KIND_I32 && bytes_dst <= 4) + || kind_dst == JIT_REG_KIND_I64); + bh_assert(reg_no_src < 16); + switch (bytes_dst) { + case 1: + a.xchg(m_dst, regs_i8[reg_no_src]); + break; + case 2: + a.xchg(m_dst, regs_i16[reg_no_src]); + break; + case 4: + a.xchg(m_dst, regs_i32[reg_no_src]); + break; + case 8: + a.xchg(m_dst, regs_i64[reg_no_src]); + break; + default: + bh_assert(0); + return false; + } + return true; +} +#endif /** * Encode loading register data from memory with imm base and imm offset * @@ -962,9 +1037,13 @@ ld_r_from_base_r_offset_r(x86::Assembler &a, uint32 bytes_dst, uint32 kind_dst, static bool st_r_to_base_imm_offset_imm(x86::Assembler &a, uint32 bytes_dst, uint32 kind_dst, int32 reg_no_src, int32 base, - int32 offset) + int32 offset, bool atomic) { x86::Mem m((uintptr_t)(base + offset), bytes_dst); +#if WASM_ENABLE_SHARED_MEMORY != 0 + if (atomic) + return xchg_r_to_m(a, bytes_dst, kind_dst, m, reg_no_src); +#endif return mov_r_to_m(a, bytes_dst, kind_dst, m, reg_no_src); } @@ -985,9 +1064,14 @@ st_r_to_base_imm_offset_imm(x86::Assembler &a, uint32 bytes_dst, */ static bool st_r_to_base_imm_offset_r(x86::Assembler &a, uint32 bytes_dst, uint32 kind_dst, - int32 reg_no_src, int32 base, int32 reg_no_offset) + int32 reg_no_src, int32 base, int32 reg_no_offset, + bool atomic) { x86::Mem m(regs_i64[reg_no_offset], base, bytes_dst); +#if WASM_ENABLE_SHARED_MEMORY != 0 + if (atomic) + return xchg_r_to_m(a, bytes_dst, kind_dst, m, reg_no_src); +#endif return mov_r_to_m(a, bytes_dst, kind_dst, m, reg_no_src); } @@ -1007,9 +1091,14 @@ st_r_to_base_imm_offset_r(x86::Assembler &a, uint32 bytes_dst, uint32 kind_dst, */ static bool st_r_to_base_r_offset_imm(x86::Assembler &a, uint32 bytes_dst, uint32 kind_dst, - int32 reg_no_src, int32 reg_no_base, int32 offset) + int32 reg_no_src, int32 reg_no_base, int32 offset, + bool atomic) { x86::Mem m(regs_i64[reg_no_base], offset, bytes_dst); +#if WASM_ENABLE_SHARED_MEMORY != 0 + if (atomic) + return xchg_r_to_m(a, bytes_dst, kind_dst, m, reg_no_src); +#endif return mov_r_to_m(a, bytes_dst, kind_dst, m, reg_no_src); } @@ -1031,9 +1120,13 @@ st_r_to_base_r_offset_imm(x86::Assembler &a, uint32 bytes_dst, uint32 kind_dst, static bool st_r_to_base_r_offset_r(x86::Assembler &a, uint32 bytes_dst, uint32 kind_dst, int32 reg_no_src, int32 reg_no_base, - int32 reg_no_offset) + int32 reg_no_offset, bool atomic) { x86::Mem m(regs_i64[reg_no_base], regs_i64[reg_no_offset], 0, 0, bytes_dst); +#if WASM_ENABLE_SHARED_MEMORY != 0 + if (atomic) + return xchg_r_to_m(a, bytes_dst, kind_dst, m, reg_no_src); +#endif return mov_r_to_m(a, bytes_dst, kind_dst, m, reg_no_src); } @@ -1058,6 +1151,37 @@ imm_set_value(Imm &imm, void *data, uint32 bytes) } } +#if WASM_ENABLE_SHARED_MEMORY != 0 +static uint32 +mov_imm_to_free_reg(x86::Assembler &a, Imm &imm, uint32 bytes) +{ + uint32 reg_no; + + switch (bytes) { + case 1: + reg_no = REG_I8_FREE_IDX; + a.mov(regs_i8[reg_no], imm); + break; + case 2: + reg_no = REG_I16_FREE_IDX; + a.mov(regs_i16[reg_no], imm); + break; + case 4: + reg_no = REG_I32_FREE_IDX; + a.mov(regs_i32[reg_no], imm); + break; + case 8: + reg_no = REG_I64_FREE_IDX; + a.mov(regs_i64[reg_no], imm); + break; + default: + bh_assert(0); + } + + return reg_no; +} +#endif + /** * Encode storing int32 imm data to memory with imm base and imm offset * @@ -1072,11 +1196,18 @@ imm_set_value(Imm &imm, void *data, uint32 bytes) */ static bool st_imm_to_base_imm_offset_imm(x86::Assembler &a, uint32 bytes_dst, - void *data_src, int32 base, int32 offset) + void *data_src, int32 base, int32 offset, + bool atomic) { x86::Mem m((uintptr_t)(base + offset), bytes_dst); Imm imm; imm_set_value(imm, data_src, bytes_dst); +#if WASM_ENABLE_SHARED_MEMORY != 0 + uint32 reg_no_src = mov_imm_to_free_reg(a, imm, bytes_dst); + if (atomic) { + return xchg_r_to_m(a, bytes_dst, JIT_REG_KIND_I64, m, reg_no_src); + } +#endif return mov_imm_to_m(a, m, imm, bytes_dst); } @@ -1095,11 +1226,17 @@ st_imm_to_base_imm_offset_imm(x86::Assembler &a, uint32 bytes_dst, */ static bool st_imm_to_base_imm_offset_r(x86::Assembler &a, uint32 bytes_dst, void *data_src, - int32 base, int32 reg_no_offset) + int32 base, int32 reg_no_offset, bool atomic) { x86::Mem m(regs_i64[reg_no_offset], base, bytes_dst); Imm imm; imm_set_value(imm, data_src, bytes_dst); +#if WASM_ENABLE_SHARED_MEMORY != 0 + uint32 reg_no_src = mov_imm_to_free_reg(a, imm, bytes_dst); + if (atomic) { + return xchg_r_to_m(a, bytes_dst, JIT_REG_KIND_I64, m, reg_no_src); + } +#endif return mov_imm_to_m(a, m, imm, bytes_dst); } @@ -1118,11 +1255,17 @@ st_imm_to_base_imm_offset_r(x86::Assembler &a, uint32 bytes_dst, void *data_src, */ static bool st_imm_to_base_r_offset_imm(x86::Assembler &a, uint32 bytes_dst, void *data_src, - int32 reg_no_base, int32 offset) + int32 reg_no_base, int32 offset, bool atomic) { x86::Mem m(regs_i64[reg_no_base], offset, bytes_dst); Imm imm; imm_set_value(imm, data_src, bytes_dst); +#if WASM_ENABLE_SHARED_MEMORY != 0 + uint32 reg_no_src = mov_imm_to_free_reg(a, imm, bytes_dst); + if (atomic) { + return xchg_r_to_m(a, bytes_dst, JIT_REG_KIND_I64, m, reg_no_src); + } +#endif return mov_imm_to_m(a, m, imm, bytes_dst); } @@ -1142,11 +1285,17 @@ st_imm_to_base_r_offset_imm(x86::Assembler &a, uint32 bytes_dst, void *data_src, */ static bool st_imm_to_base_r_offset_r(x86::Assembler &a, uint32 bytes_dst, void *data_src, - int32 reg_no_base, int32 reg_no_offset) + int32 reg_no_base, int32 reg_no_offset, bool atomic) { x86::Mem m(regs_i64[reg_no_base], regs_i64[reg_no_offset], 0, 0, bytes_dst); Imm imm; imm_set_value(imm, data_src, bytes_dst); +#if WASM_ENABLE_SHARED_MEMORY != 0 + uint32 reg_no_src = mov_imm_to_free_reg(a, imm, bytes_dst); + if (atomic) { + return xchg_r_to_m(a, bytes_dst, JIT_REG_KIND_I64, m, reg_no_src); + } +#endif return mov_imm_to_m(a, m, imm, bytes_dst); } @@ -4550,82 +4699,84 @@ cmp_r_imm_to_r_f64(x86::Assembler &a, int32 reg_no_dst, int32 reg_no1_src, * Encode insn sd: ST_type r0, r1, r2 * @param kind the data kind, such as I32, I64, F32 and F64 * @param bytes_dst the byte number of dst data - */ -#define ST_R_R_R(kind, type, bytes_dst) \ - do { \ - type data_src = 0; \ - int32 reg_no_src = 0, reg_no_base = 0, reg_no_offset = 0; \ - int32 base = 0, offset = 0; \ - bool _ret = false; \ - \ - if (jit_reg_is_const(r1)) { \ - CHECK_KIND(r1, JIT_REG_KIND_I32); \ - } \ - else { \ - CHECK_KIND(r1, JIT_REG_KIND_I64); \ - } \ - if (jit_reg_is_const(r2)) { \ - CHECK_KIND(r2, JIT_REG_KIND_I32); \ - } \ - else { \ - CHECK_KIND(r2, JIT_REG_KIND_I64); \ - } \ - \ - if (jit_reg_is_const(r0)) \ - data_src = jit_cc_get_const_##kind(cc, r0); \ - else { \ - reg_no_src = jit_reg_no(r0); \ - CHECK_REG_NO(reg_no_src, jit_reg_kind(r0)); \ - } \ - if (jit_reg_is_const(r1)) \ - base = jit_cc_get_const_I32(cc, r1); \ - else { \ - reg_no_base = jit_reg_no(r1); \ - CHECK_REG_NO(reg_no_base, jit_reg_kind(r1)); \ - } \ - if (jit_reg_is_const(r2)) \ - offset = jit_cc_get_const_I32(cc, r2); \ - else { \ - reg_no_offset = jit_reg_no(r2); \ - CHECK_REG_NO(reg_no_offset, jit_reg_kind(r2)); \ - } \ - \ - if (jit_reg_is_const(r0)) { \ - if (jit_reg_is_const(r1)) { \ - if (jit_reg_is_const(r2)) \ - _ret = st_imm_to_base_imm_offset_imm( \ - a, bytes_dst, &data_src, base, offset); \ - else \ - _ret = st_imm_to_base_imm_offset_r( \ - a, bytes_dst, &data_src, base, reg_no_offset); \ - } \ - else if (jit_reg_is_const(r2)) \ - _ret = st_imm_to_base_r_offset_imm(a, bytes_dst, &data_src, \ - reg_no_base, offset); \ - else \ - _ret = st_imm_to_base_r_offset_r(a, bytes_dst, &data_src, \ - reg_no_base, reg_no_offset); \ - } \ - else if (jit_reg_is_const(r1)) { \ - if (jit_reg_is_const(r2)) \ - _ret = st_r_to_base_imm_offset_imm(a, bytes_dst, \ - JIT_REG_KIND_##kind, \ - reg_no_src, base, offset); \ - else \ - _ret = st_r_to_base_imm_offset_r( \ - a, bytes_dst, JIT_REG_KIND_##kind, reg_no_src, base, \ - reg_no_offset); \ - } \ - else if (jit_reg_is_const(r2)) \ - _ret = \ - st_r_to_base_r_offset_imm(a, bytes_dst, JIT_REG_KIND_##kind, \ - reg_no_src, reg_no_base, offset); \ - else \ - _ret = st_r_to_base_r_offset_r(a, bytes_dst, JIT_REG_KIND_##kind, \ - reg_no_src, reg_no_base, \ - reg_no_offset); \ - if (!_ret) \ - GOTO_FAIL; \ + * @param atomic whether it's atomic store + */ +#define ST_R_R_R(kind, type, bytes_dst, atomic) \ + do { \ + type data_src = 0; \ + int32 reg_no_src = 0, reg_no_base = 0, reg_no_offset = 0; \ + int32 base = 0, offset = 0; \ + bool _ret = false; \ + \ + if (jit_reg_is_const(r1)) { \ + CHECK_KIND(r1, JIT_REG_KIND_I32); \ + } \ + else { \ + CHECK_KIND(r1, JIT_REG_KIND_I64); \ + } \ + if (jit_reg_is_const(r2)) { \ + CHECK_KIND(r2, JIT_REG_KIND_I32); \ + } \ + else { \ + CHECK_KIND(r2, JIT_REG_KIND_I64); \ + } \ + \ + if (jit_reg_is_const(r0)) \ + data_src = jit_cc_get_const_##kind(cc, r0); \ + else { \ + reg_no_src = jit_reg_no(r0); \ + CHECK_REG_NO(reg_no_src, jit_reg_kind(r0)); \ + } \ + if (jit_reg_is_const(r1)) \ + base = jit_cc_get_const_I32(cc, r1); \ + else { \ + reg_no_base = jit_reg_no(r1); \ + CHECK_REG_NO(reg_no_base, jit_reg_kind(r1)); \ + } \ + if (jit_reg_is_const(r2)) \ + offset = jit_cc_get_const_I32(cc, r2); \ + else { \ + reg_no_offset = jit_reg_no(r2); \ + CHECK_REG_NO(reg_no_offset, jit_reg_kind(r2)); \ + } \ + \ + if (jit_reg_is_const(r0)) { \ + if (jit_reg_is_const(r1)) { \ + if (jit_reg_is_const(r2)) \ + _ret = st_imm_to_base_imm_offset_imm( \ + a, bytes_dst, &data_src, base, offset, atomic); \ + else \ + _ret = st_imm_to_base_imm_offset_r( \ + a, bytes_dst, &data_src, base, reg_no_offset, atomic); \ + } \ + else if (jit_reg_is_const(r2)) \ + _ret = st_imm_to_base_r_offset_imm( \ + a, bytes_dst, &data_src, reg_no_base, offset, atomic); \ + else \ + _ret = st_imm_to_base_r_offset_r(a, bytes_dst, &data_src, \ + reg_no_base, reg_no_offset, \ + atomic); \ + } \ + else if (jit_reg_is_const(r1)) { \ + if (jit_reg_is_const(r2)) \ + _ret = st_r_to_base_imm_offset_imm( \ + a, bytes_dst, JIT_REG_KIND_##kind, reg_no_src, base, \ + offset, atomic); \ + else \ + _ret = st_r_to_base_imm_offset_r( \ + a, bytes_dst, JIT_REG_KIND_##kind, reg_no_src, base, \ + reg_no_offset, atomic); \ + } \ + else if (jit_reg_is_const(r2)) \ + _ret = st_r_to_base_r_offset_imm(a, bytes_dst, \ + JIT_REG_KIND_##kind, reg_no_src, \ + reg_no_base, offset, atomic); \ + else \ + _ret = st_r_to_base_r_offset_r(a, bytes_dst, JIT_REG_KIND_##kind, \ + reg_no_src, reg_no_base, \ + reg_no_offset, atomic); \ + if (!_ret) \ + GOTO_FAIL; \ } while (0) /** @@ -5823,13 +5974,23 @@ lower_callnative(JitCompContext *cc, x86::Assembler &a, JitInsn *insn) a.call(regs_i64[REG_RAX_IDX]); if (ret_reg) { - bh_assert((jit_reg_kind(ret_reg) == JIT_REG_KIND_I32 - && jit_reg_no(ret_reg) == REG_EAX_IDX) - || (jit_reg_kind(ret_reg) == JIT_REG_KIND_I64 - && jit_reg_no(ret_reg) == REG_RAX_IDX) - || ((jit_reg_kind(ret_reg) == JIT_REG_KIND_F32 - || jit_reg_kind(ret_reg) == JIT_REG_KIND_F64) - && jit_reg_no(ret_reg) == 0)); + uint32 ret_reg_no = jit_reg_no(ret_reg); + if (jit_reg_kind(ret_reg) == JIT_REG_KIND_I64) { + CHECK_I64_REG_NO(ret_reg_no); + /* mov res, rax */ + mov_r_to_r_i64(a, ret_reg_no, REG_RAX_IDX); + } + else if (jit_reg_kind(ret_reg) == JIT_REG_KIND_F64) { + CHECK_F64_REG_NO(ret_reg_no); + /* mov res, xmm0_f64 */ + mov_r_to_r_f64(a, ret_reg_no, 0); + } + else { + bh_assert((jit_reg_kind(ret_reg) == JIT_REG_KIND_I32 + && ret_reg_no == REG_EAX_IDX) + || (jit_reg_kind(ret_reg) == JIT_REG_KIND_F32 + && ret_reg_no == 0)); + } } return true; @@ -5860,6 +6021,7 @@ lower_callbc(JitCompContext *cc, x86::Assembler &a, bh_list *jmp_info_list, JitReg xmm0_f64_hreg = jit_reg_new(JIT_REG_KIND_F64, 0); JitReg ret_reg = *(jit_insn_opnd(insn, 0)); JitReg func_reg = *(jit_insn_opnd(insn, 2)); + JitReg func_idx = *(jit_insn_opnd(insn, 3)); JitReg src_reg; int32 func_reg_no; @@ -5870,6 +6032,15 @@ lower_callbc(JitCompContext *cc, x86::Assembler &a, bh_list *jmp_info_list, func_reg_no = jit_reg_no(func_reg); CHECK_I64_REG_NO(func_reg_no); + CHECK_KIND(func_idx, JIT_REG_KIND_I32); + if (jit_reg_is_const(func_idx)) { + imm.setValue(jit_cc_get_const_I32(cc, func_idx)); + a.mov(regs_i64[REG_RDX_IDX], imm); + } + else { + a.movzx(regs_i64[REG_RDX_IDX], regs_i32[jit_reg_no(func_idx)]); + } + node = (JmpInfo *)jit_malloc(sizeof(JmpInfo)); if (!node) GOTO_FAIL; @@ -6217,541 +6388,2732 @@ cast_r_f64_to_r_i64(x86::Assembler &a, int32 reg_no_dst, int32 reg_no_src) GOTO_FAIL; \ } while (0) -bool -jit_codegen_gen_native(JitCompContext *cc) -{ - JitBasicBlock *block; - JitInsn *insn; - JitReg r0, r1, r2, r3; - JmpInfo jmp_info_head; - bh_list *jmp_info_list = (bh_list *)&jmp_info_head; - uint32 label_index, label_num, i; - uint32 *label_offsets = NULL, code_size; -#if CODEGEN_DUMP != 0 - uint32 code_offset = 0; -#endif - bool return_value = false, is_last_insn; - void **jitted_addr; - char *code_buf, *stream; - - JitErrorHandler err_handler; - Environment env(Arch::kX64); - CodeHolder code; - code.init(env); - code.setErrorHandler(&err_handler); - x86::Assembler a(&code); +#if WASM_ENABLE_SHARED_MEMORY != 0 - if (BH_LIST_SUCCESS != bh_list_init(jmp_info_list)) { - jit_set_last_error(cc, "init jmp info list failed"); - return false; +/** + * Encode extend certain bytes in the src register to a I32 or I64 kind value in + * dst register + * + * @param a the assembler to emit the code + * @param bytes_dst the bytes number of the data, + * could be 1(byte), 2(short), 4(int32), 8(int64), + * @param kind_dst the kind of data to extend to, could be I32, I64 + * @param reg_no_src the index of register hold src value + * + * @return true if success, false otherwise + */ +static bool +extend_r_to_r(x86::Assembler &a, uint32 bytes_dst, uint32 kind_dst, + int32 reg_no_src, int32 reg_no_dst) +{ + if (kind_dst == JIT_REG_KIND_I32) { + bh_assert(reg_no_src < 16 && reg_no_dst < 16); + switch (bytes_dst) { + case 1: + extend_r8_to_r32(a, reg_no_dst, reg_no_src, false); + break; + case 2: + extend_r16_to_r32(a, reg_no_dst, reg_no_src, false); + break; + case 4: + mov_r_to_r_i32(a, reg_no_dst, reg_no_src); + break; + default: + bh_assert(0); + return false; + } } - - label_num = jit_cc_label_num(cc); - - if (!(label_offsets = - (uint32 *)jit_calloc(((uint32)sizeof(uint32)) * label_num))) { - jit_set_last_error(cc, "allocate memory failed"); - goto fail; + else if (kind_dst == JIT_REG_KIND_I64) { + bh_assert(reg_no_src < 16 && reg_no_dst < 16); + switch (bytes_dst) { + case 1: + extend_r8_to_r64(a, reg_no_dst, reg_no_src, false); + break; + case 2: + extend_r16_to_r64(a, reg_no_dst, reg_no_src, false); + break; + case 4: + extend_r32_to_r64(a, reg_no_dst, reg_no_src, false); + break; + case 8: + mov_r_to_r_i64(a, reg_no_dst, reg_no_src); + break; + default: + bh_assert(0); + return false; + } } + else { + bh_assert(0); + } + return true; +} - for (i = 0; i < label_num; i++) { - if (i == 0) - label_index = 0; - else if (i == label_num - 1) - label_index = 1; - else - label_index = i + 1; - - label_offsets[label_index] = code.sectionById(0)->buffer().size(); +/** + * Encode atomic compare and exchange, when calling this function, + * value for comparison should be already moved in register + * al/ax/eax/rax + * + * @param a the assembler to emit the code + * @param bytes_dst the bytes number of the data, + * could be 1(byte), 2(short), 4(int32), 8(int64), + * @param kind_dst the kind of data to move, could be I32, I64 + * @param m_dst the dest memory operand + * @param reg_no_xchg the index of register hold exchange value + * + * @return true if success, false otherwise + */ +static bool +at_cmpxchg(x86::Assembler &a, uint32 bytes_dst, uint32 kind_dst, + int32 reg_no_xchg, x86::Mem &m_dst) +{ + bh_assert((kind_dst == JIT_REG_KIND_I32 && bytes_dst <= 4) + || kind_dst == JIT_REG_KIND_I64); + bh_assert(reg_no_xchg < 16); + switch (bytes_dst) { + case 1: + a.lock().cmpxchg(m_dst, regs_i8[reg_no_xchg]); + break; + case 2: + a.lock().cmpxchg(m_dst, regs_i16[reg_no_xchg]); + break; + case 4: + a.lock().cmpxchg(m_dst, regs_i32[reg_no_xchg]); + break; + case 8: + a.lock().cmpxchg(m_dst, regs_i64[reg_no_xchg]); + break; + default: + bh_assert(0); + return false; + } + return true; +} - block = *jit_annl_basic_block( - cc, jit_reg_new(JIT_REG_KIND_L32, label_index)); +/** + * Encode atomic compare and exchange: load value into a register from + * memory with reg base and reg offset, compare (expected) reg data with the + * loaded value, if equal, store the (replacement) reg data to the same + * memory, else, do nothing. Either way, returns the loaded value + * + * @param a the assembler to emit the code + * @param bytes_dst the bytes number of the data to actual operated on(load, + * compare, replacement) could be 1(byte), 2(short), 4(int32), 8(int64) + * @param reg_no_xchg the no of register that stores the conditionally + * replacement value + * @param reg_no_base the no of register that stores the base address + * of src&dst memory + * @param reg_no_offset the no of register that stores the offset address + * of src&dst memory + * @return true if success, false otherwise + */ +static bool +at_cmpxchg_r_ra_base_r_offset_r(x86::Assembler &a, uint32 bytes_dst, + uint32 kind_dst, int32 reg_no_xchg, + int32 reg_no_base, int32 reg_no_offset) +{ + x86::Mem m(regs_i64[reg_no_base], regs_i64[reg_no_offset], 0, 0, bytes_dst); + return at_cmpxchg(a, bytes_dst, kind_dst, reg_no_xchg, m) + && extend_r_to_r(a, bytes_dst, kind_dst, REG_RAX_IDX, REG_RAX_IDX); +} -#if CODEGEN_DUMP != 0 - os_printf("\nL%d:\n\n", label_index); -#endif +/** + * Encode atomic compare and exchange: load value into a register from + * memory with reg base and imm offset, compare (expected) reg data with the + * loaded value, if equal, store the (replacement) reg data to the same + * memory, else, do nothing. Either way, returns the loaded value + * + * @param a the assembler to emit the code + * @param bytes_dst the bytes number of the data to actual operated on(load, + * compare, replacement) could be 1(byte), 2(short), 4(int32), 8(int64) + * @param reg_no_xchg the no of register that stores the conditionally + * replacement value + * @param reg_no_base the no of register that stores the base address + * of src&dst memory + * @param offset the offset address of the memory + * @return true if success, false otherwise + */ +static bool +at_cmpxchg_r_ra_base_r_offset_imm(x86::Assembler &a, uint32 bytes_dst, + uint32 kind_dst, int32 reg_no_xchg, + int32 reg_no_base, int32 offset) +{ + x86::Mem m(regs_i64[reg_no_base], offset, bytes_dst); + return at_cmpxchg(a, bytes_dst, kind_dst, reg_no_xchg, m) + && extend_r_to_r(a, bytes_dst, kind_dst, REG_RAX_IDX, REG_RAX_IDX); +} - JIT_FOREACH_INSN(block, insn) +/** + * Encode atomic compare and exchange: load value into a register from + * memory with reg base and reg offset, compare (expected) reg data with the + * loaded value, if equal, store the (replacement) imm data to the same + * memory, else, do nothing. Either way, returns the loaded value + * + * @param a the assembler to emit the code + * @param bytes_dst the bytes number of the data to actual operated on(load, + * compare, replacement) could be 1(byte), 2(short), 4(int32), 8(int64) + * @param data_xchg the immediate data for exchange(conditionally replacment + * value) + * @param reg_no_base the no of register that stores the base address + * of src&dst memory + * @param reg_no_offset the no of register that stores the offset address + * of src&dst memory + * @return true if success, false otherwise + */ +static bool +at_cmpxchg_imm_ra_base_r_offset_r(x86::Assembler &a, uint32 bytes_dst, + uint32 kind_dst, void *data_xchg, + int32 reg_no_base, int32 reg_no_offset) +{ + x86::Mem m(regs_i64[reg_no_base], regs_i64[reg_no_offset], 0, 0, bytes_dst); + Imm imm; + imm_set_value(imm, data_xchg, bytes_dst); + uint32 reg_no_xchg = mov_imm_to_free_reg(a, imm, bytes_dst); + return at_cmpxchg(a, bytes_dst, kind_dst, reg_no_xchg, m) + && extend_r_to_r(a, bytes_dst, kind_dst, REG_RAX_IDX, REG_RAX_IDX); +} + +/** + * Encode atomic compare and exchange: load value into a register from + * memory with reg base and imm offset, compare (expected) reg data with the + * loaded value, if equal, store the (replacement) imm data to the same + * memory, else, do nothing. Either way, returns the loaded value + * + * @param a the assembler to emit the code + * @param bytes_dst the bytes number of the data to actual operated on(load, + * compare, replacement) could be 1(byte), 2(short), 4(int32), 8(int64) + * @param data_xchg the immediate data for exchange(conditionally replacment + * value) + * @param reg_no_base the no of register that stores the base address + * of src&dst memory + * @param offset the offset address of the memory + * @return true if success, false otherwise + */ +static bool +at_cmpxchg_imm_ra_base_r_offset_imm(x86::Assembler &a, uint32 bytes_dst, + uint32 kind_dst, void *data_xchg, + int32 reg_no_base, int32 offset) +{ + x86::Mem m(regs_i64[reg_no_base], offset, bytes_dst); + Imm imm; + imm_set_value(imm, data_xchg, bytes_dst); + uint32 reg_no_xchg = mov_imm_to_free_reg(a, imm, bytes_dst); + return at_cmpxchg(a, bytes_dst, kind_dst, reg_no_xchg, m) + && extend_r_to_r(a, bytes_dst, kind_dst, REG_RAX_IDX, REG_RAX_IDX); +} + +/** + * Encode insn cmpxchg: CMPXCHG_type r0, r1, r2, r3, r4 + * @param kind the data kind, can only be I32 or I64 + * @param bytes_dst the byte number of dst data + */ +#define CMPXCHG_R_R_R_R_R(kind, type, bytes_dst) \ + do { \ + type data_xchg = 0; \ + int32 reg_no_xchg = 0, reg_no_cmp = 0, reg_no_base = 0, \ + reg_no_offset = 0; \ + int32 offset = 0; \ + bool _ret = false; \ + if (jit_reg_is_const(r3)) { \ + CHECK_KIND(r3, JIT_REG_KIND_I32); \ + } \ + else { \ + CHECK_KIND(r3, JIT_REG_KIND_I64); \ + } \ + /* r1: expected value(it must in register a) \ + * r2: memory base addr can't be const */ \ + CHECK_NCONST(r1); \ + reg_no_cmp = jit_reg_no(r1); \ + bh_assert(reg_no_cmp == REG_EAX_IDX || reg_no_cmp == REG_RAX_IDX); \ + CHECK_REG_NO(reg_no_cmp, jit_reg_kind(r1)); \ + CHECK_NCONST(r2); \ + reg_no_base = jit_reg_no(r2); \ + CHECK_REG_NO(reg_no_base, jit_reg_kind(r2)); \ + /* r0: replacement value r3: offset can be const */ \ + if (jit_reg_is_const(r0)) \ + data_xchg = jit_cc_get_const_##kind(cc, r0); \ + else { \ + reg_no_xchg = jit_reg_no(r0); \ + CHECK_REG_NO(reg_no_xchg, jit_reg_kind(r0)); \ + } \ + if (jit_reg_is_const(r3)) \ + offset = jit_cc_get_const_I32(cc, r3); \ + else { \ + reg_no_offset = jit_reg_no(r3); \ + CHECK_REG_NO(reg_no_offset, jit_reg_kind(r3)); \ + } \ + \ + if (jit_reg_is_const(r0)) { \ + if (jit_reg_is_const(r3)) \ + _ret = at_cmpxchg_imm_ra_base_r_offset_imm( \ + a, bytes_dst, JIT_REG_KIND_##kind, &data_xchg, \ + reg_no_base, offset); \ + else \ + _ret = at_cmpxchg_imm_ra_base_r_offset_r( \ + a, bytes_dst, JIT_REG_KIND_##kind, &data_xchg, \ + reg_no_base, reg_no_offset); \ + } \ + else { \ + if (jit_reg_is_const(r3)) \ + _ret = at_cmpxchg_r_ra_base_r_offset_imm( \ + a, bytes_dst, JIT_REG_KIND_##kind, reg_no_xchg, \ + reg_no_base, offset); \ + else \ + _ret = at_cmpxchg_r_ra_base_r_offset_r( \ + a, bytes_dst, JIT_REG_KIND_##kind, reg_no_xchg, \ + reg_no_base, reg_no_offset); \ + } \ + if (!_ret) \ + GOTO_FAIL; \ + } while (0) + +/** + * Encode negate a value in the register + * + * @param a the assembler to emit the code + * @param bytes_dst the bytes number of the data, + * could be 1(byte), 2(short), 4(int32), 8(int64), + * @param kind_dst the kind of data to move, could be I32, I64 + * @param reg_no_src the index of register hold src value + * + * @return true if success, false otherwise + */ +static bool +neg_r(x86::Assembler &a, uint32 bytes_dst, uint32 kind_dst, int32 reg_no_src) +{ + bh_assert((kind_dst == JIT_REG_KIND_I32 && bytes_dst <= 4) + || kind_dst == JIT_REG_KIND_I64); + bh_assert(reg_no_src < 16); + switch (bytes_dst) { + case 1: + a.neg(regs_i8[reg_no_src]); + break; + case 2: + a.neg(regs_i16[reg_no_src]); + break; + case 4: + a.neg(regs_i32[reg_no_src]); + break; + case 8: + a.neg(regs_i64[reg_no_src]); + break; + default: + bh_assert(0); + return false; + } + return true; +} + +/** + * Encode atomic exchange and add + * + * @param a the assembler to emit the code + * @param bytes_dst the bytes number of the data, + * could be 1(byte), 2(short), 4(int32), 8(int64), + * @param kind_dst the kind of data to move, could be I32, I64 + * @param reg_no_src the index of register hold operand value of add operation + * @param m_dst the dest memory operand + * + * @return true if success, false otherwise + */ +static bool +at_xadd(x86::Assembler &a, uint32 bytes_dst, uint32 kind_dst, int32 reg_no_src, + x86::Mem &m_dst) +{ + bh_assert((kind_dst == JIT_REG_KIND_I32 && bytes_dst <= 4) + || kind_dst == JIT_REG_KIND_I64); + bh_assert(reg_no_src < 16); + switch (bytes_dst) { + case 1: + a.lock().xadd(m_dst, regs_i8[reg_no_src]); + break; + case 2: + a.lock().xadd(m_dst, regs_i16[reg_no_src]); + break; + case 4: + a.lock().xadd(m_dst, regs_i32[reg_no_src]); + break; + case 8: + a.lock().xadd(m_dst, regs_i64[reg_no_src]); + break; + default: + bh_assert(0); + return false; + } + + return true; +} + +/** + * Encode atomic rmw add: load value into a register from memory + * with reg base and reg offset, add loaded value with imm data, store back + * + * @param a the assembler to emit the code + * @param bytes_dst the bytes number of the data to actual operated on(load, + * compare, replacement) could be 1(byte), 2(short), 4(int32), 8(int64) + * @param reg_no_dst the no of register that stores the returned value + * @param data_src the immediate data(first operand) + * @param reg_no_base the no of register that stores the base address + * of src&dst memory(second operand&store back) + * @param offset the offset address of the memory + * @return true if success, false otherwise + */ +static bool +at_rmw_add_imm_base_r_offset_imm(x86::Assembler &a, uint32 bytes_dst, + uint32 kind_dst, int32 reg_no_dst, + void *data_src, int32 reg_no_base, + int32 offset) +{ + x86::Mem m(regs_i64[reg_no_base], offset, bytes_dst); + Imm imm; + imm_set_value(imm, data_src, bytes_dst); + uint32 reg_no_src = mov_imm_to_free_reg(a, imm, bytes_dst); + return at_xadd(a, bytes_dst, kind_dst, reg_no_src, m) + && extend_r_to_r(a, bytes_dst, kind_dst, reg_no_src, reg_no_dst); +} + +/** + * Encode atomic rmw add: load value into a register from memory + * with reg base and reg offset, add loaded value with imm data, store back + * + * @param a the assembler to emit the code + * @param bytes_dst the bytes number of the data to actual operated on(load, + * compare, replacement) could be 1(byte), 2(short), 4(int32), 8(int64) + * @param reg_no_dst the no of register that stores the returned value + * @param data_src the immediate data(second operand) + * @param reg_no_base the no of register that stores the base address + * of src&dst memory(first operand&store back location) + * @param reg_no_offset the no of register that stores the offset of the memory + * @return true if success, false otherwise + */ +static bool +at_rmw_add_imm_base_r_offset_r(x86::Assembler &a, uint32 bytes_dst, + uint32 kind_dst, int32 reg_no_dst, + void *data_src, int32 reg_no_base, + int32 reg_no_offset) +{ + x86::Mem m(regs_i64[reg_no_base], regs_i64[reg_no_offset], 0, 0, bytes_dst); + Imm imm; + imm_set_value(imm, data_src, bytes_dst); + uint32 reg_no_src = mov_imm_to_free_reg(a, imm, bytes_dst); + return at_xadd(a, bytes_dst, kind_dst, reg_no_src, m) + && extend_r_to_r(a, bytes_dst, kind_dst, reg_no_src, reg_no_dst); +} + +/** + * Encode atomic rmw add: load value into a register from memory + * with reg base and imm offset, add loaded value with reg data, store back + * + * @param a the assembler to emit the code + * @param bytes_dst the bytes number of the data to actual operated on(load, + * compare, replacement) could be 1(byte), 2(short), 4(int32), 8(int64) + * @param reg_no_dst the no of register that stores the returned value + * @param reg_no_src the no of register store the src data(second operand) + * @param reg_no_base the no of register that stores the base address + * of src&dst memory(first operand&store back location) + * @param offset the offset address of the memory + * @return true if success, false otherwise + */ +static bool +at_rmw_add_r_base_r_offset_imm(x86::Assembler &a, uint32 bytes_dst, + uint32 kind_dst, int32 reg_no_dst, + int32 reg_no_src, int32 reg_no_base, + int32 offset) +{ + x86::Mem m(regs_i64[reg_no_base], offset, bytes_dst); + return at_xadd(a, bytes_dst, kind_dst, reg_no_src, m) + && extend_r_to_r(a, bytes_dst, kind_dst, reg_no_src, reg_no_dst); +} + +/** + * Encode atomic rmw add: load value into a register from memory + * with reg base and reg offset, add loaded value with reg data, store back + * + * @param a the assembler to emit the code + * @param bytes_dst the bytes number of the data to actual operated on(load, + * compare, replacement) could be 1(byte), 2(short), 4(int32), 8(int64) + * @param reg_no_dst the no of register that stores the returned value + * @param reg_no_src the no of register store the src data(second operand) + * @param reg_no_base the no of register that stores the base address + * of src&dst memory(first operand&store back) + * @param reg_no_offset the no of register that stores the offset of the memory + * @return true if success, false otherwise + */ +static bool +at_rmw_add_r_base_r_offset_r(x86::Assembler &a, uint32 bytes_dst, + uint32 kind_dst, int32 reg_no_dst, + int32 reg_no_src, int32 reg_no_base, + int32 reg_no_offset) +{ + x86::Mem m(regs_i64[reg_no_base], regs_i64[reg_no_offset], 0, 0, bytes_dst); + return at_xadd(a, bytes_dst, kind_dst, reg_no_src, m) + && extend_r_to_r(a, bytes_dst, kind_dst, reg_no_src, reg_no_dst); +} + +/** + * Encode atomic rmw sub: load value into a register from memory + * with reg base and reg offset, sub loaded value with imm data, store back + * + * @param a the assembler to emit the code + * @param bytes_dst the bytes number of the data to actual operated on(load, + * compare, replacement) could be 1(byte), 2(short), 4(int32), 8(int64) + * @param reg_no_dst the no of register that stores the returned value + * @param data_src the immediate data(first operand) + * @param reg_no_base the no of register that stores the base address + * of src&dst memory(second operand&store back) + * @param offset the offset address of the memory + * @return true if success, false otherwise + */ +static bool +at_rmw_sub_imm_base_r_offset_imm(x86::Assembler &a, uint32 bytes_dst, + uint32 kind_dst, int32 reg_no_dst, + void *data_src, int32 reg_no_base, + int32 offset) +{ + x86::Mem m(regs_i64[reg_no_base], offset, bytes_dst); + Imm imm; + imm_set_value(imm, data_src, bytes_dst); + uint32 reg_no_src = mov_imm_to_free_reg(a, imm, bytes_dst); + return neg_r(a, bytes_dst, kind_dst, reg_no_src) + && at_xadd(a, bytes_dst, kind_dst, reg_no_src, m) + && extend_r_to_r(a, bytes_dst, kind_dst, reg_no_src, reg_no_dst); +} + +/** + * Encode atomic rmw sub: load value into a register from memory + * with reg base and reg offset, sub loaded value with imm data, store back + * + * @param a the assembler to emit the code + * @param bytes_dst the bytes number of the data to actual operated on(load, + * compare, replacement) could be 1(byte), 2(short), 4(int32), 8(int64) + * @param reg_no_dst the no of register that stores the returned value + * @param data_src the immediate data(second operand) + * @param reg_no_base the no of register that stores the base address + * of src&dst memory(first operand&store back location) + * @param reg_no_offset the no of register that stores the offset of the memory + * @return true if success, false otherwise + */ +static bool +at_rmw_sub_imm_base_r_offset_r(x86::Assembler &a, uint32 bytes_dst, + uint32 kind_dst, int32 reg_no_dst, + void *data_src, int32 reg_no_base, + int32 reg_no_offset) +{ + x86::Mem m(regs_i64[reg_no_base], regs_i64[reg_no_offset], 0, 0, bytes_dst); + Imm imm; + imm_set_value(imm, data_src, bytes_dst); + uint32 reg_no_src = mov_imm_to_free_reg(a, imm, bytes_dst); + return neg_r(a, bytes_dst, kind_dst, reg_no_src) + && at_xadd(a, bytes_dst, kind_dst, reg_no_src, m) + && extend_r_to_r(a, bytes_dst, kind_dst, reg_no_src, reg_no_dst); +} + +/** + * Encode atomic rmw sub: load value into a register from memory + * with reg base and imm offset, sub loaded value with reg data, store back + * + * @param a the assembler to emit the code + * @param bytes_dst the bytes number of the data to actual operated on(load, + * compare, replacement) could be 1(byte), 2(short), 4(int32), 8(int64) + * @param reg_no_dst the no of register that stores the returned value + * @param reg_no_src the no of register store the src data(second operand) + * @param reg_no_base the no of register that stores the base address + * of src&dst memory(first operand&store back location) + * @param offset the offset address of the memory + * @return true if success, false otherwise + */ +static bool +at_rmw_sub_r_base_r_offset_imm(x86::Assembler &a, uint32 bytes_dst, + uint32 kind_dst, int32 reg_no_dst, + int32 reg_no_src, int32 reg_no_base, + int32 offset) +{ + x86::Mem m(regs_i64[reg_no_base], offset, bytes_dst); + return neg_r(a, bytes_dst, kind_dst, reg_no_src) + && at_xadd(a, bytes_dst, kind_dst, reg_no_src, m) + && extend_r_to_r(a, bytes_dst, kind_dst, reg_no_src, reg_no_dst); +} + +/** + * Encode atomic rmw sub: load value into a register from memory + * with reg base and reg offset, sub loaded value with reg data, store back + * + * @param a the assembler to emit the code + * @param bytes_dst the bytes number of the data to actual operated on(load, + * compare, replacement) could be 1(byte), 2(short), 4(int32), 8(int64) + * @param reg_no_dst the no of register that stores the returned value + * @param reg_no_src the no of register store the src data(second operand) + * @param reg_no_base the no of register that stores the base address + * of src&dst memory(first operand&store back) + * @param reg_no_offset the no of register that stores the offset of the memory + * @return true if success, false otherwise + */ +static bool +at_rmw_sub_r_base_r_offset_r(x86::Assembler &a, uint32 bytes_dst, + uint32 kind_dst, int32 reg_no_dst, + int32 reg_no_src, int32 reg_no_base, + int32 reg_no_offset) +{ + x86::Mem m(regs_i64[reg_no_base], regs_i64[reg_no_offset], 0, 0, bytes_dst); + return neg_r(a, bytes_dst, kind_dst, reg_no_src) + && at_xadd(a, bytes_dst, kind_dst, reg_no_src, m) + && extend_r_to_r(a, bytes_dst, kind_dst, reg_no_src, reg_no_dst); +} + +/** + * Encode atomic rmw xchg: load value into a register from memory + * with reg base and reg offset, exchange loaded value with imm data, store back + * + * @param a the assembler to emit the code + * @param bytes_dst the bytes number of the data to actual operated on(load, + * compare, replacement) could be 1(byte), 2(short), 4(int32), 8(int64) + * @param reg_no_dst the no of register that stores the returned value + * @param data_src the immediate data(first operand) + * @param reg_no_base the no of register that stores the base address + * of src&dst memory(second operand&store back) + * @param offset the offset address of the memory + * @return true if success, false otherwise + */ +static bool +at_rmw_xchg_imm_base_r_offset_imm(x86::Assembler &a, uint32 bytes_dst, + uint32 kind_dst, int32 reg_no_dst, + void *data_src, int32 reg_no_base, + int32 offset) +{ + x86::Mem m(regs_i64[reg_no_base], offset, bytes_dst); + Imm imm; + imm_set_value(imm, data_src, bytes_dst); + uint32 reg_no_src = mov_imm_to_free_reg(a, imm, bytes_dst); + return xchg_r_to_m(a, bytes_dst, kind_dst, m, reg_no_src) + && extend_r_to_r(a, bytes_dst, kind_dst, reg_no_src, reg_no_dst); +} + +/** + * Encode atomic rmw xchg: load value into a register from memory + * with reg base and reg offset, exchange loaded value with imm data, store back + * + * @param a the assembler to emit the code + * @param bytes_dst the bytes number of the data to actual operated on(load, + * compare, replacement) could be 1(byte), 2(short), 4(int32), 8(int64) + * @param reg_no_dst the no of register that stores the returned value + * @param data_src the immediate data(second operand) + * @param reg_no_base the no of register that stores the base address + * of src&dst memory(first operand&store back location) + * @param reg_no_offset the no of register that stores the offset of the memory + * @return true if success, false otherwise + */ +static bool +at_rmw_xchg_imm_base_r_offset_r(x86::Assembler &a, uint32 bytes_dst, + uint32 kind_dst, int32 reg_no_dst, + void *data_src, int32 reg_no_base, + int32 reg_no_offset) +{ + x86::Mem m(regs_i64[reg_no_base], regs_i64[reg_no_offset], 0, 0, bytes_dst); + Imm imm; + imm_set_value(imm, data_src, bytes_dst); + uint32 reg_no_src = mov_imm_to_free_reg(a, imm, bytes_dst); + return xchg_r_to_m(a, bytes_dst, kind_dst, m, reg_no_src) + && extend_r_to_r(a, bytes_dst, kind_dst, reg_no_src, reg_no_dst); +} + +/** + * Encode atomic rmw xchg: load value into a register from memory + * with reg base and imm offset, exchange loaded value with reg data, store back + * + * @param a the assembler to emit the code + * @param bytes_dst the bytes number of the data to actual operated on(load, + * compare, replacement) could be 1(byte), 2(short), 4(int32), 8(int64) + * @param reg_no_dst the no of register that stores the returned value + * @param reg_no_src the no of register store the src data(second operand) + * @param reg_no_base the no of register that stores the base address + * of src&dst memory(first operand&store back location) + * @param offset the offset address of the memory + * @return true if success, false otherwise + */ +static bool +at_rmw_xchg_r_base_r_offset_imm(x86::Assembler &a, uint32 bytes_dst, + uint32 kind_dst, int32 reg_no_dst, + int32 reg_no_src, int32 reg_no_base, + int32 offset) +{ + x86::Mem m(regs_i64[reg_no_base], offset, bytes_dst); + return xchg_r_to_m(a, bytes_dst, kind_dst, m, reg_no_src) + && extend_r_to_r(a, bytes_dst, kind_dst, reg_no_src, reg_no_dst); +} + +/** + * Encode atomic rmw xchg: load value into a register from memory + * with reg base and reg offset, exchange loaded value with reg data, store back + * + * @param a the assembler to emit the code + * @param bytes_dst the bytes number of the data to actual operated on(load, + * compare, replacement) could be 1(byte), 2(short), 4(int32), 8(int64) + * @param reg_no_dst the no of register that stores the returned value + * @param reg_no_src the no of register store the src data(second operand) + * @param reg_no_base the no of register that stores the base address + * of src&dst memory(first operand&store back) + * @param reg_no_offset the no of register that stores the offset of the memory + * @return true if success, false otherwise + */ +static bool +at_rmw_xchg_r_base_r_offset_r(x86::Assembler &a, uint32 bytes_dst, + uint32 kind_dst, int32 reg_no_dst, + int32 reg_no_src, int32 reg_no_base, + int32 reg_no_offset) +{ + x86::Mem m(regs_i64[reg_no_base], regs_i64[reg_no_offset], 0, 0, bytes_dst); + return xchg_r_to_m(a, bytes_dst, kind_dst, m, reg_no_src) + && extend_r_to_r(a, bytes_dst, kind_dst, reg_no_src, reg_no_dst); +} + +/** + * Encode insn rmw logical operation: generate a loop to make sure it's atomic + * @param bin_op the operation, can be and/or/xor + * @param kind the data kind, can only be I32 or I64 + * @param bytes_dst the byte number of dst data + */ +#define AT_RMW_LOGICAL_LOOP(bin_op, kind, bytes_dst) \ + do { \ + bh_assert((kind_dst == JIT_REG_KIND_I32 && bytes_dst <= 4) \ + || kind_dst == JIT_REG_KIND_I64); \ + bh_assert(reg_no_src < 16 && reg_no_dst < 16); \ + /* read original value in memory(operand 1) to rax(expected) */ \ + mov_m_to_r(a, bytes_dst, kind_dst, false, REG_RAX_IDX, m_dst); \ + Label loop = a.newLabel(); \ + /* check whether loop is valid, and bind the loop label \ + * to the current position in the code. */ \ + if (!loop.isValid() || a.bind(loop) != kErrorOk) \ + return false; \ + /* move operand 1 to temp reg rb */ \ + mov_r_to_r(a, kind_dst, REG_RBX_IDX, REG_RAX_IDX); \ + /* actual logical operation with operand 2, result save to rbx */ \ + switch (bytes_dst) { \ + case 1: \ + a.bin_op##_(regs_i8[REG_RBX_IDX], regs_i8[reg_no_src]); \ + break; \ + case 2: \ + a.bin_op##_(regs_i16[REG_RBX_IDX], regs_i16[reg_no_src]); \ + break; \ + case 4: \ + a.bin_op##_(regs_i32[REG_RBX_IDX], regs_i32[reg_no_src]); \ + break; \ + case 8: \ + a.bin_op##_(regs_i64[REG_RBX_IDX], regs_i64[reg_no_src]); \ + break; \ + default: \ + bh_assert(0); \ + return false; \ + } \ + /* cmp with read value in RAX, try to change with result value in RBX \ + * REG, if change successfully, mem data is changed and exit loop(ZF \ + * is set) if not, loop again(ZF is clear) and tries to do logical ops \ + * atomically */ \ + at_cmpxchg(a, bytes_dst, kind_dst, REG_RBX_IDX, m_dst); \ + a.jne(loop); \ + return true; \ + } while (0) + +/** + * Encode atomic logical binary operation: and + * + * @param a the assembler to emit the code + * @param bytes_dst the bytes number of the data, + * could be 1(byte), 2(short), 4(int32), 8(int64), + * @param kind_dst the kind of data to move, could be I32, I64 + * @param reg_no_dst the index of dest register + * @param reg_no_src the index of register hold operand value of add operation + * @param m_dst the dest memory operand + * + * @return true if success, false otherwise + */ +static bool +at_and(x86::Assembler &a, uint32 bytes_dst, uint32 kind_dst, int32 reg_no_dst, + int32 reg_no_src, x86::Mem &m_dst) +{ + AT_RMW_LOGICAL_LOOP(and, kind_dst, bytes_dst); +} + +/** + * Encode atomic logical binary operation: or + * + * @param a the assembler to emit the code + * @param bytes_dst the bytes number of the data, + * could be 1(byte), 2(short), 4(int32), 8(int64), + * @param kind_dst the kind of data to move, could be I32, I64 + * @param reg_no_dst the index of dest register + * @param reg_no_src the index of register hold operand value of add operation + * @param m_dst the dest memory operand + * + * @return true if success, false otherwise + */ +static bool +at_or(x86::Assembler &a, uint32 bytes_dst, uint32 kind_dst, int32 reg_no_dst, + int32 reg_no_src, x86::Mem &m_dst) +{ + AT_RMW_LOGICAL_LOOP(or, kind_dst, bytes_dst); +} +/** + * Encode atomic logical binary operation: xor + * + * @param a the assembler to emit the code + * @param bytes_dst the bytes number of the data, + * could be 1(byte), 2(short), 4(int32), 8(int64), + * @param kind_dst the kind of data to move, could be I32, I64 + * @param reg_no_dst the index of dest register + * @param reg_no_src the index of register hold operand value of add operation + * @param m_dst the dest memory operand + * + * @return true if success, false otherwise + */ +static bool +at_xor(x86::Assembler &a, uint32 bytes_dst, uint32 kind_dst, int32 reg_no_dst, + int32 reg_no_src, x86::Mem &m_dst) +{ + AT_RMW_LOGICAL_LOOP(xor, kind_dst, bytes_dst); +} + +/** + * Encode atomic rmw and: load value into a register from memory with reg base + * and reg offset, bitwise and loaded value with imm data, store back + * + * @param a the assembler to emit the code + * @param bytes_dst the bytes number of the data to actual operated on(load, + * compare, replacement) could be 1(byte), 2(short), 4(int32), 8(int64) + * @param reg_no_dst the no of register that stores the returned value + * @param data_src the immediate data(first operand) + * @param reg_no_base the no of register that stores the base address + * of src&dst memory(second operand&store back) + * @param offset the offset address of the memory + * @return true if success, false otherwise + */ +static bool +at_rmw_and_imm_base_r_offset_imm(x86::Assembler &a, uint32 bytes_dst, + uint32 kind_dst, int32 reg_no_dst, + void *data_src, int32 reg_no_base, + int32 offset) +{ + x86::Mem m(regs_i64[reg_no_base], offset, bytes_dst); + Imm imm; + imm_set_value(imm, data_src, bytes_dst); + uint32 reg_no_src = mov_imm_to_free_reg(a, imm, bytes_dst); + return at_and(a, bytes_dst, kind_dst, reg_no_dst, reg_no_src, m) + && extend_r_to_r(a, bytes_dst, kind_dst, REG_RAX_IDX, reg_no_dst); +} + +/** + * Encode atomic rmw and: load value into a register from memory with reg base + * and reg offset, bitwise and loaded value with imm data, store back + * + * @param a the assembler to emit the code + * @param bytes_dst the bytes number of the data to actual operated on(load, + * compare, replacement) could be 1(byte), 2(short), 4(int32), 8(int64) + * @param reg_no_dst the no of register that stores the returned value + * @param data_src the immediate data(second operand) + * @param reg_no_base the no of register that stores the base address + * of src&dst memory(first operand&store back location) + * @param reg_no_offset the no of register that stores the offset of the memory + * @return true if success, false otherwise + */ +static bool +at_rmw_and_imm_base_r_offset_r(x86::Assembler &a, uint32 bytes_dst, + uint32 kind_dst, int32 reg_no_dst, + void *data_src, int32 reg_no_base, + int32 reg_no_offset) +{ + x86::Mem m(regs_i64[reg_no_base], regs_i64[reg_no_offset], 0, 0, bytes_dst); + Imm imm; + imm_set_value(imm, data_src, bytes_dst); + uint32 reg_no_src = mov_imm_to_free_reg(a, imm, bytes_dst); + return at_and(a, bytes_dst, kind_dst, reg_no_dst, reg_no_src, m) + && extend_r_to_r(a, bytes_dst, kind_dst, REG_RAX_IDX, reg_no_dst); +} + +/** + * Encode atomic rmw and: load value into a register from memory with reg base + * and imm offset, bitwise and value with reg data, store back + * + * @param a the assembler to emit the code + * @param bytes_dst the bytes number of the data to actual operated on(load, + * compare, replacement) could be 1(byte), 2(short), 4(int32), 8(int64) + * @param reg_no_dst the no of register that stores the returned value + * @param reg_no_src the no of register store the src data(second operand) + * @param reg_no_base the no of register that stores the base address + * of src&dst memory(first operand&store back location) + * @param offset the offset address of the memory + * @return true if success, false otherwise + */ +static bool +at_rmw_and_r_base_r_offset_imm(x86::Assembler &a, uint32 bytes_dst, + uint32 kind_dst, int32 reg_no_dst, + int32 reg_no_src, int32 reg_no_base, + int32 offset) +{ + x86::Mem m(regs_i64[reg_no_base], offset, bytes_dst); + return at_and(a, bytes_dst, kind_dst, reg_no_dst, reg_no_src, m) + && extend_r_to_r(a, bytes_dst, kind_dst, REG_RAX_IDX, reg_no_dst); +} + +/** + * Encode atomic rmw and: load value into a register from memory with reg base + * and reg offset, bitwise and loaded value with reg data, store back + * + * @param a the assembler to emit the code + * @param bytes_dst the bytes number of the data to actual operated on(load, + * compare, replacement) could be 1(byte), 2(short), 4(int32), 8(int64) + * @param reg_no_dst the no of register that stores the returned value + * @param reg_no_src the no of register store the src data(second operand) + * @param reg_no_base the no of register that stores the base address + * of src&dst memory(first operand&store back) + * @param reg_no_offset the no of register that stores the offset of the memory + * @return true if success, false otherwise + */ +static bool +at_rmw_and_r_base_r_offset_r(x86::Assembler &a, uint32 bytes_dst, + uint32 kind_dst, int32 reg_no_dst, + int32 reg_no_src, int32 reg_no_base, + int32 reg_no_offset) +{ + x86::Mem m(regs_i64[reg_no_base], regs_i64[reg_no_offset], 0, 0, bytes_dst); + return at_and(a, bytes_dst, kind_dst, reg_no_dst, reg_no_src, m) + && extend_r_to_r(a, bytes_dst, kind_dst, REG_RAX_IDX, reg_no_dst); +} + +/** + * Encode atomic rmw or: load value into a register from memory with reg base + * and reg offset, bitwise or loaded value with imm data, store back + * + * @param a the assembler to emit the code + * @param bytes_dst the bytes number of the data to actual operated on(load, + * compare, replacement) could be 1(byte), 2(short), 4(int32), 8(int64) + * @param reg_no_dst the no of register that stores the returned value + * @param data_src the immediate data(first operand) + * @param reg_no_base the no of register that stores the base address + * of src&dst memory(second operand&store back) + * @param offset the offset address of the memory + * @return true if success, false otherwise + */ +static bool +at_rmw_or_imm_base_r_offset_imm(x86::Assembler &a, uint32 bytes_dst, + uint32 kind_dst, int32 reg_no_dst, + void *data_src, int32 reg_no_base, int32 offset) +{ + x86::Mem m(regs_i64[reg_no_base], offset, bytes_dst); + Imm imm; + imm_set_value(imm, data_src, bytes_dst); + uint32 reg_no_src = mov_imm_to_free_reg(a, imm, bytes_dst); + return at_or(a, bytes_dst, kind_dst, reg_no_dst, reg_no_src, m) + && extend_r_to_r(a, bytes_dst, kind_dst, REG_RAX_IDX, reg_no_dst); +} + +/** + * Encode atomic rmw or: load value into a register from memory with reg base + * and reg offset, bitwise or loaded value with imm data, store back + * + * @param a the assembler to emit the code + * @param bytes_dst the bytes number of the data to actual operated on(load, + * compare, replacement) could be 1(byte), 2(short), 4(int32), 8(int64) + * @param reg_no_dst the no of register that stores the returned value + * @param data_src the immediate data(second operand) + * @param reg_no_base the no of register that stores the base address + * of src&dst memory(first operand&store back location) + * @param reg_no_offset the no of register that stores the offset of the memory + * @return true if success, false otherwise + */ +static bool +at_rmw_or_imm_base_r_offset_r(x86::Assembler &a, uint32 bytes_dst, + uint32 kind_dst, int32 reg_no_dst, void *data_src, + int32 reg_no_base, int32 reg_no_offset) +{ + x86::Mem m(regs_i64[reg_no_base], regs_i64[reg_no_offset], 0, 0, bytes_dst); + Imm imm; + imm_set_value(imm, data_src, bytes_dst); + uint32 reg_no_src = mov_imm_to_free_reg(a, imm, bytes_dst); + return at_or(a, bytes_dst, kind_dst, reg_no_dst, reg_no_src, m) + && extend_r_to_r(a, bytes_dst, kind_dst, REG_RAX_IDX, reg_no_dst); +} + +/** + * Encode atomic rmw or: load value into a register from memory with reg base + * and imm offset, bitwise or loaded value with reg data, store back + * + * @param a the assembler to emit the code + * @param bytes_dst the bytes number of the data to actual operated on(load, + * compare, replacement) could be 1(byte), 2(short), 4(int32), 8(int64) + * @param reg_no_dst the no of register that stores the returned value + * @param reg_no_src the no of register store the src data(second operand) + * @param reg_no_base the no of register that stores the base address + * of src&dst memory(first operand&store back location) + * @param offset the offset address of the memory + * @return true if success, false otherwise + */ +static bool +at_rmw_or_r_base_r_offset_imm(x86::Assembler &a, uint32 bytes_dst, + uint32 kind_dst, int32 reg_no_dst, + int32 reg_no_src, int32 reg_no_base, int32 offset) +{ + x86::Mem m(regs_i64[reg_no_base], offset, bytes_dst); + return at_or(a, bytes_dst, kind_dst, reg_no_dst, reg_no_src, m) + && extend_r_to_r(a, bytes_dst, kind_dst, REG_RAX_IDX, reg_no_dst); +} + +/** + * Encode atomic rmw or: load value into a register from memory with reg base + * and reg offset, bitwise or loaded value with reg data, store back + * + * @param a the assembler to emit the code + * @param bytes_dst the bytes number of the data to actual operated on(load, + * compare, replacement) could be 1(byte), 2(short), 4(int32), 8(int64) + * @param reg_no_dst the no of register that stores the returned value + * @param reg_no_src the no of register store the src data(second operand) + * @param reg_no_base the no of register that stores the base address + * of src&dst memory(first operand&store back) + * @param reg_no_offset the no of register that stores the offset of the memory + * @return true if success, false otherwise + */ +static bool +at_rmw_or_r_base_r_offset_r(x86::Assembler &a, uint32 bytes_dst, + uint32 kind_dst, int32 reg_no_dst, int32 reg_no_src, + int32 reg_no_base, int32 reg_no_offset) +{ + x86::Mem m(regs_i64[reg_no_base], regs_i64[reg_no_offset], 0, 0, bytes_dst); + return at_or(a, bytes_dst, kind_dst, reg_no_dst, reg_no_src, m) + && extend_r_to_r(a, bytes_dst, kind_dst, REG_RAX_IDX, reg_no_dst); +} + +/** + * Encode atomic rmw xor: load value into a register from memory with reg base + * and reg offset, bitwise xor loaded value with imm data, store back + * + * @param a the assembler to emit the code + * @param bytes_dst the bytes number of the data to actual operated on(load, + * compare, replacement) could be 1(byte), 2(short), 4(int32), 8(int64) + * @param reg_no_dst the no of register that stores the returned value + * @param data_src the immediate data(first operand) + * @param reg_no_base the no of register that stores the base address + * of src&dst memory(second operand&store back) + * @param offset the offset address of the memory + * @return true if success, false otherwise + */ +static bool +at_rmw_xor_imm_base_r_offset_imm(x86::Assembler &a, uint32 bytes_dst, + uint32 kind_dst, int32 reg_no_dst, + void *data_src, int32 reg_no_base, + int32 offset) +{ + x86::Mem m(regs_i64[reg_no_base], offset, bytes_dst); + Imm imm; + imm_set_value(imm, data_src, bytes_dst); + uint32 reg_no_src = mov_imm_to_free_reg(a, imm, bytes_dst); + return at_xor(a, bytes_dst, kind_dst, reg_no_dst, reg_no_src, m) + && extend_r_to_r(a, bytes_dst, kind_dst, REG_RAX_IDX, reg_no_dst); +} + +/** + * Encode atomic rmw xor: load value into a register from memory with reg base + * and reg offset, bitwise xor loaded value with imm data, store back + * + * @param a the assembler to emit the code + * @param bytes_dst the bytes number of the data to actual operated on(load, + * compare, replacement) could be 1(byte), 2(short), 4(int32), 8(int64) + * @param reg_no_dst the no of register that stores the returned value + * @param data_src the immediate data(second operand) + * @param reg_no_base the no of register that stores the base address + * of src&dst memory(first operand&store back location) + * @param reg_no_offset the no of register that stores the offset of the memory + * @return true if success, false otherwise + */ +static bool +at_rmw_xor_imm_base_r_offset_r(x86::Assembler &a, uint32 bytes_dst, + uint32 kind_dst, int32 reg_no_dst, + void *data_src, int32 reg_no_base, + int32 reg_no_offset) +{ + x86::Mem m(regs_i64[reg_no_base], regs_i64[reg_no_offset], 0, 0, bytes_dst); + Imm imm; + imm_set_value(imm, data_src, bytes_dst); + uint32 reg_no_src = mov_imm_to_free_reg(a, imm, bytes_dst); + return at_xor(a, bytes_dst, kind_dst, reg_no_dst, reg_no_src, m) + && extend_r_to_r(a, bytes_dst, kind_dst, REG_RAX_IDX, reg_no_dst); +} + +/** + * Encode atomic rmw xor: load value into a register from memory with reg base + * and imm offset, bitwise xor exchange loaded value with reg data, store back + * + * @param a the assembler to emit the code + * @param bytes_dst the bytes number of the data to actual operated on(load, + * compare, replacement) could be 1(byte), 2(short), 4(int32), 8(int64) + * @param reg_no_dst the no of register that stores the returned value + * @param reg_no_src the no of register store the src data(second operand) + * @param reg_no_base the no of register that stores the base address + * of src&dst memory(first operand&store back location) + * @param offset the offset address of the memory + * @return true if success, false otherwise + */ +static bool +at_rmw_xor_r_base_r_offset_imm(x86::Assembler &a, uint32 bytes_dst, + uint32 kind_dst, int32 reg_no_dst, + int32 reg_no_src, int32 reg_no_base, + int32 offset) +{ + x86::Mem m(regs_i64[reg_no_base], offset, bytes_dst); + return at_xor(a, bytes_dst, kind_dst, reg_no_dst, reg_no_src, m) + && extend_r_to_r(a, bytes_dst, kind_dst, REG_RAX_IDX, reg_no_dst); +} + +/** + * Encode atomic rmw xor: load value into a register from memory with reg base + * and reg offset, bitwise xor loaded value with reg data, store back + * + * @param a the assembler to emit the code + * @param bytes_dst the bytes number of the data to actual operated on(load, + * compare, replacement) could be 1(byte), 2(short), 4(int32), 8(int64) + * @param reg_no_dst the no of register that stores the returned value + * @param reg_no_src the no of register store the src data(second operand) + * @param reg_no_base the no of register that stores the base address + * of src&dst memory(first operand&store back) + * @param reg_no_offset the no of register that stores the offset of the memory + * @return true if success, false otherwise + */ +static bool +at_rmw_xor_r_base_r_offset_r(x86::Assembler &a, uint32 bytes_dst, + uint32 kind_dst, int32 reg_no_dst, + int32 reg_no_src, int32 reg_no_base, + int32 reg_no_offset) +{ + x86::Mem m(regs_i64[reg_no_base], regs_i64[reg_no_offset], 0, 0, bytes_dst); + return at_xor(a, bytes_dst, kind_dst, reg_no_dst, reg_no_src, m) + && extend_r_to_r(a, bytes_dst, kind_dst, REG_RAX_IDX, reg_no_dst); +} + +/** + * Encode insn rmw RMW_type r0, r1, r2, r3 + * @param bin_op the operation, can be add/sub/xchg/and/or/xor + * @param kind the data kind, can only be I32 or I64 + * @param bytes_dst the byte number of dst data + */ +#define AT_RMW_R_R_R_R(bin_op, kind, type, bytes_dst) \ + do { \ + type data_src = 0; \ + int32 reg_no_dst = 0, reg_no_src = 0, reg_no_base = 0, \ + reg_no_offset = 0; \ + int32 offset = 0; \ + bool _ret = false; \ + if (jit_reg_is_const(r3)) { \ + CHECK_KIND(r3, JIT_REG_KIND_I32); \ + } \ + else { \ + CHECK_KIND(r3, JIT_REG_KIND_I64); \ + } \ + /* r0: read/return value r2: memory base addr can't be const */ \ + /* already check it's not const in LOAD_4ARGS(); */ \ + reg_no_dst = jit_reg_no(r0); \ + CHECK_REG_NO(reg_no_dst, jit_reg_kind(r0)); \ + /* mem_data base address has to be non-const */ \ + CHECK_NCONST(r2); \ + reg_no_base = jit_reg_no(r2); \ + CHECK_REG_NO(reg_no_base, jit_reg_kind(r2)); \ + /* r1: source operand value r3: offset can be const */ \ + if (jit_reg_is_const(r1)) \ + data_src = jit_cc_get_const_##kind(cc, r1); \ + else { \ + reg_no_src = jit_reg_no(r1); \ + CHECK_REG_NO(reg_no_src, jit_reg_kind(r1)); \ + } \ + if (jit_reg_is_const(r3)) \ + offset = jit_cc_get_const_I32(cc, r3); \ + else { \ + reg_no_offset = jit_reg_no(r3); \ + CHECK_REG_NO(reg_no_offset, jit_reg_kind(r3)); \ + } \ + \ + if (jit_reg_is_const(r1)) { \ + if (jit_reg_is_const(r3)) \ + _ret = at_rmw_##bin_op##_imm_base_r_offset_imm( \ + a, bytes_dst, JIT_REG_KIND_##kind, reg_no_dst, &data_src, \ + reg_no_base, offset); \ + else \ + _ret = at_rmw_##bin_op##_imm_base_r_offset_r( \ + a, bytes_dst, JIT_REG_KIND_##kind, reg_no_dst, &data_src, \ + reg_no_base, reg_no_offset); \ + } \ + else { \ + if (jit_reg_is_const(r3)) \ + _ret = at_rmw_##bin_op##_r_base_r_offset_imm( \ + a, bytes_dst, JIT_REG_KIND_##kind, reg_no_dst, reg_no_src, \ + reg_no_base, offset); \ + else \ + _ret = at_rmw_##bin_op##_r_base_r_offset_r( \ + a, bytes_dst, JIT_REG_KIND_##kind, reg_no_dst, reg_no_src, \ + reg_no_base, reg_no_offset); \ + } \ + if (!_ret) \ + GOTO_FAIL; \ + } while (0) + +/** + * Encode insn mfence + **/ +static void +fence(x86::Assembler &a) +{ + a.mfence(); +} + +/** + * Encode insn fence + */ +#define FENCE() fence(a) + +#endif + +bool +jit_codegen_gen_native(JitCompContext *cc) +{ + bool atomic; + JitBasicBlock *block; + JitInsn *insn; + JitReg r0, r1, r2, r3, r4; + JmpInfo jmp_info_head; + bh_list *jmp_info_list = (bh_list *)&jmp_info_head; + uint32 label_index, label_num, i; + uint32 *label_offsets = NULL, code_size; +#if CODEGEN_DUMP != 0 + uint32 code_offset = 0; +#endif + bool return_value = false, is_last_insn; + void **jitted_addr; + char *code_buf, *stream; + + JitErrorHandler err_handler; + Environment env(Arch::kX64); + CodeHolder code; + code.init(env); + code.setErrorHandler(&err_handler); + x86::Assembler a(&code); + + if (BH_LIST_SUCCESS != bh_list_init(jmp_info_list)) { + jit_set_last_error(cc, "init jmp info list failed"); + return false; + } + + label_num = jit_cc_label_num(cc); + + if (!(label_offsets = + (uint32 *)jit_calloc(((uint32)sizeof(uint32)) * label_num))) { + jit_set_last_error(cc, "allocate memory failed"); + goto fail; + } + + for (i = 0; i < label_num; i++) { + if (i == 0) + label_index = 0; + else if (i == label_num - 1) + label_index = 1; + else + label_index = i + 1; + + label_offsets[label_index] = code.sectionById(0)->buffer().size(); + + block = *jit_annl_basic_block( + cc, jit_reg_new(JIT_REG_KIND_L32, label_index)); + +#if CODEGEN_DUMP != 0 + os_printf("\nL%d:\n\n", label_index); +#endif + + JIT_FOREACH_INSN(block, insn) { is_last_insn = (insn->next == block) ? true : false; -#if CODEGEN_DUMP != 0 - os_printf("\n"); - jit_dump_insn(cc, insn); -#endif - switch (insn->opcode) { - case JIT_OP_MOV: - LOAD_2ARGS(); - if (!lower_mov(cc, a, r0, r1)) - GOTO_FAIL; +#if CODEGEN_DUMP != 0 + os_printf("\n"); + jit_dump_insn(cc, insn); +#endif + switch (insn->opcode) { + case JIT_OP_MOV: + LOAD_2ARGS(); + if (!lower_mov(cc, a, r0, r1)) + GOTO_FAIL; + break; + + case JIT_OP_I8TOI32: + LOAD_2ARGS(); + CONVERT_R_R(I32, I32, i32, i8, int8); + break; + + case JIT_OP_I8TOI64: + LOAD_2ARGS(); + CONVERT_R_R(I64, I32, i64, i8, int8); + break; + + case JIT_OP_I16TOI32: + LOAD_2ARGS(); + CONVERT_R_R(I32, I32, i32, i16, int16); + break; + + case JIT_OP_I16TOI64: + LOAD_2ARGS(); + CONVERT_R_R(I64, I32, i64, i16, int16); + break; + + case JIT_OP_I32TOI8: + LOAD_2ARGS(); + CONVERT_R_R(I32, I32, i8, i32, int32); + break; + + case JIT_OP_I32TOU8: + LOAD_2ARGS(); + CONVERT_R_R(I32, I32, u8, i32, int32); + break; + + case JIT_OP_I32TOI16: + LOAD_2ARGS(); + CONVERT_R_R(I32, I32, i16, i32, int32); + break; + + case JIT_OP_I32TOU16: + LOAD_2ARGS(); + CONVERT_R_R(I32, I32, u16, i32, int32); + break; + + case JIT_OP_I32TOI64: + LOAD_2ARGS(); + CONVERT_R_R(I64, I32, i64, i32, int32); + break; + + case JIT_OP_U32TOI64: + LOAD_2ARGS(); + CONVERT_R_R(I64, I32, i64, u32, int32); + break; + + case JIT_OP_I32TOF32: + LOAD_2ARGS(); + CONVERT_R_R(F32, I32, f32, i32, int32); + break; + + case JIT_OP_U32TOF32: + LOAD_2ARGS(); + CONVERT_R_R(F32, I32, f32, u32, uint32); + break; + + case JIT_OP_I32TOF64: + LOAD_2ARGS(); + CONVERT_R_R(F64, I32, f64, i32, int32); + break; + + case JIT_OP_U32TOF64: + LOAD_2ARGS(); + CONVERT_R_R(F64, I32, f64, u32, uint32); + break; + + case JIT_OP_I64TOI8: + LOAD_2ARGS(); + CONVERT_R_R(I32, I64, i8, i64, int64); + break; + + case JIT_OP_I64TOI16: + LOAD_2ARGS(); + CONVERT_R_R(I32, I64, i16, i64, int64); + break; + + case JIT_OP_I64TOI32: + LOAD_2ARGS(); + CONVERT_R_R(I32, I64, i32, i64, int64); + break; + + case JIT_OP_I64TOF32: + LOAD_2ARGS(); + CONVERT_R_R(F32, I64, f32, i64, int64); + break; + + case JIT_OP_I64TOF64: + LOAD_2ARGS(); + CONVERT_R_R(F64, I64, f64, i64, int64); + break; + + case JIT_OP_F32TOI32: + LOAD_2ARGS(); + CONVERT_R_R(I32, F32, i32, f32, float32); + break; + + case JIT_OP_F32TOI64: + LOAD_2ARGS(); + CONVERT_R_R(I64, F32, i64, f32, float32); + break; + + case JIT_OP_F32TOF64: + LOAD_2ARGS(); + CONVERT_R_R(F64, F32, f64, f32, float32); + break; + + case JIT_OP_F32TOU32: + LOAD_2ARGS(); + CONVERT_R_R(I32, F32, u32, f32, float32); + break; + + case JIT_OP_F64TOI32: + LOAD_2ARGS(); + CONVERT_R_R(I32, F64, i32, f64, float64); + break; + + case JIT_OP_F64TOI64: + LOAD_2ARGS(); + CONVERT_R_R(I64, F64, i64, f64, float64); + break; + + case JIT_OP_F64TOF32: + LOAD_2ARGS(); + CONVERT_R_R(F32, F64, f32, f64, float64); + break; + + case JIT_OP_F64TOU32: + LOAD_2ARGS(); + CONVERT_R_R(I32, F64, u32, f64, float64); + break; + + case JIT_OP_NEG: + LOAD_2ARGS(); + if (!lower_neg(cc, a, r0, r1)) + GOTO_FAIL; + break; + + case JIT_OP_ADD: + case JIT_OP_SUB: + case JIT_OP_MUL: + case JIT_OP_DIV_S: + case JIT_OP_REM_S: + case JIT_OP_DIV_U: + case JIT_OP_REM_U: + LOAD_3ARGS(); + if (!lower_alu(cc, a, + (ALU_OP)(ADD + (insn->opcode - JIT_OP_ADD)), + r0, r1, r2)) + GOTO_FAIL; + break; + + case JIT_OP_SHL: + case JIT_OP_SHRS: + case JIT_OP_SHRU: + case JIT_OP_ROTL: + case JIT_OP_ROTR: + LOAD_3ARGS(); + if (!lower_shift( + cc, a, + (SHIFT_OP)(SHL + (insn->opcode - JIT_OP_SHL)), r0, + r1, r2)) + GOTO_FAIL; + break; + + case JIT_OP_OR: + case JIT_OP_XOR: + case JIT_OP_AND: + LOAD_3ARGS(); + if (!lower_bit(cc, a, + (BIT_OP)(OR + (insn->opcode - JIT_OP_OR)), + r0, r1, r2)) + GOTO_FAIL; + break; + + case JIT_OP_CLZ: + case JIT_OP_CTZ: + case JIT_OP_POPCNT: + LOAD_2ARGS(); + if (!lower_bitcount( + cc, a, + (BITCOUNT_OP)(CLZ + (insn->opcode - JIT_OP_CLZ)), + r0, r1)) + GOTO_FAIL; + break; + + case JIT_OP_CMP: + LOAD_3ARGS(); + if (!lower_cmp(cc, a, r0, r1, r2)) + GOTO_FAIL; + break; + + case JIT_OP_SELECTEQ: + case JIT_OP_SELECTNE: + case JIT_OP_SELECTGTS: + case JIT_OP_SELECTGES: + case JIT_OP_SELECTLTS: + case JIT_OP_SELECTLES: + case JIT_OP_SELECTGTU: + case JIT_OP_SELECTGEU: + case JIT_OP_SELECTLTU: + case JIT_OP_SELECTLEU: + LOAD_4ARGS(); + if (!lower_select( + cc, a, + (COND_OP)(EQ + (insn->opcode - JIT_OP_SELECTEQ)), + r0, r1, r2, r3)) + GOTO_FAIL; + break; + + case JIT_OP_LDEXECENV: + LOAD_1ARG(); + CHECK_KIND(r0, JIT_REG_KIND_I32); + /* TODO */ + break; + + case JIT_OP_LDJITINFO: + LOAD_1ARG(); + CHECK_KIND(r0, JIT_REG_KIND_I32); + /* TODO */ + break; + + case JIT_OP_LDI8: + LOAD_3ARGS(); + bh_assert(jit_reg_kind(r0) == JIT_REG_KIND_I32 + || jit_reg_kind(r0) == JIT_REG_KIND_I64); + if (jit_reg_kind(r0) == JIT_REG_KIND_I32) + LD_R_R_R(I32, 1, true); + else + LD_R_R_R(I64, 1, true); + break; + + case JIT_OP_LDU8: + LOAD_3ARGS(); + bh_assert(jit_reg_kind(r0) == JIT_REG_KIND_I32 + || jit_reg_kind(r0) == JIT_REG_KIND_I64); + if (jit_reg_kind(r0) == JIT_REG_KIND_I32) + LD_R_R_R(I32, 1, false); + else + LD_R_R_R(I64, 1, false); + break; + + case JIT_OP_LDI16: + LOAD_3ARGS(); + bh_assert(jit_reg_kind(r0) == JIT_REG_KIND_I32 + || jit_reg_kind(r0) == JIT_REG_KIND_I64); + if (jit_reg_kind(r0) == JIT_REG_KIND_I32) + LD_R_R_R(I32, 2, true); + else + LD_R_R_R(I64, 2, true); + break; + + case JIT_OP_LDU16: + LOAD_3ARGS(); + bh_assert(jit_reg_kind(r0) == JIT_REG_KIND_I32 + || jit_reg_kind(r0) == JIT_REG_KIND_I64); + if (jit_reg_kind(r0) == JIT_REG_KIND_I32) + LD_R_R_R(I32, 2, false); + else + LD_R_R_R(I64, 2, false); + break; + + case JIT_OP_LDI32: + LOAD_3ARGS(); + bh_assert(jit_reg_kind(r0) == JIT_REG_KIND_I32 + || jit_reg_kind(r0) == JIT_REG_KIND_I64); + if (jit_reg_kind(r0) == JIT_REG_KIND_I32) + LD_R_R_R(I32, 4, true); + else + LD_R_R_R(I64, 4, true); + break; + + case JIT_OP_LDU32: + LOAD_3ARGS(); + bh_assert(jit_reg_kind(r0) == JIT_REG_KIND_I32 + || jit_reg_kind(r0) == JIT_REG_KIND_I64); + if (jit_reg_kind(r0) == JIT_REG_KIND_I32) + LD_R_R_R(I32, 4, false); + else + LD_R_R_R(I64, 4, false); + break; + + case JIT_OP_LDI64: + case JIT_OP_LDU64: + case JIT_OP_LDPTR: + LOAD_3ARGS(); + LD_R_R_R(I64, 8, false); break; - case JIT_OP_I8TOI32: - LOAD_2ARGS(); - CONVERT_R_R(I32, I32, i32, i8, int8); + case JIT_OP_LDF32: + LOAD_3ARGS(); + LD_R_R_R(F32, 4, false); break; - case JIT_OP_I8TOI64: - LOAD_2ARGS(); - CONVERT_R_R(I64, I32, i64, i8, int8); + case JIT_OP_LDF64: + LOAD_3ARGS(); + LD_R_R_R(F64, 8, false); break; - case JIT_OP_I16TOI32: - LOAD_2ARGS(); - CONVERT_R_R(I32, I32, i32, i16, int16); + case JIT_OP_STI8: + LOAD_3ARGS_NO_ASSIGN(); + atomic = insn->flags_u8 & 0x1; + ST_R_R_R(I32, int32, 1, atomic); break; - case JIT_OP_I16TOI64: - LOAD_2ARGS(); - CONVERT_R_R(I64, I32, i64, i16, int16); + case JIT_OP_STI16: + LOAD_3ARGS_NO_ASSIGN(); + atomic = insn->flags_u8 & 0x1; + ST_R_R_R(I32, int32, 2, atomic); break; - case JIT_OP_I32TOI8: - LOAD_2ARGS(); - CONVERT_R_R(I32, I32, i8, i32, int32); + case JIT_OP_STI32: + LOAD_3ARGS_NO_ASSIGN(); + atomic = insn->flags_u8 & 0x1; + ST_R_R_R(I32, int32, 4, atomic); break; - case JIT_OP_I32TOU8: - LOAD_2ARGS(); - CONVERT_R_R(I32, I32, u8, i32, int32); + case JIT_OP_STI64: + LOAD_3ARGS_NO_ASSIGN(); + atomic = insn->flags_u8 & 0x1; + ST_R_R_R(I64, int64, 8, atomic); break; - case JIT_OP_I32TOI16: - LOAD_2ARGS(); - CONVERT_R_R(I32, I32, i16, i32, int32); + case JIT_OP_STPTR: + LOAD_3ARGS_NO_ASSIGN(); + ST_R_R_R(I64, int64, 8, false); break; - case JIT_OP_I32TOU16: - LOAD_2ARGS(); - CONVERT_R_R(I32, I32, u16, i32, int32); + case JIT_OP_STF32: + LOAD_3ARGS_NO_ASSIGN(); + ST_R_R_R(F32, float32, 4, false); break; - case JIT_OP_I32TOI64: - LOAD_2ARGS(); - CONVERT_R_R(I64, I32, i64, i32, int32); + case JIT_OP_STF64: + LOAD_3ARGS_NO_ASSIGN(); + ST_R_R_R(F64, float64, 8, false); break; - case JIT_OP_U32TOI64: - LOAD_2ARGS(); - CONVERT_R_R(I64, I32, i64, u32, int32); + case JIT_OP_JMP: + LOAD_1ARG(); + CHECK_KIND(r0, JIT_REG_KIND_L32); + if (!(is_last_insn + && label_is_neighboring(cc, label_index, + jit_reg_no(r0)))) + JMP_TO_LABEL(jit_reg_no(r0), label_index); break; - case JIT_OP_I32TOF32: - LOAD_2ARGS(); - CONVERT_R_R(F32, I32, f32, i32, int32); + case JIT_OP_BEQ: + case JIT_OP_BNE: + case JIT_OP_BGTS: + case JIT_OP_BGES: + case JIT_OP_BLTS: + case JIT_OP_BLES: + case JIT_OP_BGTU: + case JIT_OP_BGEU: + case JIT_OP_BLTU: + case JIT_OP_BLEU: + LOAD_3ARGS(); + if (!lower_branch( + cc, a, jmp_info_list, label_index, + (COND_OP)(EQ + (insn->opcode - JIT_OP_BEQ)), r0, r1, + r2, is_last_insn)) + GOTO_FAIL; break; - case JIT_OP_U32TOF32: - LOAD_2ARGS(); - CONVERT_R_R(F32, I32, f32, u32, uint32); + case JIT_OP_LOOKUPSWITCH: + { + JitOpndLookupSwitch *opnd = jit_insn_opndls(insn); + if (!lower_lookupswitch(cc, a, jmp_info_list, label_offsets, + label_index, opnd, is_last_insn)) + GOTO_FAIL; break; + } - case JIT_OP_I32TOF64: - LOAD_2ARGS(); - CONVERT_R_R(F64, I32, f64, i32, int32); + case JIT_OP_CALLNATIVE: + if (!lower_callnative(cc, a, insn)) + GOTO_FAIL; break; - case JIT_OP_U32TOF64: - LOAD_2ARGS(); - CONVERT_R_R(F64, I32, f64, u32, uint32); + case JIT_OP_CALLBC: + if (!lower_callbc(cc, a, jmp_info_list, label_index, insn)) + GOTO_FAIL; break; - case JIT_OP_I64TOI8: - LOAD_2ARGS(); - CONVERT_R_R(I32, I64, i8, i64, int64); + case JIT_OP_RETURNBC: + if (!lower_returnbc(cc, a, insn)) + GOTO_FAIL; break; - case JIT_OP_I64TOI16: - LOAD_2ARGS(); - CONVERT_R_R(I32, I64, i16, i64, int64); + case JIT_OP_RETURN: + if (!lower_return(cc, a, insn)) + GOTO_FAIL; break; - case JIT_OP_I64TOI32: + case JIT_OP_I32CASTF32: LOAD_2ARGS(); - CONVERT_R_R(I32, I64, i32, i64, int64); + CAST_R_R(F32, I32, f32, i32, int32); break; - case JIT_OP_I64TOF32: + case JIT_OP_I64CASTF64: LOAD_2ARGS(); - CONVERT_R_R(F32, I64, f32, i64, int64); + CAST_R_R(F64, I64, f64, i64, int64); break; - case JIT_OP_I64TOF64: + case JIT_OP_F32CASTI32: LOAD_2ARGS(); - CONVERT_R_R(F64, I64, f64, i64, int64); + CAST_R_R(I32, F32, i32, f32, float); break; - case JIT_OP_F32TOI32: + case JIT_OP_F64CASTI64: LOAD_2ARGS(); - CONVERT_R_R(I32, F32, i32, f32, float32); + CAST_R_R(I64, F64, i64, f64, double); break; - case JIT_OP_F32TOI64: - LOAD_2ARGS(); - CONVERT_R_R(I64, F32, i64, f32, float32); +#if WASM_ENABLE_SHARED_MEMORY != 0 + case JIT_OP_AT_CMPXCHGU8: + LOAD_4ARGS_NO_ASSIGN(); + if (jit_reg_kind(r0) == JIT_REG_KIND_I32) + CMPXCHG_R_R_R_R_R(I32, int32, 1); + else + CMPXCHG_R_R_R_R_R(I64, int64, 1); break; - case JIT_OP_F32TOF64: - LOAD_2ARGS(); - CONVERT_R_R(F64, F32, f64, f32, float32); + case JIT_OP_AT_CMPXCHGU16: + LOAD_4ARGS_NO_ASSIGN(); + if (jit_reg_kind(r0) == JIT_REG_KIND_I32) + CMPXCHG_R_R_R_R_R(I32, int32, 2); + else + CMPXCHG_R_R_R_R_R(I64, int64, 2); break; - case JIT_OP_F32TOU32: - LOAD_2ARGS(); - CONVERT_R_R(I32, F32, u32, f32, float32); + case JIT_OP_AT_CMPXCHGI32: + LOAD_4ARGS_NO_ASSIGN(); + CMPXCHG_R_R_R_R_R(I32, int32, 4); break; - case JIT_OP_F64TOI32: - LOAD_2ARGS(); - CONVERT_R_R(I32, F64, i32, f64, float64); + case JIT_OP_AT_CMPXCHGU32: + LOAD_4ARGS_NO_ASSIGN(); + CMPXCHG_R_R_R_R_R(I64, int32, 4); break; - case JIT_OP_F64TOI64: - LOAD_2ARGS(); - CONVERT_R_R(I64, F64, i64, f64, float64); + case JIT_OP_AT_CMPXCHGI64: + LOAD_4ARGS_NO_ASSIGN(); + CMPXCHG_R_R_R_R_R(I64, int64, 8); break; - case JIT_OP_F64TOF32: - LOAD_2ARGS(); - CONVERT_R_R(F32, F64, f32, f64, float64); + case JIT_OP_AT_ADDU8: + LOAD_4ARGS(); + bh_assert(jit_reg_kind(r0) == JIT_REG_KIND_I32 + || jit_reg_kind(r0) == JIT_REG_KIND_I64); + if (jit_reg_kind(r0) == JIT_REG_KIND_I32) + AT_RMW_R_R_R_R(add, I32, int32, 1); + else + AT_RMW_R_R_R_R(add, I64, int64, 1); break; - case JIT_OP_F64TOU32: - LOAD_2ARGS(); - CONVERT_R_R(I32, F64, u32, f64, float64); + case JIT_OP_AT_ADDU16: + LOAD_4ARGS(); + bh_assert(jit_reg_kind(r0) == JIT_REG_KIND_I32 + || jit_reg_kind(r0) == JIT_REG_KIND_I64); + if (jit_reg_kind(r0) == JIT_REG_KIND_I32) + AT_RMW_R_R_R_R(add, I32, int32, 2); + else + AT_RMW_R_R_R_R(add, I64, int64, 2); break; - case JIT_OP_NEG: - LOAD_2ARGS(); - if (!lower_neg(cc, a, r0, r1)) - GOTO_FAIL; + case JIT_OP_AT_ADDI32: + LOAD_4ARGS(); + AT_RMW_R_R_R_R(add, I32, int32, 4); break; - case JIT_OP_ADD: - case JIT_OP_SUB: - case JIT_OP_MUL: - case JIT_OP_DIV_S: - case JIT_OP_REM_S: - case JIT_OP_DIV_U: - case JIT_OP_REM_U: - LOAD_3ARGS(); - if (!lower_alu(cc, a, - (ALU_OP)(ADD + (insn->opcode - JIT_OP_ADD)), - r0, r1, r2)) - GOTO_FAIL; + case JIT_OP_AT_ADDU32: + LOAD_4ARGS(); + AT_RMW_R_R_R_R(add, I64, int64, 4); break; - case JIT_OP_SHL: - case JIT_OP_SHRS: - case JIT_OP_SHRU: - case JIT_OP_ROTL: - case JIT_OP_ROTR: - LOAD_3ARGS(); - if (!lower_shift( - cc, a, - (SHIFT_OP)(SHL + (insn->opcode - JIT_OP_SHL)), r0, - r1, r2)) - GOTO_FAIL; + case JIT_OP_AT_ADDI64: + LOAD_4ARGS(); + AT_RMW_R_R_R_R(add, I64, int64, 8); break; - case JIT_OP_OR: - case JIT_OP_XOR: - case JIT_OP_AND: - LOAD_3ARGS(); - if (!lower_bit(cc, a, - (BIT_OP)(OR + (insn->opcode - JIT_OP_OR)), - r0, r1, r2)) - GOTO_FAIL; + case JIT_OP_AT_SUBU8: + LOAD_4ARGS(); + bh_assert(jit_reg_kind(r0) == JIT_REG_KIND_I32 + || jit_reg_kind(r0) == JIT_REG_KIND_I64); + if (jit_reg_kind(r0) == JIT_REG_KIND_I32) + AT_RMW_R_R_R_R(sub, I32, int32, 1); + else + AT_RMW_R_R_R_R(sub, I64, int64, 1); break; - case JIT_OP_CLZ: - case JIT_OP_CTZ: - case JIT_OP_POPCNT: - LOAD_2ARGS(); - if (!lower_bitcount( - cc, a, - (BITCOUNT_OP)(CLZ + (insn->opcode - JIT_OP_CLZ)), - r0, r1)) - GOTO_FAIL; + case JIT_OP_AT_SUBU16: + LOAD_4ARGS(); + bh_assert(jit_reg_kind(r0) == JIT_REG_KIND_I32 + || jit_reg_kind(r0) == JIT_REG_KIND_I64); + if (jit_reg_kind(r0) == JIT_REG_KIND_I32) + AT_RMW_R_R_R_R(sub, I32, int32, 2); + else + AT_RMW_R_R_R_R(sub, I64, int64, 2); break; - case JIT_OP_CMP: - LOAD_3ARGS(); - if (!lower_cmp(cc, a, r0, r1, r2)) - GOTO_FAIL; + case JIT_OP_AT_SUBI32: + LOAD_4ARGS(); + AT_RMW_R_R_R_R(sub, I32, int32, 4); + break; + + case JIT_OP_AT_SUBU32: + LOAD_4ARGS(); + AT_RMW_R_R_R_R(sub, I64, int64, 4); + break; + + case JIT_OP_AT_SUBI64: + LOAD_4ARGS(); + AT_RMW_R_R_R_R(sub, I64, int64, 8); + break; + + case JIT_OP_AT_XCHGU8: + LOAD_4ARGS(); + bh_assert(jit_reg_kind(r0) == JIT_REG_KIND_I32 + || jit_reg_kind(r0) == JIT_REG_KIND_I64); + if (jit_reg_kind(r0) == JIT_REG_KIND_I32) + AT_RMW_R_R_R_R(xchg, I32, int32, 1); + else + AT_RMW_R_R_R_R(xchg, I64, int64, 1); + break; + + case JIT_OP_AT_XCHGU16: + LOAD_4ARGS(); + bh_assert(jit_reg_kind(r0) == JIT_REG_KIND_I32 + || jit_reg_kind(r0) == JIT_REG_KIND_I64); + if (jit_reg_kind(r0) == JIT_REG_KIND_I32) + AT_RMW_R_R_R_R(xchg, I32, int32, 2); + else + AT_RMW_R_R_R_R(xchg, I64, int64, 2); break; - case JIT_OP_SELECTEQ: - case JIT_OP_SELECTNE: - case JIT_OP_SELECTGTS: - case JIT_OP_SELECTGES: - case JIT_OP_SELECTLTS: - case JIT_OP_SELECTLES: - case JIT_OP_SELECTGTU: - case JIT_OP_SELECTGEU: - case JIT_OP_SELECTLTU: - case JIT_OP_SELECTLEU: + case JIT_OP_AT_XCHGI32: LOAD_4ARGS(); - if (!lower_select( - cc, a, - (COND_OP)(EQ + (insn->opcode - JIT_OP_SELECTEQ)), - r0, r1, r2, r3)) - GOTO_FAIL; + AT_RMW_R_R_R_R(xchg, I32, int32, 4); break; - case JIT_OP_LDEXECENV: - LOAD_1ARG(); - CHECK_KIND(r0, JIT_REG_KIND_I32); - /* TODO */ + case JIT_OP_AT_XCHGU32: + LOAD_4ARGS(); + AT_RMW_R_R_R_R(xchg, I64, int64, 4); break; - case JIT_OP_LDJITINFO: - LOAD_1ARG(); - CHECK_KIND(r0, JIT_REG_KIND_I32); - /* TODO */ + case JIT_OP_AT_XCHGI64: + LOAD_4ARGS(); + AT_RMW_R_R_R_R(xchg, I64, int64, 8); break; - case JIT_OP_LDI8: - LOAD_3ARGS(); + case JIT_OP_AT_ANDU8: + LOAD_4ARGS(); bh_assert(jit_reg_kind(r0) == JIT_REG_KIND_I32 || jit_reg_kind(r0) == JIT_REG_KIND_I64); if (jit_reg_kind(r0) == JIT_REG_KIND_I32) - LD_R_R_R(I32, 1, true); + AT_RMW_R_R_R_R(and, I32, int32, 1); else - LD_R_R_R(I64, 1, true); + AT_RMW_R_R_R_R(and, I64, int64, 1); break; - case JIT_OP_LDU8: - LOAD_3ARGS(); + case JIT_OP_AT_ANDU16: + LOAD_4ARGS(); bh_assert(jit_reg_kind(r0) == JIT_REG_KIND_I32 || jit_reg_kind(r0) == JIT_REG_KIND_I64); if (jit_reg_kind(r0) == JIT_REG_KIND_I32) - LD_R_R_R(I32, 1, false); + AT_RMW_R_R_R_R(and, I32, int32, 2); else - LD_R_R_R(I64, 1, false); + AT_RMW_R_R_R_R(and, I64, int64, 2); break; - case JIT_OP_LDI16: - LOAD_3ARGS(); + case JIT_OP_AT_ANDI32: + LOAD_4ARGS(); + AT_RMW_R_R_R_R(and, I32, int32, 4); + break; + + case JIT_OP_AT_ANDU32: + LOAD_4ARGS(); + AT_RMW_R_R_R_R(and, I64, int64, 4); + break; + + case JIT_OP_AT_ANDI64: + LOAD_4ARGS(); + AT_RMW_R_R_R_R(and, I64, int64, 8); + break; + + case JIT_OP_AT_ORU8: + LOAD_4ARGS(); bh_assert(jit_reg_kind(r0) == JIT_REG_KIND_I32 || jit_reg_kind(r0) == JIT_REG_KIND_I64); if (jit_reg_kind(r0) == JIT_REG_KIND_I32) - LD_R_R_R(I32, 2, true); + AT_RMW_R_R_R_R(or, I32, int32, 1); else - LD_R_R_R(I64, 2, true); + AT_RMW_R_R_R_R(or, I64, int64, 1); break; - case JIT_OP_LDU16: - LOAD_3ARGS(); + case JIT_OP_AT_ORU16: + LOAD_4ARGS(); bh_assert(jit_reg_kind(r0) == JIT_REG_KIND_I32 || jit_reg_kind(r0) == JIT_REG_KIND_I64); if (jit_reg_kind(r0) == JIT_REG_KIND_I32) - LD_R_R_R(I32, 2, false); + AT_RMW_R_R_R_R(or, I32, int32, 2); else - LD_R_R_R(I64, 2, false); + AT_RMW_R_R_R_R(or, I64, int64, 2); break; - case JIT_OP_LDI32: - LOAD_3ARGS(); + case JIT_OP_AT_ORI32: + LOAD_4ARGS(); + AT_RMW_R_R_R_R(or, I32, int32, 4); + break; + + case JIT_OP_AT_ORU32: + LOAD_4ARGS(); + AT_RMW_R_R_R_R(or, I64, int64, 4); + break; + + case JIT_OP_AT_ORI64: + LOAD_4ARGS(); + AT_RMW_R_R_R_R(or, I64, int64, 8); + break; + + case JIT_OP_AT_XORU8: + LOAD_4ARGS(); bh_assert(jit_reg_kind(r0) == JIT_REG_KIND_I32 || jit_reg_kind(r0) == JIT_REG_KIND_I64); if (jit_reg_kind(r0) == JIT_REG_KIND_I32) - LD_R_R_R(I32, 4, true); + AT_RMW_R_R_R_R(xor, I32, int32, 1); else - LD_R_R_R(I64, 4, true); + AT_RMW_R_R_R_R(xor, I64, int64, 1); break; - case JIT_OP_LDU32: - LOAD_3ARGS(); + case JIT_OP_AT_XORU16: + LOAD_4ARGS(); bh_assert(jit_reg_kind(r0) == JIT_REG_KIND_I32 || jit_reg_kind(r0) == JIT_REG_KIND_I64); if (jit_reg_kind(r0) == JIT_REG_KIND_I32) - LD_R_R_R(I32, 4, false); + AT_RMW_R_R_R_R(xor, I32, int32, 2); else - LD_R_R_R(I64, 4, false); + AT_RMW_R_R_R_R(xor, I64, int64, 2); break; - case JIT_OP_LDI64: - case JIT_OP_LDU64: - case JIT_OP_LDPTR: - LOAD_3ARGS(); - LD_R_R_R(I64, 8, false); + case JIT_OP_AT_XORI32: + LOAD_4ARGS(); + AT_RMW_R_R_R_R(xor, I32, int32, 4); + break; + + case JIT_OP_AT_XORU32: + LOAD_4ARGS(); + AT_RMW_R_R_R_R(xor, I64, int64, 4); + break; + + case JIT_OP_AT_XORI64: + LOAD_4ARGS(); + AT_RMW_R_R_R_R(xor, I64, int64, 8); + break; + + case JIT_OP_FENCE: + FENCE(); + break; + +#endif + + default: + jit_set_last_error_v(cc, "unsupported JIT opcode 0x%2x", + insn->opcode); + GOTO_FAIL; + } + + if (err_handler.err) { + jit_set_last_error_v(cc, + "failed to generate native code for JIT " + "opcode 0x%02x, ErrorCode is %u", + insn->opcode, err_handler.err); + GOTO_FAIL; + } + +#if CODEGEN_DUMP != 0 + dump_native((char *)code.sectionById(0)->buffer().data() + + code_offset, + code.sectionById(0)->buffer().size() - code_offset); + code_offset = code.sectionById(0)->buffer().size(); +#endif + } + } + + code_buf = (char *)code.sectionById(0)->buffer().data(); + code_size = code.sectionById(0)->buffer().size(); + if (!(stream = (char *)jit_code_cache_alloc(code_size))) { + jit_set_last_error(cc, "allocate memory failed"); + goto fail; + } + + bh_memcpy_s(stream, code_size, code_buf, code_size); + cc->jitted_addr_begin = stream; + cc->jitted_addr_end = stream + code_size; + + for (i = 0; i < label_num; i++) { + if (i == 0) + label_index = 0; + else if (i == label_num - 1) + label_index = 1; + else + label_index = i + 1; + + jitted_addr = jit_annl_jitted_addr( + cc, jit_reg_new(JIT_REG_KIND_L32, label_index)); + *jitted_addr = stream + label_offsets[label_index]; + } + + patch_jmp_info_list(cc, jmp_info_list); + return_value = true; + +fail: + + jit_free(label_offsets); + free_jmp_info_list(jmp_info_list); + return return_value; +} + +#if WASM_ENABLE_LAZY_JIT != 0 && WASM_ENABLE_JIT != 0 + +#define MAX_REG_INTS 6 +#define MAX_REG_FLOATS 8 + +void * +jit_codegen_compile_call_to_llvm_jit(const WASMType *func_type) +{ + const JitHardRegInfo *hreg_info = jit_codegen_get_hreg_info(); + x86::Gp reg_lp = x86::r10, reg_res = x86::r12; + x86::Gp reg_tmp_i64 = x86::r11, reg_tmp_i32 = x86::r11d; + /* the index of integer argument registers */ + uint8 reg_idx_of_int_args[] = { REG_RDI_IDX, REG_RSI_IDX, REG_RDX_IDX, + REG_RCX_IDX, REG_R8_IDX, REG_R9_IDX }; + uint32 n_ints = 0, n_fps = 0, n_stacks = 0, n_pushed; + uint32 int_reg_idx = 0, fp_reg_idx = 0, stack_arg_idx = 0; + uint32 off_to_lp = 0, off_to_res = 0, code_size, i; + uint32 param_count = func_type->param_count; + uint32 result_count = func_type->result_count; + uint32 ext_result_count; + char *code_buf, *stream; + Imm imm; + + JitErrorHandler err_handler; + Environment env(Arch::kX64); + CodeHolder code; + code.init(env); + code.setErrorHandler(&err_handler); + x86::Assembler a(&code); + + /* Load the llvm jit function pointer */ + { + /* r11 = exec_env->module_inst */ + x86::Mem m1(regs_i64[hreg_info->exec_env_hreg_index], + (uint32)offsetof(WASMExecEnv, module_inst)); + a.mov(reg_tmp_i64, m1); + /* r11 = module_inst->func_ptrs */ + x86::Mem m2(reg_tmp_i64, + (uint32)offsetof(WASMModuleInstance, func_ptrs)); + a.mov(reg_tmp_i64, m2); + /* rax = func_ptrs[func_idx] */ + x86::Mem m3(reg_tmp_i64, x86::rdx, 3, 0); + a.mov(x86::rax, m3); + } + + n_ints++; /* exec_env */ + + for (i = 0; i < param_count; i++) { + switch (func_type->types[i]) { + case VALUE_TYPE_I32: + case VALUE_TYPE_I64: +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_FUNCREF: + case VALUE_TYPE_EXTERNREF: +#endif + if (n_ints < MAX_REG_INTS) + n_ints++; + else + n_stacks++; + break; + case VALUE_TYPE_F32: + case VALUE_TYPE_F64: + if (n_fps < MAX_REG_FLOATS) + n_fps++; + else + n_stacks++; + break; + } + } + + ext_result_count = result_count > 1 ? result_count - 1 : 0; + + if (ext_result_count > 0) { + if (n_ints + ext_result_count <= MAX_REG_INTS) { + /* extra result pointers can be stored into int registers */ + n_ints += ext_result_count; + } + else { + /* part or all extra result pointers must be stored into stack */ + n_stacks += n_ints + ext_result_count - MAX_REG_INTS; + n_ints = MAX_REG_INTS; + } + } + + n_pushed = n_stacks; + if (n_stacks & 1) { + /* Align stack on 16 bytes */ + n_pushed++; + } + if (n_pushed > 0) { + imm.setValue(n_pushed * 8); + a.sub(x86::rsp, imm); + } + + /* r10 = outs_area->lp */ + { + x86::Mem m(regs_i64[hreg_info->exec_env_hreg_index], + (uint32)offsetof(WASMExecEnv, wasm_stack.s.top)); + a.mov(reg_lp, m); + a.add(reg_lp, (uint32)offsetof(WASMInterpFrame, lp)); + } + + /* rdi = exec_env */ + a.mov(regs_i64[reg_idx_of_int_args[int_reg_idx++]], + regs_i64[hreg_info->exec_env_hreg_index]); + + for (i = 0; i < param_count; i++) { + x86::Mem m_src(reg_lp, off_to_lp); + + switch (func_type->types[i]) { + case VALUE_TYPE_I32: +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_FUNCREF: + case VALUE_TYPE_EXTERNREF: +#endif + { + if (int_reg_idx < MAX_REG_INTS) { + a.mov(regs_i32[reg_idx_of_int_args[int_reg_idx]], m_src); + int_reg_idx++; + } + else { + a.mov(reg_tmp_i32, m_src); + x86::Mem m_dst(x86::rsp, stack_arg_idx * 8); + a.mov(m_dst, reg_tmp_i32); + stack_arg_idx++; + } + off_to_lp += 4; + break; + } + case VALUE_TYPE_I64: + { + if (int_reg_idx < MAX_REG_INTS) { + a.mov(regs_i64[reg_idx_of_int_args[int_reg_idx]], m_src); + int_reg_idx++; + } + else { + a.mov(reg_tmp_i64, m_src); + x86::Mem m_dst(x86::rsp, stack_arg_idx * 8); + a.mov(m_dst, reg_tmp_i64); + stack_arg_idx++; + } + off_to_lp += 8; + break; + } + case VALUE_TYPE_F32: + { + if (fp_reg_idx < MAX_REG_FLOATS) { + a.movss(regs_float[fp_reg_idx], m_src); + fp_reg_idx++; + } + else { + a.mov(reg_tmp_i32, m_src); + x86::Mem m_dst(x86::rsp, stack_arg_idx * 8); + a.mov(m_dst, reg_tmp_i32); + stack_arg_idx++; + } + off_to_lp += 4; + break; + } + case VALUE_TYPE_F64: + { + if (fp_reg_idx < MAX_REG_FLOATS) { + a.movsd(regs_float[fp_reg_idx], m_src); + fp_reg_idx++; + } + else { + a.mov(reg_tmp_i64, m_src); + x86::Mem m_dst(x86::rsp, stack_arg_idx * 8); + a.mov(m_dst, reg_tmp_i64); + stack_arg_idx++; + } + off_to_lp += 8; + break; + } + } + } + + if (result_count > 0) { + switch (func_type->types[param_count]) { + case VALUE_TYPE_I32: +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_FUNCREF: + case VALUE_TYPE_EXTERNREF: +#endif + case VALUE_TYPE_F32: + off_to_res = 4; + break; + case VALUE_TYPE_I64: + case VALUE_TYPE_F64: + off_to_res = 8; + break; + } + + /* r12 = cur_frame->sp */ + x86::Mem m(x86::rbp, (uint32)offsetof(WASMInterpFrame, sp)); + a.mov(reg_res, m); + + for (i = 0; i < ext_result_count; i++) { + x86::Mem m(reg_res, off_to_res); + + if (int_reg_idx < MAX_REG_INTS) { + a.lea(regs_i64[reg_idx_of_int_args[int_reg_idx]], m); + int_reg_idx++; + } + else { + a.lea(reg_tmp_i64, m); + x86::Mem m_dst(x86::rsp, stack_arg_idx * 8); + a.mov(m_dst, reg_tmp_i64); + stack_arg_idx++; + } + + switch (func_type->types[param_count + 1 + i]) { + case VALUE_TYPE_I32: +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_FUNCREF: + case VALUE_TYPE_EXTERNREF: +#endif + case VALUE_TYPE_F32: + off_to_res += 4; + break; + case VALUE_TYPE_I64: + case VALUE_TYPE_F64: + off_to_res += 8; break; + } + } + } + + bh_assert(int_reg_idx == n_ints); + bh_assert(fp_reg_idx == n_fps); + bh_assert(stack_arg_idx == n_stacks); + + /* Call the llvm jit function */ + a.call(x86::rax); + + /* Check if there was exception thrown */ + { + /* r11 = exec_env->module_inst */ + x86::Mem m1(regs_i64[hreg_info->exec_env_hreg_index], + (uint32)offsetof(WASMExecEnv, module_inst)); + a.mov(reg_tmp_i64, m1); + /* module_inst->cur_exception */ + x86::Mem m2(reg_tmp_i64, + (uint32)offsetof(WASMModuleInstance, cur_exception)); + /* bl = module_inst->cur_exception[0] */ + a.mov(x86::bl, m2); + + /* cur_exception[0] == 0 ? */ + Imm imm((uint8)0); + a.cmp(x86::bl, imm); + /* If yes, jump to `Get function result and return` */ + imm.setValue(INT32_MAX); + a.je(imm); + + char *stream = (char *)a.code()->sectionById(0)->buffer().data() + + a.code()->sectionById(0)->buffer().size(); + + /* If no, set eax to JIT_INTERP_ACTION_THROWN, and + jump to code_block_return_to_interp_from_jitted to + return to interpreter */ + imm.setValue(JIT_INTERP_ACTION_THROWN); + a.mov(x86::eax, imm); + imm.setValue(code_block_return_to_interp_from_jitted); + a.mov(x86::rsi, imm); + a.jmp(x86::rsi); + + char *stream_new = (char *)a.code()->sectionById(0)->buffer().data() + + a.code()->sectionById(0)->buffer().size(); + + *(int32 *)(stream - 4) = (uint32)(stream_new - stream); + } + + /* Get function result and return */ + + if (result_count > 0 && func_type->types[param_count] != VALUE_TYPE_F32 + && func_type->types[param_count] != VALUE_TYPE_F64) { + a.mov(x86::rdx, x86::rax); + } + + if (off_to_res > 0) { + imm.setValue(off_to_res); + a.add(reg_res, imm); + /* cur_frame->sp = r12 */ + x86::Mem m(x86::rbp, (uint32)offsetof(WASMInterpFrame, sp)); + a.mov(m, reg_res); + } + + if (n_pushed > 0) { + imm.setValue(n_pushed * 8); + a.add(x86::rsp, imm); + } + + /* Return to the caller */ + { + /* eax = action = JIT_INTERP_ACTION_NORMAL */ + Imm imm(0); + a.mov(x86::eax, imm); - case JIT_OP_LDF32: - LOAD_3ARGS(); - LD_R_R_R(F32, 4, false); - break; + uint32 jitted_return_addr_offset = + jit_frontend_get_jitted_return_addr_offset(); + x86::Mem m(x86::rbp, jitted_return_addr_offset); + a.jmp(m); + } - case JIT_OP_LDF64: - LOAD_3ARGS(); - LD_R_R_R(F64, 8, false); - break; + if (err_handler.err) + return NULL; - case JIT_OP_STI8: - LOAD_3ARGS_NO_ASSIGN(); - ST_R_R_R(I32, int32, 1); - break; + code_buf = (char *)code.sectionById(0)->buffer().data(); + code_size = code.sectionById(0)->buffer().size(); + stream = (char *)jit_code_cache_alloc(code_size); + if (!stream) + return NULL; - case JIT_OP_STI16: - LOAD_3ARGS_NO_ASSIGN(); - ST_R_R_R(I32, int32, 2); - break; + bh_memcpy_s(stream, code_size, code_buf, code_size); - case JIT_OP_STI32: - LOAD_3ARGS_NO_ASSIGN(); - ST_R_R_R(I32, int32, 4); - break; +#if 0 + dump_native(stream, code_size); +#endif - case JIT_OP_STI64: - case JIT_OP_STPTR: - LOAD_3ARGS_NO_ASSIGN(); - ST_R_R_R(I64, int64, 8); - break; + return stream; +} - case JIT_OP_STF32: - LOAD_3ARGS_NO_ASSIGN(); - ST_R_R_R(F32, float32, 4); - break; +static WASMInterpFrame * +fast_jit_alloc_frame(WASMExecEnv *exec_env, uint32 param_cell_num, + uint32 ret_cell_num) +{ + WASMModuleInstance *module_inst = + (WASMModuleInstance *)exec_env->module_inst; + WASMInterpFrame *frame; + uint32 size_frame1 = wasm_interp_interp_frame_size(ret_cell_num); + uint32 size_frame2 = wasm_interp_interp_frame_size(param_cell_num); - case JIT_OP_STF64: - LOAD_3ARGS_NO_ASSIGN(); - ST_R_R_R(F64, float64, 8); - break; + /** + * Check whether we can allocate two frames: the first is an implied + * frame to store the function results from jit function to call, + * the second is the frame for the jit function + */ + if ((uint8 *)exec_env->wasm_stack.s.top + size_frame1 + size_frame2 + > exec_env->wasm_stack.s.top_boundary) { + wasm_set_exception(module_inst, "wasm operand stack overflow"); + return NULL; + } - case JIT_OP_JMP: - LOAD_1ARG(); - CHECK_KIND(r0, JIT_REG_KIND_L32); - if (!(is_last_insn - && label_is_neighboring(cc, label_index, - jit_reg_no(r0)))) - JMP_TO_LABEL(jit_reg_no(r0), label_index); - break; + /* Allocate the frame */ + frame = (WASMInterpFrame *)exec_env->wasm_stack.s.top; + exec_env->wasm_stack.s.top += size_frame1; + + frame->function = NULL; + frame->ip = NULL; + frame->sp = frame->lp; + frame->prev_frame = wasm_exec_env_get_cur_frame(exec_env); + frame->jitted_return_addr = + (uint8 *)code_block_return_to_interp_from_jitted; + + wasm_exec_env_set_cur_frame(exec_env, frame); + + return frame; +} + +void * +jit_codegen_compile_call_to_fast_jit(const WASMModule *module, uint32 func_idx) +{ + uint32 func_idx_non_import = func_idx - module->import_function_count; + WASMType *func_type = module->functions[func_idx_non_import]->func_type; + /* the index of integer argument registers */ + uint8 reg_idx_of_int_args[] = { REG_RDI_IDX, REG_RSI_IDX, REG_RDX_IDX, + REG_RCX_IDX, REG_R8_IDX, REG_R9_IDX }; + uint32 int_reg_idx, fp_reg_idx, stack_arg_idx; + uint32 switch_info_offset, exec_env_offset, stack_arg_offset; + uint32 int_reg_offset, frame_lp_offset; + uint32 switch_info_size, code_size, i; + uint32 param_count = func_type->param_count; + uint32 result_count = func_type->result_count; + uint32 ext_result_count = result_count > 1 ? result_count - 1 : 0; + uint32 param_cell_num = func_type->param_cell_num; + uint32 ret_cell_num = + func_type->ret_cell_num > 2 ? func_type->ret_cell_num : 2; + char *code_buf, *stream; + Imm imm; - case JIT_OP_BEQ: - case JIT_OP_BNE: - case JIT_OP_BGTS: - case JIT_OP_BGES: - case JIT_OP_BLTS: - case JIT_OP_BLES: - case JIT_OP_BGTU: - case JIT_OP_BGEU: - case JIT_OP_BLTU: - case JIT_OP_BLEU: - LOAD_3ARGS(); - if (!lower_branch( - cc, a, jmp_info_list, label_index, - (COND_OP)(EQ + (insn->opcode - JIT_OP_BEQ)), r0, r1, - r2, is_last_insn)) - GOTO_FAIL; - break; + JitErrorHandler err_handler; + Environment env(Arch::kX64); + CodeHolder code; + code.init(env); + code.setErrorHandler(&err_handler); + x86::Assembler a(&code); - case JIT_OP_LOOKUPSWITCH: - { - JitOpndLookupSwitch *opnd = jit_insn_opndls(insn); - if (!lower_lookupswitch(cc, a, jmp_info_list, label_offsets, - label_index, opnd, is_last_insn)) - GOTO_FAIL; - break; - } + /** + * Push JitInterpSwitchInfo and make stack 16-byte aligned: + * the size pushed must be odd multiples of 8, as the stack pointer + * %rsp must be aligned to a 16-byte boundary before making a call, + * and when a function (including this llvm jit function) gets + * control, the %rsp is not 16-byte aligned (call instruction will + * push the ret address to stack). + */ + switch_info_size = align_uint((uint32)sizeof(JitInterpSwitchInfo), 16) + 8; + imm.setValue((uint64)switch_info_size); + a.sub(x86::rsp, imm); + + /* Push all integer argument registers since we will use them as + temporarily registers to load/store data */ + for (i = 0; i < MAX_REG_INTS; i++) { + a.push(regs_i64[reg_idx_of_int_args[MAX_REG_INTS - 1 - i]]); + } - case JIT_OP_CALLNATIVE: - if (!lower_callnative(cc, a, insn)) - GOTO_FAIL; - break; + /* We don't push float/double register since we don't use them here */ - case JIT_OP_CALLBC: - if (!lower_callbc(cc, a, jmp_info_list, label_index, insn)) - GOTO_FAIL; - break; + /** + * Layout of the stack now: + * stack arguments + * ret address of the caller + * switch info + * int registers: r9, r8, rcx, rdx, rsi + * exec_env: rdi + */ + + /* offset of the first stack argument to the stack pointer, + add 8 to skip the ret address of the caller */ + stack_arg_offset = switch_info_size + 8 * MAX_REG_INTS + 8; + /* offset of jit interp switch info to the stack pointer */ + switch_info_offset = 8 * MAX_REG_INTS; + /* offset of the first int register to the stack pointer */ + int_reg_offset = 8; + /* offset of exec_env to the stack pointer */ + exec_env_offset = 0; + + /* Call fast_jit_alloc_frame to allocate the stack frame to + receive the results of the fast jit function to call */ + + /* rdi = exec_env, has been already set as exec_env is + the first argument of LLVM JIT function */ + /* rsi = param_cell_num */ + imm.setValue(param_cell_num); + a.mov(x86::rsi, imm); + /* rdx = ret_cell_num */ + imm.setValue(ret_cell_num); + a.mov(x86::rdx, imm); + /* call fast_jit_alloc_frame */ + imm.setValue((uint64)(uintptr_t)fast_jit_alloc_frame); + a.mov(x86::rax, imm); + a.call(x86::rax); + + /* Check the return value, note now rax is the allocated frame */ + { + /* Did fast_jit_alloc_frame return NULL? */ + Imm imm((uint64)0); + a.cmp(x86::rax, imm); + /* If no, jump to `Copy arguments to frame lp area` */ + imm.setValue(INT32_MAX); + a.jne(imm); - case JIT_OP_RETURNBC: - if (!lower_returnbc(cc, a, insn)) - GOTO_FAIL; - break; + char *stream = (char *)a.code()->sectionById(0)->buffer().data() + + a.code()->sectionById(0)->buffer().size(); - case JIT_OP_RETURN: - if (!lower_return(cc, a, insn)) - GOTO_FAIL; - break; + /* If yes, set eax to 0, return to caller */ - case JIT_OP_I32CASTF32: - LOAD_2ARGS(); - CAST_R_R(F32, I32, f32, i32, int32); - break; + /* Pop all integer arument registers */ + for (i = 0; i < MAX_REG_INTS; i++) { + a.pop(regs_i64[reg_idx_of_int_args[i]]); + } + /* Pop jit interp switch info */ + imm.setValue((uint64)switch_info_size); + a.add(x86::rsp, imm); + + /* Return to the caller, don't use leave as we didn't + `push rbp` and `mov rbp, rsp` */ + a.ret(); + + /* Patch the offset of jne instruction */ + char *stream_new = (char *)a.code()->sectionById(0)->buffer().data() + + a.code()->sectionById(0)->buffer().size(); + *(int32 *)(stream - 4) = (int32)(stream_new - stream); + } - case JIT_OP_I64CASTF64: - LOAD_2ARGS(); - CAST_R_R(F64, I64, f64, i64, int64); - break; + int_reg_idx = 1; /* skip exec_env */ + fp_reg_idx = 0; + stack_arg_idx = 0; + + /* Offset of the dest arguments to outs area */ + frame_lp_offset = wasm_interp_interp_frame_size(ret_cell_num) + + (uint32)offsetof(WASMInterpFrame, lp); + + /* Copy arguments to frame lp area */ + for (i = 0; i < func_type->param_count; i++) { + x86::Mem m_dst(x86::rax, frame_lp_offset); + switch (func_type->types[i]) { + case VALUE_TYPE_I32: +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_FUNCREF: + case VALUE_TYPE_EXTERNREF: +#endif + if (int_reg_idx < MAX_REG_INTS) { + /* Copy i32 argument from int register */ + x86::Mem m_src(x86::rsp, int_reg_offset); + a.mov(x86::esi, m_src); + a.mov(m_dst, x86::esi); + int_reg_offset += 8; + int_reg_idx++; + } + else { + /* Copy i32 argument from stack */ + x86::Mem m_src(x86::rsp, stack_arg_offset); + a.mov(x86::esi, m_src); + a.mov(m_dst, x86::esi); + stack_arg_offset += 8; + stack_arg_idx++; + } + frame_lp_offset += 4; + break; + case VALUE_TYPE_I64: + if (int_reg_idx < MAX_REG_INTS) { + /* Copy i64 argument from int register */ + x86::Mem m_src(x86::rsp, int_reg_offset); + a.mov(x86::rsi, m_src); + a.mov(m_dst, x86::rsi); + int_reg_offset += 8; + int_reg_idx++; + } + else { + /* Copy i64 argument from stack */ + x86::Mem m_src(x86::rsp, stack_arg_offset); + a.mov(x86::rsi, m_src); + a.mov(m_dst, x86::rsi); + stack_arg_offset += 8; + stack_arg_idx++; + } + frame_lp_offset += 8; + break; + case VALUE_TYPE_F32: + if (fp_reg_idx < MAX_REG_FLOATS) { + /* Copy f32 argument from fp register */ + a.movss(m_dst, regs_float[fp_reg_idx++]); + } + else { + /* Copy f32 argument from stack */ + x86::Mem m_src(x86::rsp, stack_arg_offset); + a.mov(x86::esi, m_src); + a.mov(m_dst, x86::esi); + stack_arg_offset += 8; + stack_arg_idx++; + } + frame_lp_offset += 4; + break; + case VALUE_TYPE_F64: + if (fp_reg_idx < MAX_REG_FLOATS) { + /* Copy f64 argument from fp register */ + a.movsd(m_dst, regs_float[fp_reg_idx++]); + } + else { + /* Copy f64 argument from stack */ + x86::Mem m_src(x86::rsp, stack_arg_offset); + a.mov(x86::rsi, m_src); + a.mov(m_dst, x86::rsi); + stack_arg_offset += 8; + stack_arg_idx++; + } + frame_lp_offset += 8; + break; + default: + bh_assert(0); + } + } - case JIT_OP_F32CASTI32: - LOAD_2ARGS(); - CAST_R_R(I32, F32, i32, f32, float); - break; + /* Call the fast jit function */ + { + /* info = rsp + switch_info_offset */ + a.lea(x86::rsi, x86::ptr(x86::rsp, switch_info_offset)); + /* info.frame = frame = rax, or return of fast_jit_alloc_frame */ + x86::Mem m1(x86::rsi, (uint32)offsetof(JitInterpSwitchInfo, frame)); + a.mov(m1, x86::rax); + + /* Call code_block_switch_to_jitted_from_interp + with argument (exec_env, info, func_idx, pc) */ + /* rdi = exec_env */ + a.mov(x86::rdi, x86::ptr(x86::rsp, exec_env_offset)); + /* rsi = info, has been set */ + /* rdx = func_idx */ + imm.setValue(func_idx); + a.mov(x86::rdx, imm); + /* module_inst = exec_env->module_inst */ + a.mov(x86::rcx, + x86::ptr(x86::rdi, (uint32)offsetof(WASMExecEnv, module_inst))); + /* fast_jit_func_ptrs = module_inst->fast_jit_func_ptrs */ + a.mov(x86::rcx, + x86::ptr(x86::rcx, (uint32)offsetof(WASMModuleInstance, + fast_jit_func_ptrs))); + imm.setValue(func_idx_non_import); + a.mov(x86::rax, imm); + x86::Mem m3(x86::rcx, x86::rax, 3, 0); + /* rcx = module_inst->fast_jit_func_ptrs[func_idx_non_import] */ + a.mov(x86::rcx, m3); + + imm.setValue( + (uint64)(uintptr_t)code_block_switch_to_jitted_from_interp); + a.mov(x86::rax, imm); + a.call(x86::rax); + } - case JIT_OP_F64CASTI64: - LOAD_2ARGS(); - CAST_R_R(I64, F64, i64, f64, double); - break; + /* No need to check exception thrown here as it will be checked + in the caller */ - default: - jit_set_last_error_v(cc, "unsupported JIT opcode 0x%2x", - insn->opcode); - GOTO_FAIL; - } + /* Copy function results */ + if (result_count > 0) { + frame_lp_offset = offsetof(WASMInterpFrame, lp); - if (err_handler.err) { - jit_set_last_error_v(cc, - "failed to generate native code for JIT " - "opcode 0x%02x, ErrorCode is %u", - insn->opcode, err_handler.err); - GOTO_FAIL; - } + switch (func_type->types[param_count]) { + case VALUE_TYPE_I32: +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_FUNCREF: + case VALUE_TYPE_EXTERNREF: +#endif + a.mov(x86::eax, x86::edx); + frame_lp_offset += 4; + break; + case VALUE_TYPE_I64: + a.mov(x86::rax, x86::rdx); + frame_lp_offset += 8; + break; + case VALUE_TYPE_F32: + /* The first result has been put to xmm0 */ + frame_lp_offset += 4; + break; + case VALUE_TYPE_F64: + /* The first result has been put to xmm0 */ + frame_lp_offset += 8; + break; + default: + bh_assert(0); + } -#if CODEGEN_DUMP != 0 - dump_native((char *)code.sectionById(0)->buffer().data() - + code_offset, - code.sectionById(0)->buffer().size() - code_offset); - code_offset = code.sectionById(0)->buffer().size(); + /* Copy extra results from exec_env->cur_frame */ + if (ext_result_count > 0) { + /* rdi = exec_env */ + a.mov(x86::rdi, x86::ptr(x86::rsp, exec_env_offset)); + /* rsi = exec_env->cur_frame */ + a.mov(x86::rsi, + x86::ptr(x86::rdi, (uint32)offsetof(WASMExecEnv, cur_frame))); + + for (i = 0; i < ext_result_count; i++) { + switch (func_type->types[param_count + 1 + i]) { + case VALUE_TYPE_I32: +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_FUNCREF: + case VALUE_TYPE_EXTERNREF: #endif + case VALUE_TYPE_F32: + { + /* Copy 32-bit result */ + a.mov(x86::ecx, x86::ptr(x86::rsi, frame_lp_offset)); + if (int_reg_idx < MAX_REG_INTS) { + x86::Mem m1(x86::rsp, + exec_env_offset + int_reg_idx * 8); + a.mov(x86::rdx, m1); + x86::Mem m2(x86::rdx, 0); + a.mov(m2, x86::ecx); + int_reg_idx++; + } + else { + x86::Mem m1(x86::rsp, stack_arg_offset); + a.mov(x86::rdx, m1); + x86::Mem m2(x86::rdx, 0); + a.mov(m2, x86::ecx); + stack_arg_offset += 8; + stack_arg_idx++; + } + frame_lp_offset += 4; + break; + } + case VALUE_TYPE_I64: + case VALUE_TYPE_F64: + { + /* Copy 64-bit result */ + a.mov(x86::rcx, x86::ptr(x86::rsi, frame_lp_offset)); + if (int_reg_idx < MAX_REG_INTS) { + x86::Mem m1(x86::rsp, + exec_env_offset + int_reg_idx * 8); + a.mov(x86::rdx, m1); + x86::Mem m2(x86::rdx, 0); + a.mov(m2, x86::rcx); + int_reg_idx++; + } + else { + x86::Mem m1(x86::rsp, stack_arg_offset); + a.mov(x86::rdx, m1); + x86::Mem m2(x86::rdx, 0); + a.mov(m2, x86::rcx); + stack_arg_offset += 8; + stack_arg_idx++; + } + frame_lp_offset += 8; + break; + } + default: + bh_assert(0); + } + } } } - code_buf = (char *)code.sectionById(0)->buffer().data(); - code_size = code.sectionById(0)->buffer().size(); - if (!(stream = (char *)jit_code_cache_alloc(code_size))) { - jit_set_last_error(cc, "allocate memory failed"); - goto fail; + /* Free the frame allocated */ + + /* rdi = exec_env */ + a.mov(x86::rdi, x86::ptr(x86::rsp, exec_env_offset)); + /* rsi = exec_env->cur_frame */ + a.mov(x86::rsi, + x86::ptr(x86::rdi, (uint32)offsetof(WASMExecEnv, cur_frame))); + /* rdx = exec_env->cur_frame->prev_frame */ + a.mov(x86::rdx, + x86::ptr(x86::rsi, (uint32)offsetof(WASMInterpFrame, prev_frame))); + /* exec_env->wasm_stack.s.top = cur_frame */ + { + x86::Mem m(x86::rdi, offsetof(WASMExecEnv, wasm_stack.s.top)); + a.mov(m, x86::rsi); + } + /* exec_env->cur_frame = prev_frame */ + { + x86::Mem m(x86::rdi, offsetof(WASMExecEnv, cur_frame)); + a.mov(m, x86::rdx); } - bh_memcpy_s(stream, code_size, code_buf, code_size); - cc->jitted_addr_begin = stream; - cc->jitted_addr_end = stream + code_size; + /* Pop all integer arument registers */ + for (i = 0; i < MAX_REG_INTS; i++) { + a.pop(regs_i64[reg_idx_of_int_args[i]]); + } + /* Pop jit interp switch info */ + imm.setValue((uint64)switch_info_size); + a.add(x86::rsp, imm); - for (i = 0; i < label_num; i++) { - if (i == 0) - label_index = 0; - else if (i == label_num - 1) - label_index = 1; - else - label_index = i + 1; + /* Return to the caller, don't use leave as we didn't + `push rbp` and `mov rbp, rsp` */ + a.ret(); - jitted_addr = jit_annl_jitted_addr( - cc, jit_reg_new(JIT_REG_KIND_L32, label_index)); - *jitted_addr = stream + label_offsets[label_index]; + if (err_handler.err) { + return NULL; } - patch_jmp_info_list(cc, jmp_info_list); - return_value = true; + code_buf = (char *)code.sectionById(0)->buffer().data(); + code_size = code.sectionById(0)->buffer().size(); + stream = (char *)jit_code_cache_alloc(code_size); + if (!stream) + return NULL; -fail: + bh_memcpy_s(stream, code_size, code_buf, code_size); - jit_free(label_offsets); - free_jmp_info_list(jmp_info_list); - return return_value; +#if 0 + printf("Code of call to fast jit of func %u:\n", func_idx); + dump_native(stream, code_size); + printf("\n"); +#endif + + return stream; } +#endif /* end of WASM_ENABLE_LAZY_JIT != 0 && WASM_ENABLE_JIT != 0 */ + bool jit_codegen_lower(JitCompContext *cc) { @@ -6793,6 +9155,8 @@ jit_codegen_init() code.setErrorHandler(&err_handler); x86::Assembler a(&code); + /* Initialize code_block_switch_to_jitted_from_interp */ + /* push callee-save registers */ a.push(x86::rbp); a.push(x86::rbx); @@ -6812,9 +9176,11 @@ jit_codegen_init() /* exec_env_reg = exec_env */ a.mov(regs_i64[hreg_info->exec_env_hreg_index], x86::rdi); /* fp_reg = info->frame */ - a.mov(x86::rbp, x86::ptr(x86::rsi, 0)); - /* jmp target */ - a.jmp(x86::rdx); + a.mov(x86::rbp, x86::ptr(x86::rsi, offsetof(JitInterpSwitchInfo, frame))); + /* rdx = func_idx, is already set in the func_idx argument of + jit_codegen_interp_jitted_glue */ + /* jmp target, rcx = pc */ + a.jmp(x86::rcx); if (err_handler.err) return false; @@ -6832,26 +9198,25 @@ jit_codegen_init() dump_native(stream, code_size); #endif - a.setOffset(0); + /* Initialize code_block_return_to_interp_from_jitted */ - /* TODO: mask floating-point exception */ - /* TODO: floating-point parameters */ + a.setOffset(0); /* pop info */ a.pop(x86::rsi); /* info->frame = fp_reg */ { - x86::Mem m(x86::rsi, 0); + x86::Mem m(x86::rsi, offsetof(JitInterpSwitchInfo, frame)); a.mov(m, x86::rbp); } - /* info->out.ret.ival[0, 1] = rcx */ + /* info->out.ret.ival[0, 1] = rdx */ { - x86::Mem m(x86::rsi, 8); + x86::Mem m(x86::rsi, offsetof(JitInterpSwitchInfo, out.ret.ival)); a.mov(m, x86::rdx); } /* info->out.ret.fval[0, 1] = xmm0 */ { - x86::Mem m(x86::rsi, 16); + x86::Mem m(x86::rsi, offsetof(JitInterpSwitchInfo, out.ret.fval)); a.movsd(m, x86::xmm0); } @@ -6874,12 +9239,125 @@ jit_codegen_init() goto fail1; bh_memcpy_s(stream, code_size, code_buf, code_size); - code_block_return_to_interp_from_jitted = stream; + code_block_return_to_interp_from_jitted = + jit_globals->return_to_interp_from_jitted = stream; + +#if 0 + dump_native(stream, code_size); +#endif + +#if WASM_ENABLE_LAZY_JIT != 0 + /* Initialize code_block_compile_fast_jit_and_then_call */ + + a.setOffset(0); + + /* Use rbx, r12, r13 to save func_dix, module_inst and module, + as they are callee-save registers */ + + /* Backup func_idx: rbx = rdx = func_idx, note that rdx has + been prepared in the caller: + callbc or code_block_switch_to_jitted_from_interp */ + a.mov(x86::rbx, x86::rdx); + /* r12 = module_inst = exec_env->module_inst */ + { + x86::Mem m(regs_i64[hreg_info->exec_env_hreg_index], + (uint32)offsetof(WASMExecEnv, module_inst)); + a.mov(x86::r12, m); + } + /* rdi = r13 = module_inst->module */ + { + x86::Mem m(x86::r12, (uint32)offsetof(WASMModuleInstance, module)); + a.mov(x86::rdi, m); + a.mov(x86::r13, x86::rdi); + } + /* rsi = rdx = func_idx */ + a.mov(x86::rsi, x86::rdx); + /* Call jit_compiler_compile(module, func_idx) */ + { + Imm imm((uint64)(uintptr_t)jit_compiler_compile); + a.mov(x86::rax, imm); + a.call(x86::rax); + } + + /* Check if failed to compile the jit function */ + { + /* Did jit_compiler_compile return false? */ + Imm imm((uint8)0); + a.cmp(x86::al, imm); + /* If no, jump to `Load compiled func ptr and call it` */ + imm.setValue(INT32_MAX); + a.jne(imm); + + char *stream = (char *)a.code()->sectionById(0)->buffer().data() + + a.code()->sectionById(0)->buffer().size(); + + /* If yes, call jit_set_exception_with_id to throw exception, + and then set eax to JIT_INTERP_ACTION_THROWN, and jump to + code_block_return_to_interp_from_jitted to return */ + + /* rdi = module_inst */ + a.mov(x86::rdi, x86::r12); + /* rsi = EXCE_FAILED_TO_COMPILE_FAST_JIT_FUNC */ + imm.setValue(EXCE_FAILED_TO_COMPILE_FAST_JIT_FUNC); + a.mov(x86::rsi, imm); + /* Call jit_set_exception_with_id */ + imm.setValue((uint64)(uintptr_t)jit_set_exception_with_id); + a.mov(x86::rax, imm); + a.call(x86::rax); + /* Return to the caller */ + imm.setValue(JIT_INTERP_ACTION_THROWN); + a.mov(x86::eax, imm); + imm.setValue(code_block_return_to_interp_from_jitted); + a.mov(x86::rsi, imm); + a.jmp(x86::rsi); + + /* Patch the offset of jne instruction */ + char *stream_new = (char *)a.code()->sectionById(0)->buffer().data() + + a.code()->sectionById(0)->buffer().size(); + *(int32 *)(stream - 4) = (int32)(stream_new - stream); + } + + /* Load compiled func ptr and call it */ + { + /* rsi = module->import_function_count */ + x86::Mem m1(x86::r13, + (uint32)offsetof(WASMModule, import_function_count)); + a.movzx(x86::rsi, m1); + /* rbx = rbx - module->import_function_count */ + a.sub(x86::rbx, x86::rsi); + /* rax = module->fast_jit_func_ptrs */ + x86::Mem m2(x86::r13, (uint32)offsetof(WASMModule, fast_jit_func_ptrs)); + a.mov(x86::rax, m2); + /* rax = fast_jit_func_ptrs[rbx] */ + x86::Mem m3(x86::rax, x86::rbx, 3, 0); + a.mov(x86::rax, m3); + a.jmp(x86::rax); + } + + if (err_handler.err) + goto fail2; + + code_buf = (char *)code.sectionById(0)->buffer().data(); + code_size = code.sectionById(0)->buffer().size(); + stream = (char *)jit_code_cache_alloc(code_size); + if (!stream) + goto fail2; + + bh_memcpy_s(stream, code_size, code_buf, code_size); + code_block_compile_fast_jit_and_then_call = + jit_globals->compile_fast_jit_and_then_call = stream; + +#if 0 + dump_native(stream, code_size); +#endif +#endif /* end of WASM_ENABLE_LAZY_JIT != 0 */ - jit_globals->return_to_interp_from_jitted = - code_block_return_to_interp_from_jitted; return true; +#if WASM_ENABLE_LAZY_JIT != 0 +fail2: + jit_code_cache_free(code_block_return_to_interp_from_jitted); +#endif fail1: jit_code_cache_free(code_block_switch_to_jitted_from_interp); return false; @@ -6888,8 +9366,11 @@ jit_codegen_init() void jit_codegen_destroy() { - jit_code_cache_free(code_block_switch_to_jitted_from_interp); +#if WASM_ENABLE_LAZY_JIT != 0 + jit_code_cache_free(code_block_compile_fast_jit_and_then_call); +#endif jit_code_cache_free(code_block_return_to_interp_from_jitted); + jit_code_cache_free(code_block_switch_to_jitted_from_interp); } /* clang-format off */ diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/fe/jit_emit_compare.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/fe/jit_emit_compare.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/fe/jit_emit_compare.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/fe/jit_emit_compare.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/fe/jit_emit_compare.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/fe/jit_emit_compare.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/fe/jit_emit_compare.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/fe/jit_emit_compare.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/fe/jit_emit_const.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/fe/jit_emit_const.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/fe/jit_emit_const.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/fe/jit_emit_const.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/fe/jit_emit_const.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/fe/jit_emit_const.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/fe/jit_emit_const.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/fe/jit_emit_const.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/fe/jit_emit_control.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/fe/jit_emit_control.c similarity index 91% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/fe/jit_emit_control.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/fe/jit_emit_control.c index eafce674982..f7536c73ea1 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/fe/jit_emit_control.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/fe/jit_emit_control.c @@ -5,6 +5,7 @@ #include "jit_emit_control.h" #include "jit_emit_exception.h" +#include "jit_emit_function.h" #include "../jit_frontend.h" #include "../interpreter/wasm_loader.h" @@ -29,7 +30,7 @@ #define BUILD_COND_BR(value_if, block_then, block_else) \ do { \ - if (!GEN_INSN(CMP, cc->cmp_reg, value_if, NEW_CONST(cc, 0)) \ + if (!GEN_INSN(CMP, cc->cmp_reg, value_if, NEW_CONST(I32, 0)) \ || !GEN_INSN(BNE, cc->cmp_reg, jit_basic_block_label(block_then), \ jit_basic_block_label(block_else))) { \ jit_set_last_error(cc, "generate bne insn failed"); \ @@ -380,11 +381,51 @@ copy_block_arities(JitCompContext *cc, JitReg dst_frame_sp, uint8 *dst_types, } } -static void +static bool handle_func_return(JitCompContext *cc, JitBlock *block) { JitReg prev_frame, prev_frame_sp; JitReg ret_reg = 0; +#if WASM_ENABLE_PERF_PROFILING != 0 + JitReg func_inst = jit_cc_new_reg_ptr(cc); + JitReg time_start = jit_cc_new_reg_I64(cc); + JitReg time_end = jit_cc_new_reg_I64(cc); + JitReg cur_exec_time = jit_cc_new_reg_I64(cc); + JitReg total_exec_time = jit_cc_new_reg_I64(cc); + JitReg total_exec_cnt = jit_cc_new_reg_I32(cc); +#endif + +#if WASM_ENABLE_PERF_PROFILING != 0 + /* time_end = os_time_get_boot_microsecond() */ + if (!jit_emit_callnative(cc, os_time_get_boot_microsecond, time_end, NULL, + 0)) { + return false; + } + /* time_start = cur_frame->time_started */ + GEN_INSN(LDI64, time_start, cc->fp_reg, + NEW_CONST(I32, offsetof(WASMInterpFrame, time_started))); + /* cur_exec_time = time_end - time_start */ + GEN_INSN(SUB, cur_exec_time, time_end, time_start); + /* func_inst = cur_frame->function */ + GEN_INSN(LDPTR, func_inst, cc->fp_reg, + NEW_CONST(I32, offsetof(WASMInterpFrame, function))); + /* total_exec_time = func_inst->total_exec_time */ + GEN_INSN(LDI64, total_exec_time, func_inst, + NEW_CONST(I32, offsetof(WASMFunctionInstance, total_exec_time))); + /* total_exec_time += cur_exec_time */ + GEN_INSN(ADD, total_exec_time, total_exec_time, cur_exec_time); + /* func_inst->total_exec_time = total_exec_time */ + GEN_INSN(STI64, total_exec_time, func_inst, + NEW_CONST(I32, offsetof(WASMFunctionInstance, total_exec_time))); + /* totoal_exec_cnt = func_inst->total_exec_cnt */ + GEN_INSN(LDI32, total_exec_cnt, func_inst, + NEW_CONST(I32, offsetof(WASMFunctionInstance, total_exec_cnt))); + /* total_exec_cnt++ */ + GEN_INSN(ADD, total_exec_cnt, total_exec_cnt, NEW_CONST(I32, 1)); + /* func_inst->total_exec_cnt = total_exec_cnt */ + GEN_INSN(STI32, total_exec_cnt, func_inst, + NEW_CONST(I32, offsetof(WASMFunctionInstance, total_exec_cnt))); +#endif prev_frame = jit_cc_new_reg_ptr(cc); prev_frame_sp = jit_cc_new_reg_ptr(cc); @@ -420,6 +461,8 @@ handle_func_return(JitCompContext *cc, JitBlock *block) GEN_INSN(MOV, cc->fp_reg, prev_frame); /* return 0 */ GEN_INSN(RETURNBC, NEW_CONST(I32, JIT_INTERP_ACTION_NORMAL), ret_reg, 0); + + return true; } /** @@ -446,7 +489,9 @@ handle_op_end(JitCompContext *cc, uint8 **p_frame_ip, bool is_block_polymorphic) create the end basic block, just continue to translate the following opcodes */ if (block->label_type == LABEL_TYPE_FUNCTION) { - handle_func_return(cc, block); + if (!handle_func_return(cc, block)) { + return false; + } SET_BB_END_BCIP(cc->cur_basic_block, *p_frame_ip - 1); clear_values(jit_frame); } @@ -548,7 +593,10 @@ handle_op_end(JitCompContext *cc, uint8 **p_frame_ip, bool is_block_polymorphic) block = jit_block_stack_pop(&cc->block_stack); if (block->label_type == LABEL_TYPE_FUNCTION) { - handle_func_return(cc, block); + if (!handle_func_return(cc, block)) { + jit_block_destroy(block); + goto fail; + } SET_BB_END_BCIP(cc->cur_basic_block, *p_frame_ip - 1); clear_values(jit_frame); } @@ -856,6 +904,42 @@ check_copy_arities(const JitBlock *block_dst, JitFrame *jit_frame) } } +#if WASM_ENABLE_THREAD_MGR != 0 +bool +jit_check_suspend_flags(JitCompContext *cc) +{ + JitReg exec_env, suspend_flags, terminate_flag, offset; + JitBasicBlock *terminate_block, *cur_basic_block; + JitFrame *jit_frame = cc->jit_frame; + + cur_basic_block = cc->cur_basic_block; + terminate_block = jit_cc_new_basic_block(cc, 0); + if (!terminate_block) { + return false; + } + + gen_commit_values(jit_frame, jit_frame->lp, jit_frame->sp); + exec_env = cc->exec_env_reg; + suspend_flags = jit_cc_new_reg_I32(cc); + terminate_flag = jit_cc_new_reg_I32(cc); + + offset = jit_cc_new_const_I32(cc, offsetof(WASMExecEnv, suspend_flags)); + GEN_INSN(LDI32, suspend_flags, exec_env, offset); + GEN_INSN(AND, terminate_flag, suspend_flags, NEW_CONST(I32, 1)); + + GEN_INSN(CMP, cc->cmp_reg, terminate_flag, NEW_CONST(I32, 0)); + GEN_INSN(BNE, cc->cmp_reg, jit_basic_block_label(terminate_block), 0); + + cc->cur_basic_block = terminate_block; + GEN_INSN(RETURN, NEW_CONST(I32, 0)); + + cc->cur_basic_block = cur_basic_block; + + return true; +} + +#endif + static bool handle_op_br(JitCompContext *cc, uint32 br_depth, uint8 **p_frame_ip) { @@ -938,6 +1022,13 @@ handle_op_br(JitCompContext *cc, uint32 br_depth, uint8 **p_frame_ip) bool jit_compile_op_br(JitCompContext *cc, uint32 br_depth, uint8 **p_frame_ip) { + +#if WASM_ENABLE_THREAD_MGR != 0 + /* Insert suspend check point */ + if (!jit_check_suspend_flags(cc)) + return false; +#endif + return handle_op_br(cc, br_depth, p_frame_ip) && handle_next_reachable_block(cc, p_frame_ip); } @@ -1057,6 +1148,12 @@ jit_compile_op_br_if(JitCompContext *cc, uint32 br_depth, jit_insn_delete(insn_select); } +#if WASM_ENABLE_THREAD_MGR != 0 + /* Insert suspend check point */ + if (!jit_check_suspend_flags(cc)) + return false; +#endif + SET_BUILDER_POS(if_basic_block); SET_BB_BEGIN_BCIP(if_basic_block, *p_frame_ip - 1); @@ -1096,6 +1193,12 @@ jit_compile_op_br_table(JitCompContext *cc, uint32 *br_depths, uint32 br_count, uint32 i = 0; JitOpndLookupSwitch *opnd = NULL; +#if WASM_ENABLE_THREAD_MGR != 0 + /* Insert suspend check point */ + if (!jit_check_suspend_flags(cc)) + return false; +#endif + cur_basic_block = cc->cur_basic_block; POP_I32(value); @@ -1190,7 +1293,9 @@ jit_compile_op_return(JitCompContext *cc, uint8 **p_frame_ip) bh_assert(block_func); - handle_func_return(cc, block_func); + if (!handle_func_return(cc, block_func)) { + return false; + } SET_BB_END_BCIP(cc->cur_basic_block, *p_frame_ip - 1); clear_values(cc->jit_frame); @@ -1200,7 +1305,7 @@ jit_compile_op_return(JitCompContext *cc, uint8 **p_frame_ip) bool jit_compile_op_unreachable(JitCompContext *cc, uint8 **p_frame_ip) { - if (!jit_emit_exception(cc, JIT_EXCE_UNREACHABLE, JIT_OP_JMP, 0, NULL)) + if (!jit_emit_exception(cc, EXCE_UNREACHABLE, JIT_OP_JMP, 0, NULL)) return false; return handle_next_reachable_block(cc, p_frame_ip); diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/fe/jit_emit_control.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/fe/jit_emit_control.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/fe/jit_emit_control.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/fe/jit_emit_control.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/fe/jit_emit_conversion.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/fe/jit_emit_conversion.c similarity index 97% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/fe/jit_emit_conversion.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/fe/jit_emit_conversion.c index e753f929d66..8308a3ca945 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/fe/jit_emit_conversion.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/fe/jit_emit_conversion.c @@ -201,19 +201,19 @@ jit_compile_check_value_range(JitCompContext *cc, JitReg value, JitReg min_fp, goto fail; GEN_INSN(CMP, cc->cmp_reg, nan_ret, NEW_CONST(I32, 1)); - if (!jit_emit_exception(cc, JIT_EXCE_INVALID_CONVERSION_TO_INTEGER, - JIT_OP_BEQ, cc->cmp_reg, NULL)) + if (!jit_emit_exception(cc, EXCE_INVALID_CONVERSION_TO_INTEGER, JIT_OP_BEQ, + cc->cmp_reg, NULL)) goto fail; /* If value is out of integer range, throw exception */ GEN_INSN(CMP, cc->cmp_reg, min_fp, value); - if (!jit_emit_exception(cc, JIT_EXCE_INTEGER_OVERFLOW, JIT_OP_BGES, - cc->cmp_reg, NULL)) + if (!jit_emit_exception(cc, EXCE_INTEGER_OVERFLOW, JIT_OP_BGES, cc->cmp_reg, + NULL)) goto fail; GEN_INSN(CMP, cc->cmp_reg, value, max_fp); - if (!jit_emit_exception(cc, JIT_EXCE_INTEGER_OVERFLOW, JIT_OP_BGES, - cc->cmp_reg, NULL)) + if (!jit_emit_exception(cc, EXCE_INTEGER_OVERFLOW, JIT_OP_BGES, cc->cmp_reg, + NULL)) goto fail; return true; diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/fe/jit_emit_conversion.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/fe/jit_emit_conversion.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/fe/jit_emit_conversion.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/fe/jit_emit_conversion.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/fe/jit_emit_exception.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/fe/jit_emit_exception.c similarity index 98% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/fe/jit_emit_exception.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/fe/jit_emit_exception.c index 5e22768583c..2addb5cde2f 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/fe/jit_emit_exception.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/fe/jit_emit_exception.c @@ -14,7 +14,7 @@ jit_emit_exception(JitCompContext *cc, int32 exception_id, uint8 jit_opcode, JitIncomingInsn *incoming_insn; JitReg else_label; - bh_assert(exception_id < JIT_EXCE_NUM); + bh_assert(exception_id < EXCE_NUM); if (jit_opcode >= JIT_OP_BEQ && jit_opcode <= JIT_OP_BLEU) { bh_assert(cond_br_if == cc->cmp_reg); diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/fe/jit_emit_exception.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/fe/jit_emit_exception.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/fe/jit_emit_exception.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/fe/jit_emit_exception.h diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/fe/jit_emit_function.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/fe/jit_emit_function.c new file mode 100644 index 00000000000..3ac9e3ed6bb --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/fe/jit_emit_function.c @@ -0,0 +1,945 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "jit_emit_function.h" +#include "jit_emit_exception.h" +#include "jit_emit_control.h" +#include "../jit_frontend.h" +#include "../jit_codegen.h" +#include "../../interpreter/wasm_runtime.h" + +static bool +emit_callnative(JitCompContext *cc, JitReg native_func_reg, JitReg res, + JitReg *params, uint32 param_count); + +/* Prepare parameters for the function to call */ +static bool +pre_call(JitCompContext *cc, const WASMType *func_type) +{ + JitReg value; + uint32 i, outs_off; + /* Prepare parameters for the function to call */ + outs_off = + cc->total_frame_size + offsetof(WASMInterpFrame, lp) + + wasm_get_cell_num(func_type->types, func_type->param_count) * 4; + + for (i = 0; i < func_type->param_count; i++) { + switch (func_type->types[func_type->param_count - 1 - i]) { + case VALUE_TYPE_I32: +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_EXTERNREF: + case VALUE_TYPE_FUNCREF: +#endif + POP_I32(value); + outs_off -= 4; + GEN_INSN(STI32, value, cc->fp_reg, NEW_CONST(I32, outs_off)); + break; + case VALUE_TYPE_I64: + POP_I64(value); + outs_off -= 8; + GEN_INSN(STI64, value, cc->fp_reg, NEW_CONST(I32, outs_off)); + break; + case VALUE_TYPE_F32: + POP_F32(value); + outs_off -= 4; + GEN_INSN(STF32, value, cc->fp_reg, NEW_CONST(I32, outs_off)); + break; + case VALUE_TYPE_F64: + POP_F64(value); + outs_off -= 8; + GEN_INSN(STF64, value, cc->fp_reg, NEW_CONST(I32, outs_off)); + break; + default: + bh_assert(0); + goto fail; + } + } + + /* Commit sp as the callee may use it to store the results */ + gen_commit_sp_ip(cc->jit_frame); + + return true; +fail: + return false; +} + +/* Push results */ +static bool +post_return(JitCompContext *cc, const WASMType *func_type, JitReg first_res, + bool update_committed_sp) +{ + uint32 i, n; + JitReg value; + + n = cc->jit_frame->sp - cc->jit_frame->lp; + for (i = 0; i < func_type->result_count; i++) { + switch (func_type->types[func_type->param_count + i]) { + case VALUE_TYPE_I32: +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_EXTERNREF: + case VALUE_TYPE_FUNCREF: +#endif + if (i == 0 && first_res) { + bh_assert(jit_reg_kind(first_res) == JIT_REG_KIND_I32); + value = first_res; + } + else { + value = jit_cc_new_reg_I32(cc); + GEN_INSN(LDI32, value, cc->fp_reg, + NEW_CONST(I32, offset_of_local(n))); + } + PUSH_I32(value); + n++; + break; + case VALUE_TYPE_I64: + if (i == 0 && first_res) { + bh_assert(jit_reg_kind(first_res) == JIT_REG_KIND_I64); + value = first_res; + } + else { + value = jit_cc_new_reg_I64(cc); + GEN_INSN(LDI64, value, cc->fp_reg, + NEW_CONST(I32, offset_of_local(n))); + } + PUSH_I64(value); + n += 2; + break; + case VALUE_TYPE_F32: + if (i == 0 && first_res) { + bh_assert(jit_reg_kind(first_res) == JIT_REG_KIND_F32); + value = first_res; + } + else { + value = jit_cc_new_reg_F32(cc); + GEN_INSN(LDF32, value, cc->fp_reg, + NEW_CONST(I32, offset_of_local(n))); + } + PUSH_F32(value); + n++; + break; + case VALUE_TYPE_F64: + if (i == 0 && first_res) { + bh_assert(jit_reg_kind(first_res) == JIT_REG_KIND_F64); + value = first_res; + } + else { + value = jit_cc_new_reg_F64(cc); + GEN_INSN(LDF64, value, cc->fp_reg, + NEW_CONST(I32, offset_of_local(n))); + } + PUSH_F64(value); + n += 2; + break; + default: + bh_assert(0); + goto fail; + } + } + + if (update_committed_sp) + /* Update the committed_sp as the callee has updated the frame sp */ + cc->jit_frame->committed_sp = cc->jit_frame->sp; + + return true; +fail: + return false; +} + +static bool +pre_load(JitCompContext *cc, JitReg *argvs, const WASMType *func_type) +{ + JitReg value; + uint32 i; + + /* Prepare parameters for the function to call */ + for (i = 0; i < func_type->param_count; i++) { + switch (func_type->types[func_type->param_count - 1 - i]) { + case VALUE_TYPE_I32: +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_EXTERNREF: + case VALUE_TYPE_FUNCREF: +#endif + POP_I32(value); + argvs[func_type->param_count - 1 - i] = value; + break; + case VALUE_TYPE_I64: + POP_I64(value); + argvs[func_type->param_count - 1 - i] = value; + break; + case VALUE_TYPE_F32: + POP_F32(value); + argvs[func_type->param_count - 1 - i] = value; + break; + case VALUE_TYPE_F64: + POP_F64(value); + argvs[func_type->param_count - 1 - i] = value; + break; + default: + bh_assert(0); + goto fail; + } + } + + gen_commit_sp_ip(cc->jit_frame); + + return true; +fail: + return false; +} + +static JitReg +create_first_res_reg(JitCompContext *cc, const WASMType *func_type) +{ + if (func_type->result_count) { + switch (func_type->types[func_type->param_count]) { + case VALUE_TYPE_I32: +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_EXTERNREF: + case VALUE_TYPE_FUNCREF: +#endif + return jit_cc_new_reg_I32(cc); + case VALUE_TYPE_I64: + return jit_cc_new_reg_I64(cc); + case VALUE_TYPE_F32: + return jit_cc_new_reg_F32(cc); + case VALUE_TYPE_F64: + return jit_cc_new_reg_F64(cc); + default: + bh_assert(0); + return 0; + } + } + return 0; +} + +bool +jit_compile_op_call(JitCompContext *cc, uint32 func_idx, bool tail_call) +{ + WASMModule *wasm_module = cc->cur_wasm_module; + WASMFunctionImport *func_import; + WASMFunction *func; + WASMType *func_type; + JitFrame *jit_frame = cc->jit_frame; + JitReg fast_jit_func_ptrs, jitted_code = 0; + JitReg native_func, *argvs = NULL, *argvs1 = NULL, func_params[5]; + JitReg native_addr_ptr, module_inst_reg, ret, res; + uint32 jitted_func_idx, i; + uint64 total_size; + const char *signature = NULL; + /* Whether the argument is a pointer/str argument and + need to call jit_check_app_addr_and_convert */ + bool is_pointer_arg; + bool return_value = false; + +#if WASM_ENABLE_THREAD_MGR != 0 + /* Insert suspend check point */ + if (!jit_check_suspend_flags(cc)) + goto fail; +#endif + + if (func_idx < wasm_module->import_function_count) { + /* The function to call is an import function */ + func_import = &wasm_module->import_functions[func_idx].u.function; + func_type = func_import->func_type; + + /* Call fast_jit_invoke_native in some cases */ + if (!func_import->func_ptr_linked /* import func hasn't been linked */ + || func_import->call_conv_wasm_c_api /* linked by wasm_c_api */ + || func_import->call_conv_raw /* registered as raw mode */ + || func_type->param_count >= 5 /* registered as normal mode, but + jit_emit_callnative only supports + maximum 6 registers now + (include exec_nev) */) { + JitReg arg_regs[3]; + + if (!pre_call(cc, func_type)) { + goto fail; + } + + /* Call fast_jit_invoke_native */ + ret = jit_cc_new_reg_I32(cc); + arg_regs[0] = cc->exec_env_reg; + arg_regs[1] = NEW_CONST(I32, func_idx); + arg_regs[2] = cc->fp_reg; + if (!jit_emit_callnative(cc, fast_jit_invoke_native, ret, arg_regs, + 3)) { + goto fail; + } + + /* Convert the return value from bool to uint32 */ + GEN_INSN(AND, ret, ret, NEW_CONST(I32, 0xFF)); + + /* Check whether there is exception thrown */ + GEN_INSN(CMP, cc->cmp_reg, ret, NEW_CONST(I32, 0)); + if (!jit_emit_exception(cc, EXCE_ALREADY_THROWN, JIT_OP_BEQ, + cc->cmp_reg, NULL)) { + goto fail; + } + + if (!post_return(cc, func_type, 0, true)) { + goto fail; + } + +#if WASM_ENABLE_THREAD_MGR != 0 + /* Insert suspend check point */ + if (!jit_check_suspend_flags(cc)) + goto fail; +#endif + + return true; + } + + /* Import function was registered as normal mode, and its argument count + is no more than 5, we directly call it */ + + signature = func_import->signature; + bh_assert(signature); + + /* Allocate memory for argvs*/ + total_size = sizeof(JitReg) * (uint64)(func_type->param_count); + if (total_size > 0) { + if (total_size >= UINT32_MAX + || !(argvs = jit_malloc((uint32)total_size))) { + goto fail; + } + } + + /* Pop function params from stack and store them into argvs */ + if (!pre_load(cc, argvs, func_type)) { + goto fail; + } + + ret = jit_cc_new_reg_I32(cc); + func_params[0] = module_inst_reg = get_module_inst_reg(jit_frame); + func_params[4] = native_addr_ptr = jit_cc_new_reg_ptr(cc); + GEN_INSN(ADD, native_addr_ptr, cc->exec_env_reg, + NEW_CONST(PTR, offsetof(WASMExecEnv, jit_cache))); + + /* Traverse each pointer/str argument, call + jit_check_app_addr_and_convert to check whether it is + in the range of linear memory and and convert it from + app offset into native address */ + for (i = 0; i < func_type->param_count; i++) { + + is_pointer_arg = false; + + if (signature[i + 1] == '*') { + /* param is a pointer */ + is_pointer_arg = true; + func_params[1] = NEW_CONST(I32, false); /* is_str = false */ + func_params[2] = argvs[i]; + if (signature[i + 2] == '~') { + /* pointer with length followed */ + func_params[3] = argvs[i + 1]; + } + else { + /* pointer with length followed */ + func_params[3] = NEW_CONST(I32, 1); + } + } + else if (signature[i + 1] == '$') { + /* param is a string */ + is_pointer_arg = true; + func_params[1] = NEW_CONST(I32, true); /* is_str = true */ + func_params[2] = argvs[i]; + func_params[3] = NEW_CONST(I32, 1); + } + + if (is_pointer_arg) { + if (!jit_emit_callnative(cc, jit_check_app_addr_and_convert, + ret, func_params, 5)) { + goto fail; + } + + /* Convert the return value from bool to uint32 */ + GEN_INSN(AND, ret, ret, NEW_CONST(I32, 0xFF)); + /* Check whether there is exception thrown */ + GEN_INSN(CMP, cc->cmp_reg, ret, NEW_CONST(I32, 0)); + if (!jit_emit_exception(cc, EXCE_ALREADY_THROWN, JIT_OP_BEQ, + cc->cmp_reg, NULL)) { + return false; + } + + /* Load native addr from pointer of native addr, + or exec_env->jit_cache */ + argvs[i] = jit_cc_new_reg_ptr(cc); + GEN_INSN(LDPTR, argvs[i], native_addr_ptr, NEW_CONST(I32, 0)); + } + } + + res = create_first_res_reg(cc, func_type); + + /* Prepare arguments of the native function */ + if (!(argvs1 = + jit_calloc(sizeof(JitReg) * (func_type->param_count + 1)))) { + goto fail; + } + argvs1[0] = cc->exec_env_reg; + for (i = 0; i < func_type->param_count; i++) { + argvs1[i + 1] = argvs[i]; + } + + /* Call the native function */ + native_func = NEW_CONST(PTR, (uintptr_t)func_import->func_ptr_linked); + if (!emit_callnative(cc, native_func, res, argvs1, + func_type->param_count + 1)) { + jit_free(argvs1); + goto fail; + } + jit_free(argvs1); + + /* Check whether there is exception thrown */ + GEN_INSN(LDI8, ret, module_inst_reg, + NEW_CONST(I32, offsetof(WASMModuleInstance, cur_exception))); + GEN_INSN(CMP, cc->cmp_reg, ret, NEW_CONST(I32, 0)); + if (!jit_emit_exception(cc, EXCE_ALREADY_THROWN, JIT_OP_BNE, + cc->cmp_reg, NULL)) { + goto fail; + } + + if (!post_return(cc, func_type, res, false)) { + goto fail; + } + } + else { + /* The function to call is a bytecode function */ + func = wasm_module + ->functions[func_idx - wasm_module->import_function_count]; + func_type = func->func_type; + + /* jitted_code = func_ptrs[func_idx - import_function_count] */ + fast_jit_func_ptrs = get_fast_jit_func_ptrs_reg(jit_frame); + jitted_code = jit_cc_new_reg_ptr(cc); + jitted_func_idx = func_idx - wasm_module->import_function_count; + GEN_INSN(LDPTR, jitted_code, fast_jit_func_ptrs, + NEW_CONST(I32, (uint32)sizeof(void *) * jitted_func_idx)); + + if (!pre_call(cc, func_type)) { + goto fail; + } + + res = create_first_res_reg(cc, func_type); + + GEN_INSN(CALLBC, res, 0, jitted_code, NEW_CONST(I32, func_idx)); + + if (!post_return(cc, func_type, res, true)) { + goto fail; + } + } + +#if WASM_ENABLE_THREAD_MGR != 0 + /* Insert suspend check point */ + if (!jit_check_suspend_flags(cc)) + goto fail; +#endif + + /* Clear part of memory regs and table regs as their values + may be changed in the function call */ + if (cc->cur_wasm_module->possible_memory_grow) + clear_memory_regs(jit_frame); + clear_table_regs(jit_frame); + + /* Ignore tail call currently */ + (void)tail_call; + + return_value = true; + +fail: + if (argvs) + jit_free(argvs); + + return return_value; +} + +static JitReg +pack_argv(JitCompContext *cc) +{ + /* reuse the stack of the next frame */ + uint32 stack_base; + JitReg argv; + + stack_base = cc->total_frame_size + offsetof(WASMInterpFrame, lp); + argv = jit_cc_new_reg_ptr(cc); + GEN_INSN(ADD, argv, cc->fp_reg, NEW_CONST(PTR, stack_base)); + if (jit_get_last_error(cc)) { + return (JitReg)0; + } + return argv; +} + +bool +jit_compile_op_call_indirect(JitCompContext *cc, uint32 type_idx, + uint32 tbl_idx) +{ + WASMModule *wasm_module = cc->cur_wasm_module; + JitBasicBlock *block_import, *block_nonimport, *func_return; + JitReg elem_idx, native_ret, argv, arg_regs[6]; + JitFrame *jit_frame = cc->jit_frame; + JitReg tbl_size, offset, offset_i32; + JitReg func_import, func_idx, tbl_elems, func_count; + JitReg func_type_indexes, func_type_idx, fast_jit_func_ptrs; + JitReg offset1_i32, offset1, func_type_idx1, res; + JitReg import_func_ptrs, jitted_code_idx, jitted_code; + WASMType *func_type; + uint32 n; + + POP_I32(elem_idx); + + /* check elem_idx */ + tbl_size = get_table_cur_size_reg(jit_frame, tbl_idx); + + GEN_INSN(CMP, cc->cmp_reg, elem_idx, tbl_size); + if (!jit_emit_exception(cc, EXCE_UNDEFINED_ELEMENT, JIT_OP_BGEU, + cc->cmp_reg, NULL)) + goto fail; + + /* check func_idx */ + if (UINTPTR_MAX == UINT64_MAX) { + offset_i32 = jit_cc_new_reg_I32(cc); + offset = jit_cc_new_reg_I64(cc); + GEN_INSN(SHL, offset_i32, elem_idx, NEW_CONST(I32, 2)); + GEN_INSN(I32TOI64, offset, offset_i32); + } + else { + offset = jit_cc_new_reg_I32(cc); + GEN_INSN(SHL, offset, elem_idx, NEW_CONST(I32, 2)); + } + func_idx = jit_cc_new_reg_I32(cc); + tbl_elems = get_table_elems_reg(jit_frame, tbl_idx); + GEN_INSN(LDI32, func_idx, tbl_elems, offset); + + GEN_INSN(CMP, cc->cmp_reg, func_idx, NEW_CONST(I32, -1)); + if (!jit_emit_exception(cc, EXCE_UNINITIALIZED_ELEMENT, JIT_OP_BEQ, + cc->cmp_reg, NULL)) + goto fail; + + func_count = NEW_CONST(I32, wasm_module->import_function_count + + wasm_module->function_count); + GEN_INSN(CMP, cc->cmp_reg, func_idx, func_count); + if (!jit_emit_exception(cc, EXCE_INVALID_FUNCTION_INDEX, JIT_OP_BGTU, + cc->cmp_reg, NULL)) + goto fail; + + /* check func_type */ + /* get func_type_idx from func_type_indexes */ + if (UINTPTR_MAX == UINT64_MAX) { + offset1_i32 = jit_cc_new_reg_I32(cc); + offset1 = jit_cc_new_reg_I64(cc); + GEN_INSN(SHL, offset1_i32, func_idx, NEW_CONST(I32, 2)); + GEN_INSN(I32TOI64, offset1, offset1_i32); + } + else { + offset1 = jit_cc_new_reg_I32(cc); + GEN_INSN(SHL, offset1, func_idx, NEW_CONST(I32, 2)); + } + + func_type_indexes = get_func_type_indexes_reg(jit_frame); + func_type_idx = jit_cc_new_reg_I32(cc); + GEN_INSN(LDI32, func_type_idx, func_type_indexes, offset1); + + type_idx = wasm_get_smallest_type_idx(wasm_module->types, + wasm_module->type_count, type_idx); + func_type_idx1 = NEW_CONST(I32, type_idx); + GEN_INSN(CMP, cc->cmp_reg, func_type_idx, func_type_idx1); + if (!jit_emit_exception(cc, EXCE_INVALID_FUNCTION_TYPE_INDEX, JIT_OP_BNE, + cc->cmp_reg, NULL)) + goto fail; + + /* pop function arguments and store it to out area of callee stack frame */ + func_type = wasm_module->types[type_idx]; + if (!pre_call(cc, func_type)) { + goto fail; + } + + /* store elem_idx and func_idx to exec_env->jit_cache */ + GEN_INSN(STI32, elem_idx, cc->exec_env_reg, + NEW_CONST(I32, offsetof(WASMExecEnv, jit_cache))); + GEN_INSN(STI32, func_idx, cc->exec_env_reg, + NEW_CONST(I32, offsetof(WASMExecEnv, jit_cache) + 4)); + +#if WASM_ENABLE_THREAD_MGR != 0 + /* Insert suspend check point */ + if (!jit_check_suspend_flags(cc)) + goto fail; +#endif + + block_import = jit_cc_new_basic_block(cc, 0); + block_nonimport = jit_cc_new_basic_block(cc, 0); + func_return = jit_cc_new_basic_block(cc, 0); + if (!block_import || !block_nonimport || !func_return) { + goto fail; + } + + /* Commit register values to locals and stacks */ + gen_commit_values(jit_frame, jit_frame->lp, jit_frame->sp); + /* Clear frame values */ + clear_values(jit_frame); + + /* jump to block_import or block_nonimport */ + GEN_INSN(CMP, cc->cmp_reg, func_idx, + NEW_CONST(I32, cc->cur_wasm_module->import_function_count)); + GEN_INSN(BLTU, cc->cmp_reg, jit_basic_block_label(block_import), + jit_basic_block_label(block_nonimport)); + + /* block_import */ + cc->cur_basic_block = block_import; + + elem_idx = jit_cc_new_reg_I32(cc); + GEN_INSN(LDI32, elem_idx, cc->exec_env_reg, + NEW_CONST(I32, offsetof(WASMExecEnv, jit_cache))); + GEN_INSN(LDI32, func_idx, cc->exec_env_reg, + NEW_CONST(I32, offsetof(WASMExecEnv, jit_cache) + 4)); + + argv = pack_argv(cc); + if (!argv) { + goto fail; + } + native_ret = jit_cc_new_reg_I32(cc); + arg_regs[0] = cc->exec_env_reg; + arg_regs[1] = NEW_CONST(I32, tbl_idx); + arg_regs[2] = elem_idx; + arg_regs[3] = NEW_CONST(I32, type_idx); + arg_regs[4] = NEW_CONST(I32, func_type->param_cell_num); + arg_regs[5] = argv; + + import_func_ptrs = get_import_func_ptrs_reg(jit_frame); + func_import = jit_cc_new_reg_ptr(cc); + if (UINTPTR_MAX == UINT64_MAX) { + JitReg func_import_offset = jit_cc_new_reg_I32(cc); + JitReg func_import_offset_i64 = jit_cc_new_reg_I64(cc); + GEN_INSN(SHL, func_import_offset, func_idx, NEW_CONST(I32, 3)); + GEN_INSN(I32TOI64, func_import_offset_i64, func_import_offset); + GEN_INSN(LDPTR, func_import, import_func_ptrs, func_import_offset_i64); + } + else { + JitReg func_import_offset = jit_cc_new_reg_I32(cc); + GEN_INSN(SHL, func_import_offset, func_idx, NEW_CONST(I32, 2)); + GEN_INSN(LDPTR, func_import, import_func_ptrs, func_import_offset); + } + if (!jit_emit_callnative(cc, fast_jit_call_indirect, native_ret, arg_regs, + 6)) { + goto fail; + } + + /* Convert bool to uint32 */ + GEN_INSN(AND, native_ret, native_ret, NEW_CONST(I32, 0xFF)); + + /* Check whether there is exception thrown */ + GEN_INSN(CMP, cc->cmp_reg, native_ret, NEW_CONST(I32, 0)); + if (!jit_emit_exception(cc, EXCE_ALREADY_THROWN, JIT_OP_BEQ, cc->cmp_reg, + NULL)) { + return false; + } + + /* Store res into current frame, so that post_return in + block func_return can get the value */ + n = cc->jit_frame->sp - cc->jit_frame->lp; + if (func_type->result_count > 0) { + switch (func_type->types[func_type->param_count]) { + case VALUE_TYPE_I32: +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_EXTERNREF: + case VALUE_TYPE_FUNCREF: +#endif + res = jit_cc_new_reg_I32(cc); + GEN_INSN(LDI32, res, argv, NEW_CONST(I32, 0)); + GEN_INSN(STI32, res, cc->fp_reg, + NEW_CONST(I32, offset_of_local(n))); + break; + case VALUE_TYPE_I64: + res = jit_cc_new_reg_I64(cc); + GEN_INSN(LDI64, res, argv, NEW_CONST(I32, 0)); + GEN_INSN(STI64, res, cc->fp_reg, + NEW_CONST(I32, offset_of_local(n))); + break; + case VALUE_TYPE_F32: + res = jit_cc_new_reg_F32(cc); + GEN_INSN(LDF32, res, argv, NEW_CONST(I32, 0)); + GEN_INSN(STF32, res, cc->fp_reg, + NEW_CONST(I32, offset_of_local(n))); + break; + case VALUE_TYPE_F64: + res = jit_cc_new_reg_F64(cc); + GEN_INSN(LDF64, res, argv, NEW_CONST(I32, 0)); + GEN_INSN(STF64, res, cc->fp_reg, + NEW_CONST(I32, offset_of_local(n))); + break; + default: + bh_assert(0); + goto fail; + } + } + + gen_commit_values(jit_frame, jit_frame->lp, jit_frame->sp); + clear_values(jit_frame); + GEN_INSN(JMP, jit_basic_block_label(func_return)); + + /* basic_block non_import */ + cc->cur_basic_block = block_nonimport; + + GEN_INSN(LDI32, func_idx, cc->exec_env_reg, + NEW_CONST(I32, offsetof(WASMExecEnv, jit_cache) + 4)); + + /* get jitted_code */ + fast_jit_func_ptrs = get_fast_jit_func_ptrs_reg(jit_frame); + jitted_code_idx = jit_cc_new_reg_I32(cc); + jitted_code = jit_cc_new_reg_ptr(cc); + GEN_INSN(SUB, jitted_code_idx, func_idx, + NEW_CONST(I32, cc->cur_wasm_module->import_function_count)); + if (UINTPTR_MAX == UINT64_MAX) { + JitReg jitted_code_offset = jit_cc_new_reg_I32(cc); + JitReg jitted_code_offset_64 = jit_cc_new_reg_I64(cc); + GEN_INSN(SHL, jitted_code_offset, jitted_code_idx, NEW_CONST(I32, 3)); + GEN_INSN(I32TOI64, jitted_code_offset_64, jitted_code_offset); + GEN_INSN(LDPTR, jitted_code, fast_jit_func_ptrs, jitted_code_offset_64); + } + else { + JitReg jitted_code_offset = jit_cc_new_reg_I32(cc); + GEN_INSN(SHL, jitted_code_offset, jitted_code_idx, NEW_CONST(I32, 2)); + GEN_INSN(LDPTR, jitted_code, fast_jit_func_ptrs, jitted_code_offset); + } + + res = 0; + if (func_type->result_count > 0) { + switch (func_type->types[func_type->param_count]) { + case VALUE_TYPE_I32: +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_EXTERNREF: + case VALUE_TYPE_FUNCREF: +#endif + res = jit_cc_new_reg_I32(cc); + break; + case VALUE_TYPE_I64: + res = jit_cc_new_reg_I64(cc); + break; + case VALUE_TYPE_F32: + res = jit_cc_new_reg_F32(cc); + break; + case VALUE_TYPE_F64: + res = jit_cc_new_reg_F64(cc); + break; + default: + bh_assert(0); + goto fail; + } + } + GEN_INSN(CALLBC, res, 0, jitted_code, func_idx); + /* Store res into current frame, so that post_return in + block func_return can get the value */ + n = cc->jit_frame->sp - cc->jit_frame->lp; + if (func_type->result_count > 0) { + switch (func_type->types[func_type->param_count]) { + case VALUE_TYPE_I32: +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_EXTERNREF: + case VALUE_TYPE_FUNCREF: +#endif + GEN_INSN(STI32, res, cc->fp_reg, + NEW_CONST(I32, offset_of_local(n))); + break; + case VALUE_TYPE_I64: + GEN_INSN(STI64, res, cc->fp_reg, + NEW_CONST(I32, offset_of_local(n))); + break; + case VALUE_TYPE_F32: + GEN_INSN(STF32, res, cc->fp_reg, + NEW_CONST(I32, offset_of_local(n))); + break; + case VALUE_TYPE_F64: + GEN_INSN(STF64, res, cc->fp_reg, + NEW_CONST(I32, offset_of_local(n))); + break; + default: + bh_assert(0); + goto fail; + } + } + /* commit and clear jit frame, then jump to block func_ret */ + gen_commit_values(jit_frame, jit_frame->lp, jit_frame->sp); + clear_values(jit_frame); + GEN_INSN(JMP, jit_basic_block_label(func_return)); + + /* translate block func_return */ + cc->cur_basic_block = func_return; + if (!post_return(cc, func_type, 0, true)) { + goto fail; + } + +#if WASM_ENABLE_THREAD_MGR != 0 + /* Insert suspend check point */ + if (!jit_check_suspend_flags(cc)) + goto fail; +#endif + + /* Clear part of memory regs and table regs as their values + may be changed in the function call */ + if (cc->cur_wasm_module->possible_memory_grow) + clear_memory_regs(cc->jit_frame); + clear_table_regs(cc->jit_frame); + return true; +fail: + return false; +} + +#if WASM_ENABLE_REF_TYPES != 0 +bool +jit_compile_op_ref_null(JitCompContext *cc, uint32 ref_type) +{ + PUSH_I32(NEW_CONST(I32, NULL_REF)); + (void)ref_type; + return true; +fail: + return false; +} + +bool +jit_compile_op_ref_is_null(JitCompContext *cc) +{ + JitReg ref, res; + + POP_I32(ref); + + GEN_INSN(CMP, cc->cmp_reg, ref, NEW_CONST(I32, NULL_REF)); + res = jit_cc_new_reg_I32(cc); + GEN_INSN(SELECTEQ, res, cc->cmp_reg, NEW_CONST(I32, 1), NEW_CONST(I32, 0)); + PUSH_I32(res); + + return true; +fail: + return false; +} + +bool +jit_compile_op_ref_func(JitCompContext *cc, uint32 func_idx) +{ + PUSH_I32(NEW_CONST(I32, func_idx)); + return true; +fail: + return false; +} +#endif + +#if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64) +static bool +emit_callnative(JitCompContext *cc, JitReg native_func_reg, JitReg res, + JitReg *params, uint32 param_count) +{ + JitInsn *insn; + char *i64_arg_names[] = { "rdi", "rsi", "rdx", "rcx", "r8", "r9" }; + char *f32_arg_names[] = { "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" }; + char *f64_arg_names[] = { "xmm0_f64", "xmm1_f64", "xmm2_f64", + "xmm3_f64", "xmm4_f64", "xmm5_f64" }; + JitReg i64_arg_regs[6], f32_arg_regs[6], f64_arg_regs[6], res_reg = 0; + JitReg eax_hreg = jit_codegen_get_hreg_by_name("eax"); + JitReg xmm0_hreg = jit_codegen_get_hreg_by_name("xmm0"); + uint32 i, i64_reg_idx, float_reg_idx; + + bh_assert(param_count <= 6); + + for (i = 0; i < 6; i++) { + i64_arg_regs[i] = jit_codegen_get_hreg_by_name(i64_arg_names[i]); + f32_arg_regs[i] = jit_codegen_get_hreg_by_name(f32_arg_names[i]); + f64_arg_regs[i] = jit_codegen_get_hreg_by_name(f64_arg_names[i]); + } + + i64_reg_idx = float_reg_idx = 0; + for (i = 0; i < param_count; i++) { + switch (jit_reg_kind(params[i])) { + case JIT_REG_KIND_I32: + GEN_INSN(I32TOI64, i64_arg_regs[i64_reg_idx++], params[i]); + break; + case JIT_REG_KIND_I64: + GEN_INSN(MOV, i64_arg_regs[i64_reg_idx++], params[i]); + break; + case JIT_REG_KIND_F32: + GEN_INSN(MOV, f32_arg_regs[float_reg_idx++], params[i]); + break; + case JIT_REG_KIND_F64: + GEN_INSN(MOV, f64_arg_regs[float_reg_idx++], params[i]); + break; + default: + bh_assert(0); + return false; + } + } + + if (res) { + switch (jit_reg_kind(res)) { + case JIT_REG_KIND_I32: + res_reg = eax_hreg; + break; + case JIT_REG_KIND_I64: + res_reg = res; + break; + case JIT_REG_KIND_F32: + res_reg = xmm0_hreg; + break; + case JIT_REG_KIND_F64: + res_reg = res; + break; + default: + bh_assert(0); + return false; + } + } + + insn = GEN_INSN(CALLNATIVE, res_reg, native_func_reg, param_count); + if (!insn) { + return false; + } + + i64_reg_idx = float_reg_idx = 0; + for (i = 0; i < param_count; i++) { + switch (jit_reg_kind(params[i])) { + case JIT_REG_KIND_I32: + case JIT_REG_KIND_I64: + *(jit_insn_opndv(insn, i + 2)) = i64_arg_regs[i64_reg_idx++]; + break; + case JIT_REG_KIND_F32: + *(jit_insn_opndv(insn, i + 2)) = f32_arg_regs[float_reg_idx++]; + break; + case JIT_REG_KIND_F64: + *(jit_insn_opndv(insn, i + 2)) = f64_arg_regs[float_reg_idx++]; + break; + default: + bh_assert(0); + return false; + } + } + + if (res && res != res_reg) { + GEN_INSN(MOV, res, res_reg); + } + + return true; +} +#else +static bool +emit_callnative(JitCompContext *cc, JitRef native_func_reg, JitReg res, + JitReg *params, uint32 param_count) +{ + JitInsn *insn; + uint32 i; + + bh_assert(param_count <= 6); + + insn = GEN_INSN(CALLNATIVE, res, native_func_reg, param_count); + if (!insn) + return false; + + for (i = 0; i < param_count; i++) { + *(jit_insn_opndv(insn, i + 2)) = params[i]; + } + return true; +} +#endif + +bool +jit_emit_callnative(JitCompContext *cc, void *native_func, JitReg res, + JitReg *params, uint32 param_count) +{ + return emit_callnative(cc, NEW_CONST(PTR, (uintptr_t)native_func), res, + params, param_count); +} diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/fe/jit_emit_function.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/fe/jit_emit_function.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/fe/jit_emit_function.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/fe/jit_emit_function.h diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/fe/jit_emit_memory.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/fe/jit_emit_memory.c new file mode 100644 index 00000000000..9635d4e57e2 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/fe/jit_emit_memory.c @@ -0,0 +1,1200 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "jit_emit_memory.h" +#include "jit_emit_exception.h" +#include "jit_emit_function.h" +#include "../jit_frontend.h" +#include "../jit_codegen.h" +#include "../../interpreter/wasm_runtime.h" +#include "jit_emit_control.h" + +#ifndef OS_ENABLE_HW_BOUND_CHECK +static JitReg +get_memory_boundary(JitCompContext *cc, uint32 mem_idx, uint32 bytes) +{ + JitReg memory_boundary; + + switch (bytes) { + case 1: + { + memory_boundary = + get_mem_bound_check_1byte_reg(cc->jit_frame, mem_idx); + break; + } + case 2: + { + memory_boundary = + get_mem_bound_check_2bytes_reg(cc->jit_frame, mem_idx); + break; + } + case 4: + { + memory_boundary = + get_mem_bound_check_4bytes_reg(cc->jit_frame, mem_idx); + break; + } + case 8: + { + memory_boundary = + get_mem_bound_check_8bytes_reg(cc->jit_frame, mem_idx); + break; + } + case 16: + { + memory_boundary = + get_mem_bound_check_16bytes_reg(cc->jit_frame, mem_idx); + break; + } + default: + { + bh_assert(0); + goto fail; + } + } + + return memory_boundary; +fail: + return 0; +} +#endif + +#if WASM_ENABLE_SHARED_MEMORY != 0 +static void +set_load_or_store_atomic(JitInsn *load_or_store_inst) +{ + load_or_store_inst->flags_u8 |= 0x1; +} +#endif + +#if UINTPTR_MAX == UINT64_MAX +static JitReg +check_and_seek_on_64bit_platform(JitCompContext *cc, JitReg addr, JitReg offset, + JitReg memory_boundary) +{ + JitReg long_addr, offset1; + + /* long_addr = (int64_t)addr */ + long_addr = jit_cc_new_reg_I64(cc); + GEN_INSN(U32TOI64, long_addr, addr); + + /* offset1 = offset + long_addr */ + offset1 = jit_cc_new_reg_I64(cc); + GEN_INSN(ADD, offset1, offset, long_addr); + +#ifndef OS_ENABLE_HW_BOUND_CHECK + /* if (offset1 > memory_boundary) goto EXCEPTION */ + GEN_INSN(CMP, cc->cmp_reg, offset1, memory_boundary); + if (!jit_emit_exception(cc, EXCE_OUT_OF_BOUNDS_MEMORY_ACCESS, JIT_OP_BGTU, + cc->cmp_reg, NULL)) { + goto fail; + } +#endif + + return offset1; +#ifndef OS_ENABLE_HW_BOUND_CHECK +fail: + return 0; +#endif +} +#else +static JitReg +check_and_seek_on_32bit_platform(JitCompContext *cc, JitReg addr, JitReg offset, + JitReg memory_boundary) +{ + JitReg offset1; + + /* offset1 = offset + addr */ + offset1 = jit_cc_new_reg_I32(cc); + GEN_INSN(ADD, offset1, offset, addr); + + /* if (offset1 < addr) goto EXCEPTION */ + GEN_INSN(CMP, cc->cmp_reg, offset1, addr); + if (!jit_emit_exception(cc, EXCE_OUT_OF_BOUNDS_MEMORY_ACCESS, JIT_OP_BLTU, + cc->cmp_reg, NULL)) { + goto fail; + } + +#ifndef OS_ENABLE_HW_BOUND_CHECK + /* if (offset1 > memory_boundary) goto EXCEPTION */ + GEN_INSN(CMP, cc->cmp_reg, offset1, memory_boundary); + if (!jit_emit_exception(cc, EXCE_OUT_OF_BOUNDS_MEMORY_ACCESS, JIT_OP_BGTU, + cc->cmp_reg, NULL)) { + goto fail; + } +#endif + + return offset1; +fail: + return 0; +} +#endif + +static JitReg +check_and_seek(JitCompContext *cc, JitReg addr, uint32 offset, uint32 bytes) +{ + JitReg memory_boundary = 0, offset1; +#ifndef OS_ENABLE_HW_BOUND_CHECK + /* the default memory */ + uint32 mem_idx = 0; +#endif + +#ifndef OS_ENABLE_HW_BOUND_CHECK + /* ---------- check ---------- */ + /* 1. shortcut if the memory size is 0 */ + if (cc->cur_wasm_module->memories != NULL + && 0 == cc->cur_wasm_module->memories[mem_idx].init_page_count) { + JitReg module_inst, cur_page_count; + uint32 cur_page_count_offset = + (uint32)offsetof(WASMModuleInstance, global_table_data.bytes) + + (uint32)offsetof(WASMMemoryInstance, cur_page_count); + + /* if (cur_mem_page_count == 0) goto EXCEPTION */ + module_inst = get_module_inst_reg(cc->jit_frame); + cur_page_count = jit_cc_new_reg_I32(cc); + GEN_INSN(LDI32, cur_page_count, module_inst, + NEW_CONST(I32, cur_page_count_offset)); + GEN_INSN(CMP, cc->cmp_reg, cur_page_count, NEW_CONST(I32, 0)); + if (!jit_emit_exception(cc, EXCE_OUT_OF_BOUNDS_MEMORY_ACCESS, + JIT_OP_BEQ, cc->cmp_reg, NULL)) { + goto fail; + } + } + + /* 2. a complete boundary check */ + memory_boundary = get_memory_boundary(cc, mem_idx, bytes); + if (!memory_boundary) + goto fail; +#endif + +#if UINTPTR_MAX == UINT64_MAX + offset1 = check_and_seek_on_64bit_platform(cc, addr, NEW_CONST(I64, offset), + memory_boundary); + if (!offset1) + goto fail; +#else + offset1 = check_and_seek_on_32bit_platform(cc, addr, NEW_CONST(I32, offset), + memory_boundary); + if (!offset1) + goto fail; +#endif + + return offset1; +fail: + return 0; +} + +#if UINTPTR_MAX == UINT64_MAX +#define CHECK_ALIGNMENT(offset1) \ + do { \ + JitReg align_mask = NEW_CONST(I64, ((uint64)1 << align) - 1); \ + JitReg AND_res = jit_cc_new_reg_I64(cc); \ + GEN_INSN(AND, AND_res, offset1, align_mask); \ + GEN_INSN(CMP, cc->cmp_reg, AND_res, NEW_CONST(I64, 0)); \ + if (!jit_emit_exception(cc, EXCE_UNALIGNED_ATOMIC, JIT_OP_BNE, \ + cc->cmp_reg, NULL)) \ + goto fail; \ + } while (0) +#else +#define CHECK_ALIGNMENT(offset1) \ + do { \ + JitReg align_mask = NEW_CONST(I32, (1 << align) - 1); \ + JitReg AND_res = jit_cc_new_reg_I32(cc); \ + GEN_INSN(AND, AND_res, offset1, align_mask); \ + GEN_INSN(CMP, cc->cmp_reg, AND_res, NEW_CONST(I32, 0)); \ + if (!jit_emit_exception(cc, EXCE_UNALIGNED_ATOMIC, JIT_OP_BNE, \ + cc->cmp_reg, NULL)) \ + goto fail; \ + } while (0) +#endif + +bool +jit_compile_op_i32_load(JitCompContext *cc, uint32 align, uint32 offset, + uint32 bytes, bool sign, bool atomic) +{ + JitReg addr, offset1, value, memory_data; + JitInsn *load_insn = NULL; + + POP_I32(addr); + + offset1 = check_and_seek(cc, addr, offset, bytes); + if (!offset1) { + goto fail; + } +#if WASM_ENABLE_SHARED_MEMORY != 0 + if (atomic) { + CHECK_ALIGNMENT(offset1); + } +#endif + + memory_data = get_memory_data_reg(cc->jit_frame, 0); + + value = jit_cc_new_reg_I32(cc); + switch (bytes) { + case 1: + { + if (sign) { + load_insn = GEN_INSN(LDI8, value, memory_data, offset1); + } + else { + load_insn = GEN_INSN(LDU8, value, memory_data, offset1); + } + break; + } + case 2: + { + if (sign) { + load_insn = GEN_INSN(LDI16, value, memory_data, offset1); + } + else { + load_insn = GEN_INSN(LDU16, value, memory_data, offset1); + } + break; + } + case 4: + { + if (sign) { + load_insn = GEN_INSN(LDI32, value, memory_data, offset1); + } + else { + load_insn = GEN_INSN(LDU32, value, memory_data, offset1); + } + break; + } + default: + { + bh_assert(0); + goto fail; + } + } + +#if WASM_ENABLE_SHARED_MEMORY != 0 + if (atomic && load_insn) + set_load_or_store_atomic(load_insn); +#else + (void)load_insn; +#endif + + PUSH_I32(value); + return true; +fail: + return false; +} + +bool +jit_compile_op_i64_load(JitCompContext *cc, uint32 align, uint32 offset, + uint32 bytes, bool sign, bool atomic) +{ + JitReg addr, offset1, value, memory_data; + JitInsn *load_insn = NULL; + + POP_I32(addr); + + offset1 = check_and_seek(cc, addr, offset, bytes); + if (!offset1) { + goto fail; + } +#if WASM_ENABLE_SHARED_MEMORY != 0 + if (atomic) { + CHECK_ALIGNMENT(offset1); + } +#endif + + memory_data = get_memory_data_reg(cc->jit_frame, 0); + + value = jit_cc_new_reg_I64(cc); + switch (bytes) { + case 1: + { + if (sign) { + load_insn = GEN_INSN(LDI8, value, memory_data, offset1); + } + else { + load_insn = GEN_INSN(LDU8, value, memory_data, offset1); + } + break; + } + case 2: + { + if (sign) { + load_insn = GEN_INSN(LDI16, value, memory_data, offset1); + } + else { + load_insn = GEN_INSN(LDU16, value, memory_data, offset1); + } + break; + } + case 4: + { + if (sign) { + load_insn = GEN_INSN(LDI32, value, memory_data, offset1); + } + else { + load_insn = GEN_INSN(LDU32, value, memory_data, offset1); + } + break; + } + case 8: + { + if (sign) { + load_insn = GEN_INSN(LDI64, value, memory_data, offset1); + } + else { + load_insn = GEN_INSN(LDU64, value, memory_data, offset1); + } + break; + } + default: + { + bh_assert(0); + goto fail; + } + } + +#if WASM_ENABLE_SHARED_MEMORY != 0 + if (atomic && load_insn) + set_load_or_store_atomic(load_insn); +#else + (void)load_insn; +#endif + + PUSH_I64(value); + return true; +fail: + return false; +} + +bool +jit_compile_op_f32_load(JitCompContext *cc, uint32 align, uint32 offset) +{ + JitReg addr, offset1, value, memory_data; + + POP_I32(addr); + + offset1 = check_and_seek(cc, addr, offset, 4); + if (!offset1) { + goto fail; + } + + memory_data = get_memory_data_reg(cc->jit_frame, 0); + + value = jit_cc_new_reg_F32(cc); + GEN_INSN(LDF32, value, memory_data, offset1); + + PUSH_F32(value); + return true; +fail: + return false; +} + +bool +jit_compile_op_f64_load(JitCompContext *cc, uint32 align, uint32 offset) +{ + JitReg addr, offset1, value, memory_data; + + POP_I32(addr); + + offset1 = check_and_seek(cc, addr, offset, 8); + if (!offset1) { + goto fail; + } + + memory_data = get_memory_data_reg(cc->jit_frame, 0); + + value = jit_cc_new_reg_F64(cc); + GEN_INSN(LDF64, value, memory_data, offset1); + + PUSH_F64(value); + return true; +fail: + return false; +} + +bool +jit_compile_op_i32_store(JitCompContext *cc, uint32 align, uint32 offset, + uint32 bytes, bool atomic) +{ + JitReg value, addr, offset1, memory_data; + JitInsn *store_insn = NULL; + + POP_I32(value); + POP_I32(addr); + + offset1 = check_and_seek(cc, addr, offset, bytes); + if (!offset1) { + goto fail; + } +#if WASM_ENABLE_SHARED_MEMORY != 0 + if (atomic) { + CHECK_ALIGNMENT(offset1); + } +#endif + + memory_data = get_memory_data_reg(cc->jit_frame, 0); + + switch (bytes) { + case 1: + { + store_insn = GEN_INSN(STI8, value, memory_data, offset1); + break; + } + case 2: + { + store_insn = GEN_INSN(STI16, value, memory_data, offset1); + break; + } + case 4: + { + store_insn = GEN_INSN(STI32, value, memory_data, offset1); + break; + } + default: + { + bh_assert(0); + goto fail; + } + } +#if WASM_ENABLE_SHARED_MEMORY != 0 + if (atomic && store_insn) + set_load_or_store_atomic(store_insn); +#else + (void)store_insn; +#endif + + return true; +fail: + return false; +} + +bool +jit_compile_op_i64_store(JitCompContext *cc, uint32 align, uint32 offset, + uint32 bytes, bool atomic) +{ + JitReg value, addr, offset1, memory_data; + JitInsn *store_insn = NULL; + + POP_I64(value); + POP_I32(addr); + + offset1 = check_and_seek(cc, addr, offset, bytes); + if (!offset1) { + goto fail; + } +#if WASM_ENABLE_SHARED_MEMORY != 0 + if (atomic) { + CHECK_ALIGNMENT(offset1); + } +#endif + + if (jit_reg_is_const(value) && bytes < 8) { + value = NEW_CONST(I32, (int32)jit_cc_get_const_I64(cc, value)); + } + + memory_data = get_memory_data_reg(cc->jit_frame, 0); + + switch (bytes) { + case 1: + { + store_insn = GEN_INSN(STI8, value, memory_data, offset1); + break; + } + case 2: + { + store_insn = GEN_INSN(STI16, value, memory_data, offset1); + break; + } + case 4: + { + store_insn = GEN_INSN(STI32, value, memory_data, offset1); + break; + } + case 8: + { + store_insn = GEN_INSN(STI64, value, memory_data, offset1); + break; + } + default: + { + bh_assert(0); + goto fail; + } + } +#if WASM_ENABLE_SHARED_MEMORY != 0 + if (atomic && store_insn) + set_load_or_store_atomic(store_insn); +#else + (void)store_insn; +#endif + + return true; +fail: + return false; +} + +bool +jit_compile_op_f32_store(JitCompContext *cc, uint32 align, uint32 offset) +{ + JitReg value, addr, offset1, memory_data; + + POP_F32(value); + POP_I32(addr); + + offset1 = check_and_seek(cc, addr, offset, 4); + if (!offset1) { + goto fail; + } + + memory_data = get_memory_data_reg(cc->jit_frame, 0); + + GEN_INSN(STF32, value, memory_data, offset1); + + return true; +fail: + return false; +} + +bool +jit_compile_op_f64_store(JitCompContext *cc, uint32 align, uint32 offset) +{ + JitReg value, addr, offset1, memory_data; + + POP_F64(value); + POP_I32(addr); + + offset1 = check_and_seek(cc, addr, offset, 8); + if (!offset1) { + goto fail; + } + + memory_data = get_memory_data_reg(cc->jit_frame, 0); + + GEN_INSN(STF64, value, memory_data, offset1); + + return true; +fail: + return false; +} + +bool +jit_compile_op_memory_size(JitCompContext *cc, uint32 mem_idx) +{ + JitReg module_inst, cur_page_count; + uint32 cur_page_count_offset = + (uint32)offsetof(WASMModuleInstance, global_table_data.bytes) + + (uint32)offsetof(WASMMemoryInstance, cur_page_count); + + module_inst = get_module_inst_reg(cc->jit_frame); + cur_page_count = jit_cc_new_reg_I32(cc); + GEN_INSN(LDI32, cur_page_count, module_inst, + NEW_CONST(I32, cur_page_count_offset)); + + PUSH_I32(cur_page_count); + + return true; +fail: + return false; +} + +bool +jit_compile_op_memory_grow(JitCompContext *cc, uint32 mem_idx) +{ + JitReg module_inst, grow_res, res; + JitReg prev_page_count, inc_page_count, args[2]; + + /* Get current page count */ + uint32 cur_page_count_offset = + (uint32)offsetof(WASMModuleInstance, global_table_data.bytes) + + (uint32)offsetof(WASMMemoryInstance, cur_page_count); + + module_inst = get_module_inst_reg(cc->jit_frame); + prev_page_count = jit_cc_new_reg_I32(cc); + GEN_INSN(LDI32, prev_page_count, module_inst, + NEW_CONST(I32, cur_page_count_offset)); + + /* Call wasm_enlarge_memory */ + POP_I32(inc_page_count); + + grow_res = jit_cc_new_reg_I32(cc); + args[0] = get_module_inst_reg(cc->jit_frame); + args[1] = inc_page_count; + + if (!jit_emit_callnative(cc, wasm_enlarge_memory, grow_res, args, 2)) { + goto fail; + } + /* Convert bool to uint32 */ + GEN_INSN(AND, grow_res, grow_res, NEW_CONST(I32, 0xFF)); + + /* return different values according to memory.grow result */ + res = jit_cc_new_reg_I32(cc); + GEN_INSN(CMP, cc->cmp_reg, grow_res, NEW_CONST(I32, 0)); + GEN_INSN(SELECTNE, res, cc->cmp_reg, prev_page_count, + NEW_CONST(I32, (int32)-1)); + PUSH_I32(res); + + /* Ensure a refresh in next get memory related registers */ + clear_memory_regs(cc->jit_frame); + + return true; +fail: + return false; +} + +#if WASM_ENABLE_BULK_MEMORY != 0 +static int +wasm_init_memory(WASMModuleInstance *inst, uint32 mem_idx, uint32 seg_idx, + uint32 len, uint32 mem_offset, uint32 data_offset) +{ + WASMMemoryInstance *mem_inst; + WASMDataSeg *data_segment; + uint32 mem_size; + uint8 *mem_addr, *data_addr; + + /* if d + n > the length of mem.data */ + mem_inst = inst->memories[mem_idx]; + mem_size = mem_inst->cur_page_count * mem_inst->num_bytes_per_page; + if (mem_size < mem_offset || mem_size - mem_offset < len) + goto out_of_bounds; + + /* if s + n > the length of data.data */ + bh_assert(seg_idx < inst->module->data_seg_count); + data_segment = inst->module->data_segments[seg_idx]; + if (data_segment->data_length < data_offset + || data_segment->data_length - data_offset < len) + goto out_of_bounds; + + mem_addr = mem_inst->memory_data + mem_offset; + data_addr = data_segment->data + data_offset; + bh_memcpy_s(mem_addr, mem_size - mem_offset, data_addr, len); + + return 0; +out_of_bounds: + wasm_set_exception(inst, "out of bounds memory access"); + return -1; +} + +bool +jit_compile_op_memory_init(JitCompContext *cc, uint32 mem_idx, uint32 seg_idx) +{ + JitReg len, mem_offset, data_offset, res; + JitReg args[6] = { 0 }; + + POP_I32(len); + POP_I32(data_offset); + POP_I32(mem_offset); + + res = jit_cc_new_reg_I32(cc); + args[0] = get_module_inst_reg(cc->jit_frame); + args[1] = NEW_CONST(I32, mem_idx); + args[2] = NEW_CONST(I32, seg_idx); + args[3] = len; + args[4] = mem_offset; + args[5] = data_offset; + + if (!jit_emit_callnative(cc, wasm_init_memory, res, args, + sizeof(args) / sizeof(args[0]))) + goto fail; + + GEN_INSN(CMP, cc->cmp_reg, res, NEW_CONST(I32, 0)); + if (!jit_emit_exception(cc, EXCE_ALREADY_THROWN, JIT_OP_BLTS, cc->cmp_reg, + NULL)) + goto fail; + + return true; +fail: + return false; +} + +bool +jit_compile_op_data_drop(JitCompContext *cc, uint32 seg_idx) +{ + JitReg module = get_module_reg(cc->jit_frame); + JitReg data_segments = jit_cc_new_reg_ptr(cc); + JitReg data_segment = jit_cc_new_reg_ptr(cc); + + GEN_INSN(LDPTR, data_segments, module, + NEW_CONST(I32, offsetof(WASMModule, data_segments))); + GEN_INSN(LDPTR, data_segment, data_segments, + NEW_CONST(I32, seg_idx * sizeof(WASMDataSeg *))); + GEN_INSN(STI32, NEW_CONST(I32, 0), data_segment, + NEW_CONST(I32, offsetof(WASMDataSeg, data_length))); + + return true; +} + +static int +wasm_copy_memory(WASMModuleInstance *inst, uint32 src_mem_idx, + uint32 dst_mem_idx, uint32 len, uint32 src_offset, + uint32 dst_offset) +{ + WASMMemoryInstance *src_mem, *dst_mem; + uint32 src_mem_size, dst_mem_size; + uint8 *src_addr, *dst_addr; + + src_mem = inst->memories[src_mem_idx]; + dst_mem = inst->memories[dst_mem_idx]; + src_mem_size = src_mem->cur_page_count * src_mem->num_bytes_per_page; + dst_mem_size = dst_mem->cur_page_count * dst_mem->num_bytes_per_page; + + /* if s + n > the length of mem.data */ + if (src_mem_size < src_offset || src_mem_size - src_offset < len) + goto out_of_bounds; + + /* if d + n > the length of mem.data */ + if (dst_mem_size < dst_offset || dst_mem_size - dst_offset < len) + goto out_of_bounds; + + src_addr = src_mem->memory_data + src_offset; + dst_addr = dst_mem->memory_data + dst_offset; + /* allowing the destination and source to overlap */ + bh_memmove_s(dst_addr, dst_mem_size - dst_offset, src_addr, len); + + return 0; +out_of_bounds: + wasm_set_exception(inst, "out of bounds memory access"); + return -1; +} + +bool +jit_compile_op_memory_copy(JitCompContext *cc, uint32 src_mem_idx, + uint32 dst_mem_idx) +{ + JitReg len, src, dst, res; + JitReg args[6] = { 0 }; + + POP_I32(len); + POP_I32(src); + POP_I32(dst); + + res = jit_cc_new_reg_I32(cc); + args[0] = get_module_inst_reg(cc->jit_frame); + args[1] = NEW_CONST(I32, src_mem_idx); + args[2] = NEW_CONST(I32, dst_mem_idx); + args[3] = len; + args[4] = src; + args[5] = dst; + + if (!jit_emit_callnative(cc, wasm_copy_memory, res, args, + sizeof(args) / sizeof(args[0]))) + goto fail; + + GEN_INSN(CMP, cc->cmp_reg, res, NEW_CONST(I32, 0)); + if (!jit_emit_exception(cc, EXCE_ALREADY_THROWN, JIT_OP_BLTS, cc->cmp_reg, + NULL)) + goto fail; + + return true; +fail: + return false; +} + +static int +wasm_fill_memory(WASMModuleInstance *inst, uint32 mem_idx, uint32 len, + uint32 val, uint32 dst) +{ + WASMMemoryInstance *mem_inst; + uint32 mem_size; + uint8 *dst_addr; + + mem_inst = inst->memories[mem_idx]; + mem_size = mem_inst->cur_page_count * mem_inst->num_bytes_per_page; + + if (mem_size < dst || mem_size - dst < len) + goto out_of_bounds; + + dst_addr = mem_inst->memory_data + dst; + memset(dst_addr, val, len); + + return 0; +out_of_bounds: + wasm_set_exception(inst, "out of bounds memory access"); + return -1; +} + +bool +jit_compile_op_memory_fill(JitCompContext *cc, uint32 mem_idx) +{ + JitReg res, len, val, dst; + JitReg args[5] = { 0 }; + + POP_I32(len); + POP_I32(val); + POP_I32(dst); + + res = jit_cc_new_reg_I32(cc); + args[0] = get_module_inst_reg(cc->jit_frame); + args[1] = NEW_CONST(I32, mem_idx); + args[2] = len; + args[3] = val; + args[4] = dst; + + if (!jit_emit_callnative(cc, wasm_fill_memory, res, args, + sizeof(args) / sizeof(args[0]))) + goto fail; + + GEN_INSN(CMP, cc->cmp_reg, res, NEW_CONST(I32, 0)); + if (!jit_emit_exception(cc, EXCE_ALREADY_THROWN, JIT_OP_BLTS, cc->cmp_reg, + NULL)) + goto fail; + + return true; +fail: + return false; +} +#endif + +#if WASM_ENABLE_SHARED_MEMORY != 0 +#define GEN_AT_RMW_INSN(op, op_type, bytes, result, value, memory_data, \ + offset1) \ + do { \ + switch (bytes) { \ + case 1: \ + { \ + insn = GEN_INSN(AT_##op##U8, result, value, memory_data, \ + offset1); \ + break; \ + } \ + case 2: \ + { \ + insn = GEN_INSN(AT_##op##U16, result, value, memory_data, \ + offset1); \ + break; \ + } \ + case 4: \ + { \ + if (op_type == VALUE_TYPE_I32) \ + insn = GEN_INSN(AT_##op##I32, result, value, memory_data, \ + offset1); \ + else \ + insn = GEN_INSN(AT_##op##U32, result, value, memory_data, \ + offset1); \ + break; \ + } \ + case 8: \ + { \ + insn = GEN_INSN(AT_##op##I64, result, value, memory_data, \ + offset1); \ + break; \ + } \ + default: \ + { \ + bh_assert(0); \ + goto fail; \ + } \ + } \ + } while (0) + +bool +jit_compile_op_atomic_rmw(JitCompContext *cc, uint8 atomic_op, uint8 op_type, + uint32 align, uint32 offset, uint32 bytes) +{ + JitReg addr, offset1, memory_data, value, result, eax_hreg, rax_hreg, + ebx_hreg, rbx_hreg; + JitInsn *insn = NULL; + bool is_i32 = op_type == VALUE_TYPE_I32; + bool is_logical_op = atomic_op == AtomicRMWBinOpAnd + || atomic_op == AtomicRMWBinOpOr + || atomic_op == AtomicRMWBinOpXor; + + /* currently we only implement atomic rmw on x86-64 target */ +#if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64) + + /* For atomic logical binary ops, it implicitly uses rax in cmpxchg + * instruction and implicitly uses rbx for storing temp value in the + * generated loop */ + eax_hreg = jit_codegen_get_hreg_by_name("eax"); + rax_hreg = jit_codegen_get_hreg_by_name("rax"); + ebx_hreg = jit_codegen_get_hreg_by_name("ebx"); + rbx_hreg = jit_codegen_get_hreg_by_name("rbx"); + + bh_assert(op_type == VALUE_TYPE_I32 || op_type == VALUE_TYPE_I64); + if (op_type == VALUE_TYPE_I32) { + POP_I32(value); + } + else { + POP_I64(value); + } + POP_I32(addr); + + offset1 = check_and_seek(cc, addr, offset, bytes); + if (!offset1) { + goto fail; + } + CHECK_ALIGNMENT(offset1); + + memory_data = get_memory_data_reg(cc->jit_frame, 0); + + if (op_type == VALUE_TYPE_I32) + result = jit_cc_new_reg_I32(cc); + else + result = jit_cc_new_reg_I64(cc); + + switch (atomic_op) { + case AtomicRMWBinOpAdd: + { + GEN_AT_RMW_INSN(ADD, op_type, bytes, result, value, memory_data, + offset1); + break; + } + case AtomicRMWBinOpSub: + { + GEN_AT_RMW_INSN(SUB, op_type, bytes, result, value, memory_data, + offset1); + break; + } + case AtomicRMWBinOpAnd: + { + GEN_AT_RMW_INSN(AND, op_type, bytes, result, value, memory_data, + offset1); + break; + } + case AtomicRMWBinOpOr: + { + GEN_AT_RMW_INSN(OR, op_type, bytes, result, value, memory_data, + offset1); + break; + } + case AtomicRMWBinOpXor: + { + GEN_AT_RMW_INSN(XOR, op_type, bytes, result, value, memory_data, + offset1); + break; + } + case AtomicRMWBinOpXchg: + { + GEN_AT_RMW_INSN(XCHG, op_type, bytes, result, value, memory_data, + offset1); + break; + } + default: + { + bh_assert(0); + goto fail; + } + } + + if (is_logical_op + && (!insn + || !jit_lock_reg_in_insn(cc, insn, is_i32 ? eax_hreg : rax_hreg) + || !jit_lock_reg_in_insn(cc, insn, is_i32 ? ebx_hreg : rbx_hreg))) { + jit_set_last_error( + cc, "generate atomic logical insn or lock ra&rb hreg failed"); + goto fail; + } + + if (op_type == VALUE_TYPE_I32) + PUSH_I32(result); + else + PUSH_I64(result); + + return true; +#endif /* defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64) */ + +fail: + return false; +} + +bool +jit_compile_op_atomic_cmpxchg(JitCompContext *cc, uint8 op_type, uint32 align, + uint32 offset, uint32 bytes) +{ + JitReg addr, offset1, memory_data, value, expect, result; + bool is_i32 = op_type == VALUE_TYPE_I32; + /* currently we only implement atomic cmpxchg on x86-64 target */ +#if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64) + /* cmpxchg will use register al/ax/eax/rax to store parameter expected + * value, and the read result will also be stored to al/ax/eax/rax */ + JitReg eax_hreg = jit_codegen_get_hreg_by_name("eax"); + JitReg rax_hreg = jit_codegen_get_hreg_by_name("rax"); + JitInsn *insn = NULL; + + bh_assert(op_type == VALUE_TYPE_I32 || op_type == VALUE_TYPE_I64); + if (is_i32) { + POP_I32(value); + POP_I32(expect); + result = jit_cc_new_reg_I32(cc); + } + else { + POP_I64(value); + POP_I64(expect); + result = jit_cc_new_reg_I64(cc); + } + POP_I32(addr); + + offset1 = check_and_seek(cc, addr, offset, bytes); + if (!offset1) { + goto fail; + } + CHECK_ALIGNMENT(offset1); + + memory_data = get_memory_data_reg(cc->jit_frame, 0); + + GEN_INSN(MOV, is_i32 ? eax_hreg : rax_hreg, expect); + switch (bytes) { + case 1: + { + insn = GEN_INSN(AT_CMPXCHGU8, value, is_i32 ? eax_hreg : rax_hreg, + memory_data, offset1); + break; + } + case 2: + { + insn = GEN_INSN(AT_CMPXCHGU16, value, is_i32 ? eax_hreg : rax_hreg, + memory_data, offset1); + break; + } + case 4: + { + if (op_type == VALUE_TYPE_I32) + insn = + GEN_INSN(AT_CMPXCHGI32, value, is_i32 ? eax_hreg : rax_hreg, + memory_data, offset1); + else + insn = + GEN_INSN(AT_CMPXCHGU32, value, is_i32 ? eax_hreg : rax_hreg, + memory_data, offset1); + break; + } + case 8: + { + insn = GEN_INSN(AT_CMPXCHGI64, value, is_i32 ? eax_hreg : rax_hreg, + memory_data, offset1); + break; + } + default: + { + bh_assert(0); + goto fail; + } + } + + if (!insn + || !jit_lock_reg_in_insn(cc, insn, is_i32 ? eax_hreg : rax_hreg)) { + jit_set_last_error(cc, "generate cmpxchg insn or lock ra hreg failed"); + goto fail; + } + + GEN_INSN(MOV, result, is_i32 ? eax_hreg : rax_hreg); + + if (is_i32) + PUSH_I32(result); + else + PUSH_I64(result); + + return true; +#endif /* defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64) */ + +fail: + return false; +} + +bool +jit_compile_op_atomic_wait(JitCompContext *cc, uint8 op_type, uint32 align, + uint32 offset, uint32 bytes) +{ + bh_assert(op_type == VALUE_TYPE_I32 || op_type == VALUE_TYPE_I64); + + // Pop atomic.wait arguments + JitReg timeout, expect, expect_64, addr; + POP_I64(timeout); + if (op_type == VALUE_TYPE_I32) { + POP_I32(expect); + expect_64 = jit_cc_new_reg_I64(cc); + GEN_INSN(I32TOI64, expect_64, expect); + } + else { + POP_I64(expect_64); + } + POP_I32(addr); + + // Get referenced address and store it in `maddr` + JitReg memory_data = get_memory_data_reg(cc->jit_frame, 0); + JitReg offset1 = check_and_seek(cc, addr, offset, bytes); + if (!offset1) + goto fail; + CHECK_ALIGNMENT(offset1); + + JitReg maddr = jit_cc_new_reg_ptr(cc); + GEN_INSN(ADD, maddr, memory_data, offset1); + + // Prepare `wasm_runtime_atomic_wait` arguments + JitReg res = jit_cc_new_reg_I32(cc); + JitReg args[5] = { 0 }; + args[0] = get_module_inst_reg(cc->jit_frame); + args[1] = maddr; + args[2] = expect_64; + args[3] = timeout; + args[4] = NEW_CONST(I32, false); + + if (!jit_emit_callnative(cc, wasm_runtime_atomic_wait, res, args, + sizeof(args) / sizeof(args[0]))) + goto fail; + + // Handle return code + GEN_INSN(CMP, cc->cmp_reg, res, NEW_CONST(I32, -1)); + if (!jit_emit_exception(cc, EXCE_ALREADY_THROWN, JIT_OP_BEQ, cc->cmp_reg, + NULL)) + goto fail; + + PUSH_I32(res); + +#if WASM_ENABLE_THREAD_MGR != 0 + /* Insert suspend check point */ + if (!jit_check_suspend_flags(cc)) + goto fail; +#endif + return true; +fail: + return false; +} + +bool +jit_compiler_op_atomic_notify(JitCompContext *cc, uint32 align, uint32 offset, + uint32 bytes) +{ + // Pop atomic.notify arguments + JitReg notify_count, addr; + POP_I32(notify_count); + POP_I32(addr); + + // Get referenced address and store it in `maddr` + JitReg memory_data = get_memory_data_reg(cc->jit_frame, 0); + JitReg offset1 = check_and_seek(cc, addr, offset, bytes); + if (!offset1) + goto fail; + CHECK_ALIGNMENT(offset1); + + JitReg maddr = jit_cc_new_reg_ptr(cc); + GEN_INSN(ADD, maddr, memory_data, offset1); + + // Prepare `wasm_runtime_atomic_notify` arguments + JitReg res = jit_cc_new_reg_I32(cc); + JitReg args[3] = { 0 }; + args[0] = get_module_inst_reg(cc->jit_frame); + args[1] = maddr; + args[2] = notify_count; + + if (!jit_emit_callnative(cc, wasm_runtime_atomic_notify, res, args, + sizeof(args) / sizeof(args[0]))) + goto fail; + + // Handle return code + GEN_INSN(CMP, cc->cmp_reg, res, NEW_CONST(I32, 0)); + if (!jit_emit_exception(cc, EXCE_ALREADY_THROWN, JIT_OP_BLTS, cc->cmp_reg, + NULL)) + goto fail; + + PUSH_I32(res); + return true; +fail: + return false; +} + +bool +jit_compiler_op_atomic_fence(JitCompContext *cc) +{ + GEN_INSN(FENCE); + return true; +} +#endif diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/fe/jit_emit_memory.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/fe/jit_emit_memory.h similarity index 97% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/fe/jit_emit_memory.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/fe/jit_emit_memory.h index bbf715f2a17..6565cdc11b2 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/fe/jit_emit_memory.h +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/fe/jit_emit_memory.h @@ -80,6 +80,9 @@ jit_compile_op_atomic_wait(JitCompContext *cc, uint8 op_type, uint32 align, bool jit_compiler_op_atomic_notify(JitCompContext *cc, uint32 align, uint32 offset, uint32 bytes); + +bool +jit_compiler_op_atomic_fence(JitCompContext *cc); #endif #ifdef __cplusplus diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/fe/jit_emit_numberic.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/fe/jit_emit_numberic.c similarity index 96% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/fe/jit_emit_numberic.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/fe/jit_emit_numberic.c index 3b2f21af864..03491e691b8 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/fe/jit_emit_numberic.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/fe/jit_emit_numberic.c @@ -665,7 +665,7 @@ compile_int_div(JitCompContext *cc, IntArithmetic arith_op, bool is_i32, case 0: { /* Directly throw exception if divided by zero */ - if (!(jit_emit_exception(cc, JIT_EXCE_INTEGER_DIVIDE_BY_ZERO, + if (!(jit_emit_exception(cc, EXCE_INTEGER_DIVIDE_BY_ZERO, JIT_OP_JMP, 0, NULL))) goto fail; @@ -699,7 +699,7 @@ compile_int_div(JitCompContext *cc, IntArithmetic arith_op, bool is_i32, /* Throw integer overflow exception if left is INT32_MIN or INT64_MIN */ - if (!(jit_emit_exception(cc, JIT_EXCE_INTEGER_OVERFLOW, + if (!(jit_emit_exception(cc, EXCE_INTEGER_OVERFLOW, JIT_OP_BEQ, cc->cmp_reg, NULL))) goto fail; @@ -739,8 +739,8 @@ compile_int_div(JitCompContext *cc, IntArithmetic arith_op, bool is_i32, GEN_INSN(CMP, cc->cmp_reg, right, is_i32 ? NEW_CONST(I32, 0) : NEW_CONST(I64, 0)); /* Throw integer divided by zero exception if right is zero */ - if (!(jit_emit_exception(cc, JIT_EXCE_INTEGER_DIVIDE_BY_ZERO, - JIT_OP_BEQ, cc->cmp_reg, NULL))) + if (!(jit_emit_exception(cc, EXCE_INTEGER_DIVIDE_BY_ZERO, JIT_OP_BEQ, + cc->cmp_reg, NULL))) goto fail; switch (arith_op) { @@ -760,8 +760,8 @@ compile_int_div(JitCompContext *cc, IntArithmetic arith_op, bool is_i32, GEN_INSN(CMP, cc->cmp_reg, cmp1, NEW_CONST(I32, 1)); /* Throw integer overflow exception if left is INT32_MIN or INT64_MIN, and right is -1 */ - if (!(jit_emit_exception(cc, JIT_EXCE_INTEGER_OVERFLOW, - JIT_OP_BEQ, cc->cmp_reg, NULL))) + if (!(jit_emit_exception(cc, EXCE_INTEGER_OVERFLOW, JIT_OP_BEQ, + cc->cmp_reg, NULL))) goto fail; /* Build default div and rem */ @@ -770,16 +770,21 @@ compile_int_div(JitCompContext *cc, IntArithmetic arith_op, bool is_i32, } case INT_REM_S: { + JitReg left1 = + is_i32 ? jit_cc_new_reg_I32(cc) : jit_cc_new_reg_I64(cc); + GEN_INSN(CMP, cc->cmp_reg, right, is_i32 ? NEW_CONST(I32, -1) : NEW_CONST(I64, -1LL)); + /* Don't generate `SELECTEQ left, cmp_reg, 0, left` since + left might be const, use left1 instead */ if (is_i32) - GEN_INSN(SELECTEQ, left, cc->cmp_reg, NEW_CONST(I32, 0), + GEN_INSN(SELECTEQ, left1, cc->cmp_reg, NEW_CONST(I32, 0), left); else - GEN_INSN(SELECTEQ, left, cc->cmp_reg, NEW_CONST(I64, 0), + GEN_INSN(SELECTEQ, left1, cc->cmp_reg, NEW_CONST(I64, 0), left); /* Build default div and rem */ - return compile_int_div_no_check(cc, arith_op, is_i32, left, + return compile_int_div_no_check(cc, arith_op, is_i32, left1, right, res); } default: @@ -1522,47 +1527,47 @@ jit_compile_op_f64_math(JitCompContext *cc, FloatMath math_op) } static float32 -local_minf(float32 f1, float32 f2) +f32_min(float32 a, float32 b) { - if (isnan(f1)) - return f1; - if (isnan(f2)) - return f2; - - return fminf(f1, f2); + if (isnan(a) || isnan(b)) + return NAN; + else if (a == 0 && a == b) + return signbit(a) ? a : b; + else + return a > b ? b : a; } -static float64 -local_min(float64 f1, float64 f2) +static float32 +f32_max(float32 a, float32 b) { - if (isnan(f1)) - return f1; - if (isnan(f2)) - return f2; - - return fmin(f1, f2); + if (isnan(a) || isnan(b)) + return NAN; + else if (a == 0 && a == b) + return signbit(a) ? b : a; + else + return a > b ? a : b; } -static float32 -local_maxf(float32 f1, float32 f2) +static float64 +f64_min(float64 a, float64 b) { - if (isnan(f1)) - return f1; - if (isnan(f2)) - return f2; - - return fmaxf(f1, f2); + if (isnan(a) || isnan(b)) + return NAN; + else if (a == 0 && a == b) + return signbit(a) ? a : b; + else + return a > b ? b : a; } static float64 -local_max(float64 f1, float64 f2) +f64_max(float64 a, float64 b) { - if (isnan(f1)) - return f1; - if (isnan(f2)) - return f2; - - return fmax(f1, f2); + if (isnan(a) || isnan(b)) + return NAN; + else if (a == 0 && a == b) + return signbit(a) ? b : a; + else + return a > b ? a : b; } static bool @@ -1574,9 +1579,9 @@ compile_op_float_min_max(JitCompContext *cc, FloatArithmetic arith_op, res = is_f32 ? jit_cc_new_reg_F32(cc) : jit_cc_new_reg_F64(cc); if (arith_op == FLOAT_MIN) - func = is_f32 ? (void *)local_minf : (void *)local_min; + func = is_f32 ? (void *)f32_min : (void *)f64_min; else - func = is_f32 ? (void *)local_maxf : (void *)local_max; + func = is_f32 ? (void *)f32_max : (void *)f64_max; args[0] = lhs; args[1] = rhs; diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/fe/jit_emit_numberic.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/fe/jit_emit_numberic.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/fe/jit_emit_numberic.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/fe/jit_emit_numberic.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/fe/jit_emit_parametric.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/fe/jit_emit_parametric.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/fe/jit_emit_parametric.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/fe/jit_emit_parametric.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/fe/jit_emit_parametric.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/fe/jit_emit_parametric.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/fe/jit_emit_parametric.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/fe/jit_emit_parametric.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/fe/jit_emit_table.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/fe/jit_emit_table.c similarity index 86% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/fe/jit_emit_table.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/fe/jit_emit_table.c index 57017113314..9fb61931f2d 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/fe/jit_emit_table.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/fe/jit_emit_table.c @@ -30,15 +30,15 @@ jit_compile_op_elem_drop(JitCompContext *cc, uint32 tbl_seg_idx) bool jit_compile_op_table_get(JitCompContext *cc, uint32 tbl_idx) { - JitReg elem_idx, tbl_sz, tbl_data, elem_idx_long, offset, res; + JitReg elem_idx, tbl_sz, tbl_elems, elem_idx_long, offset, res; POP_I32(elem_idx); /* if (elem_idx >= tbl_sz) goto exception; */ tbl_sz = get_table_cur_size_reg(cc->jit_frame, tbl_idx); GEN_INSN(CMP, cc->cmp_reg, elem_idx, tbl_sz); - if (!jit_emit_exception(cc, JIT_EXCE_OUT_OF_BOUNDS_TABLE_ACCESS, - JIT_OP_BGEU, cc->cmp_reg, NULL)) + if (!jit_emit_exception(cc, EXCE_OUT_OF_BOUNDS_TABLE_ACCESS, JIT_OP_BGEU, + cc->cmp_reg, NULL)) goto fail; elem_idx_long = jit_cc_new_reg_I64(cc); @@ -48,8 +48,8 @@ jit_compile_op_table_get(JitCompContext *cc, uint32 tbl_idx) GEN_INSN(MUL, offset, elem_idx_long, NEW_CONST(I64, sizeof(uint32))); res = jit_cc_new_reg_I32(cc); - tbl_data = get_table_data_reg(cc->jit_frame, tbl_idx); - GEN_INSN(LDI32, res, tbl_data, offset); + tbl_elems = get_table_elems_reg(cc->jit_frame, tbl_idx); + GEN_INSN(LDI32, res, tbl_elems, offset); PUSH_I32(res); return true; @@ -60,7 +60,7 @@ jit_compile_op_table_get(JitCompContext *cc, uint32 tbl_idx) bool jit_compile_op_table_set(JitCompContext *cc, uint32 tbl_idx) { - JitReg elem_idx, elem_val, tbl_sz, tbl_data, elem_idx_long, offset; + JitReg elem_idx, elem_val, tbl_sz, tbl_elems, elem_idx_long, offset; POP_I32(elem_val); POP_I32(elem_idx); @@ -68,8 +68,8 @@ jit_compile_op_table_set(JitCompContext *cc, uint32 tbl_idx) /* if (elem_idx >= tbl_sz) goto exception; */ tbl_sz = get_table_cur_size_reg(cc->jit_frame, tbl_idx); GEN_INSN(CMP, cc->cmp_reg, elem_idx, tbl_sz); - if (!jit_emit_exception(cc, JIT_EXCE_OUT_OF_BOUNDS_TABLE_ACCESS, - JIT_OP_BGEU, cc->cmp_reg, NULL)) + if (!jit_emit_exception(cc, EXCE_OUT_OF_BOUNDS_TABLE_ACCESS, JIT_OP_BGEU, + cc->cmp_reg, NULL)) goto fail; elem_idx_long = jit_cc_new_reg_I64(cc); @@ -78,8 +78,8 @@ jit_compile_op_table_set(JitCompContext *cc, uint32 tbl_idx) offset = jit_cc_new_reg_I64(cc); GEN_INSN(MUL, offset, elem_idx_long, NEW_CONST(I64, sizeof(uint32))); - tbl_data = get_table_data_reg(cc->jit_frame, tbl_idx); - GEN_INSN(STI32, elem_val, tbl_data, offset); + tbl_elems = get_table_elems_reg(cc->jit_frame, tbl_idx); + GEN_INSN(STI32, elem_val, tbl_elems, offset); return true; fail: @@ -105,7 +105,7 @@ wasm_init_table(WASMModuleInstance *inst, uint32 tbl_idx, uint32 elem_idx, if (src > elem_len || elem_len - src < len) goto out_of_bounds; - bh_memcpy_s((uint8 *)(tbl) + offsetof(WASMTableInstance, base_addr) + 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))); @@ -140,8 +140,8 @@ jit_compile_op_table_init(JitCompContext *cc, uint32 tbl_idx, goto fail; GEN_INSN(CMP, cc->cmp_reg, res, NEW_CONST(I32, 0)); - if (!jit_emit_exception(cc, JIT_EXCE_ALREADY_THROWN, JIT_OP_BLTS, - cc->cmp_reg, NULL)) + if (!jit_emit_exception(cc, EXCE_ALREADY_THROWN, JIT_OP_BLTS, cc->cmp_reg, + NULL)) goto fail; return true; @@ -167,10 +167,10 @@ wasm_copy_table(WASMModuleInstance *inst, uint32 src_tbl_idx, if (dst_offset > dst_tbl_sz || dst_tbl_sz - dst_offset < len) goto out_of_bounds; - bh_memmove_s((uint8 *)(dst_tbl) + offsetof(WASMTableInstance, base_addr) + bh_memmove_s((uint8 *)dst_tbl + offsetof(WASMTableInstance, elems) + dst_offset * sizeof(uint32), (uint32)((dst_tbl_sz - dst_offset) * sizeof(uint32)), - (uint8 *)(src_tbl) + offsetof(WASMTableInstance, base_addr) + (uint8 *)src_tbl + offsetof(WASMTableInstance, elems) + src_offset * sizeof(uint32), (uint32)(len * sizeof(uint32))); @@ -204,8 +204,8 @@ jit_compile_op_table_copy(JitCompContext *cc, uint32 src_tbl_idx, goto fail; GEN_INSN(CMP, cc->cmp_reg, res, NEW_CONST(I32, 0)); - if (!jit_emit_exception(cc, JIT_EXCE_ALREADY_THROWN, JIT_OP_BLTS, - cc->cmp_reg, NULL)) + if (!jit_emit_exception(cc, EXCE_ALREADY_THROWN, JIT_OP_BLTS, cc->cmp_reg, + NULL)) goto fail; return true; @@ -276,7 +276,7 @@ wasm_fill_table(WASMModuleInstance *inst, uint32 tbl_idx, uint32 dst, goto out_of_bounds; for (; len != 0; dst++, len--) { - ((uint32 *)(tbl->base_addr))[dst] = val; + tbl->elems[dst] = val; } return 0; @@ -307,8 +307,8 @@ jit_compile_op_table_fill(JitCompContext *cc, uint32 tbl_idx) goto fail; GEN_INSN(CMP, cc->cmp_reg, res, NEW_CONST(I32, 0)); - if (!jit_emit_exception(cc, JIT_EXCE_ALREADY_THROWN, JIT_OP_BLTS, - cc->cmp_reg, NULL)) + if (!jit_emit_exception(cc, EXCE_ALREADY_THROWN, JIT_OP_BLTS, cc->cmp_reg, + NULL)) goto fail; return true; diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/fe/jit_emit_table.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/fe/jit_emit_table.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/fe/jit_emit_table.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/fe/jit_emit_table.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/fe/jit_emit_variable.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/fe/jit_emit_variable.c similarity index 86% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/fe/jit_emit_variable.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/fe/jit_emit_variable.c index e018d22060c..ffbf06ab13d 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/fe/jit_emit_variable.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/fe/jit_emit_variable.c @@ -177,21 +177,6 @@ get_global_type(const WASMModule *module, uint32 global_idx) } } -static uint32 -get_global_data_offset(const WASMModule *module, uint32 global_idx) -{ - if (global_idx < module->import_global_count) { - const WASMGlobalImport *import_global = - &((module->import_globals + global_idx)->u.global); - return import_global->data_offset; - } - else { - const WASMGlobal *global = - module->globals + (global_idx - module->import_global_count); - return global->data_offset; - } -} - bool jit_compile_op_get_global(JitCompContext *cc, uint32 global_idx) { @@ -202,8 +187,10 @@ jit_compile_op_get_global(JitCompContext *cc, uint32 global_idx) bh_assert(global_idx < cc->cur_wasm_module->import_global_count + cc->cur_wasm_module->global_count); - data_offset = get_global_data_offset(cc->cur_wasm_module, global_idx); + data_offset = + jit_frontend_get_global_data_offset(cc->cur_wasm_module, global_idx); global_type = get_global_type(cc->cur_wasm_module, global_idx); + switch (global_type) { case VALUE_TYPE_I32: #if WASM_ENABLE_REF_TYPES != 0 @@ -212,28 +199,28 @@ jit_compile_op_get_global(JitCompContext *cc, uint32 global_idx) #endif { value = jit_cc_new_reg_I32(cc); - GEN_INSN(LDI32, value, get_global_data_reg(cc->jit_frame), + GEN_INSN(LDI32, value, get_module_inst_reg(cc->jit_frame), NEW_CONST(I32, data_offset)); break; } case VALUE_TYPE_I64: { value = jit_cc_new_reg_I64(cc); - GEN_INSN(LDI64, value, get_global_data_reg(cc->jit_frame), + GEN_INSN(LDI64, value, get_module_inst_reg(cc->jit_frame), NEW_CONST(I32, data_offset)); break; } case VALUE_TYPE_F32: { value = jit_cc_new_reg_F32(cc); - GEN_INSN(LDF32, value, get_global_data_reg(cc->jit_frame), + GEN_INSN(LDF32, value, get_module_inst_reg(cc->jit_frame), NEW_CONST(I32, data_offset)); break; } case VALUE_TYPE_F64: { value = jit_cc_new_reg_F64(cc); - GEN_INSN(LDF64, value, get_global_data_reg(cc->jit_frame), + GEN_INSN(LDF64, value, get_module_inst_reg(cc->jit_frame), NEW_CONST(I32, data_offset)); break; } @@ -262,8 +249,10 @@ jit_compile_op_set_global(JitCompContext *cc, uint32 global_idx, bh_assert(global_idx < cc->cur_wasm_module->import_global_count + cc->cur_wasm_module->global_count); - data_offset = get_global_data_offset(cc->cur_wasm_module, global_idx); + data_offset = + jit_frontend_get_global_data_offset(cc->cur_wasm_module, global_idx); global_type = get_global_type(cc->cur_wasm_module, global_idx); + switch (global_type) { case VALUE_TYPE_I32: #if WASM_ENABLE_REF_TYPES != 0 @@ -277,36 +266,36 @@ jit_compile_op_set_global(JitCompContext *cc, uint32 global_idx, JitReg aux_stack_bottom = get_aux_stack_bottom_reg(cc->jit_frame); GEN_INSN(CMP, cc->cmp_reg, value, aux_stack_bound); - if (!(jit_emit_exception(cc, JIT_EXCE_AUX_STACK_OVERFLOW, + if (!(jit_emit_exception(cc, EXCE_AUX_STACK_OVERFLOW, JIT_OP_BLEU, cc->cmp_reg, NULL))) goto fail; GEN_INSN(CMP, cc->cmp_reg, value, aux_stack_bottom); - if (!(jit_emit_exception(cc, JIT_EXCE_AUX_STACK_UNDERFLOW, + if (!(jit_emit_exception(cc, EXCE_AUX_STACK_UNDERFLOW, JIT_OP_BGTU, cc->cmp_reg, NULL))) goto fail; } - GEN_INSN(STI32, value, get_global_data_reg(cc->jit_frame), + GEN_INSN(STI32, value, get_module_inst_reg(cc->jit_frame), NEW_CONST(I32, data_offset)); break; } case VALUE_TYPE_I64: { POP_I64(value); - GEN_INSN(STI64, value, get_global_data_reg(cc->jit_frame), + GEN_INSN(STI64, value, get_module_inst_reg(cc->jit_frame), NEW_CONST(I32, data_offset)); break; } case VALUE_TYPE_F32: { POP_F32(value); - GEN_INSN(STF32, value, get_global_data_reg(cc->jit_frame), + GEN_INSN(STF32, value, get_module_inst_reg(cc->jit_frame), NEW_CONST(I32, data_offset)); break; } case VALUE_TYPE_F64: { POP_F64(value); - GEN_INSN(STF64, value, get_global_data_reg(cc->jit_frame), + GEN_INSN(STF64, value, get_module_inst_reg(cc->jit_frame), NEW_CONST(I32, data_offset)); break; } diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/fe/jit_emit_variable.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/fe/jit_emit_variable.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/fe/jit_emit_variable.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/fe/jit_emit_variable.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/iwasm_fast_jit.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/iwasm_fast_jit.cmake similarity index 96% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/iwasm_fast_jit.cmake rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/iwasm_fast_jit.cmake index 67c4b975b42..cd880a34b2e 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/iwasm_fast_jit.cmake +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/iwasm_fast_jit.cmake @@ -16,11 +16,13 @@ if (WAMR_BUILD_TARGET STREQUAL "X86_64" OR WAMR_BUILD_TARGET STREQUAL "AMD_64") FetchContent_Declare( asmjit GIT_REPOSITORY https://github.com/asmjit/asmjit.git + GIT_TAG c1019f1642a588107148f64ba54584b0ae3ec8d1 ) else () FetchContent_Declare( asmjit GIT_REPOSITORY https://github.com/asmjit/asmjit.git + GIT_TAG c1019f1642a588107148f64ba54584b0ae3ec8d1 PATCH_COMMAND git apply ${IWASM_FAST_JIT_DIR}/asmjit_sgx_patch.diff ) endif () diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/jit_codecache.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/jit_codecache.c similarity index 62% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/jit_codecache.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/jit_codecache.c index 4c899ad9d7b..73a034f3497 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/jit_codecache.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/jit_codecache.c @@ -56,10 +56,31 @@ jit_code_cache_free(void *ptr) bool jit_pass_register_jitted_code(JitCompContext *cc) { - uint32 jit_func_idx = - cc->cur_wasm_func_idx - cc->cur_wasm_module->import_function_count; - cc->cur_wasm_func->fast_jit_jitted_code = cc->jitted_addr_begin; - cc->cur_wasm_module->fast_jit_func_ptrs[jit_func_idx] = + WASMModuleInstance *instance; + WASMModule *module = cc->cur_wasm_module; + WASMFunction *func = cc->cur_wasm_func; + uint32 jit_func_idx = cc->cur_wasm_func_idx - module->import_function_count; + +#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \ + && WASM_ENABLE_LAZY_JIT != 0 + os_mutex_lock(&module->instance_list_lock); +#endif + + module->fast_jit_func_ptrs[jit_func_idx] = func->fast_jit_jitted_code = cc->jitted_addr_begin; + +#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \ + && WASM_ENABLE_LAZY_JIT != 0 + instance = module->instance_list; + while (instance) { + if (instance->e->running_mode == Mode_Fast_JIT) + instance->fast_jit_func_ptrs[jit_func_idx] = cc->jitted_addr_begin; + instance = instance->e->next; + } + + os_mutex_unlock(&module->instance_list_lock); +#else + (void)instance; +#endif return true; } diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/jit_codecache.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/jit_codecache.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/jit_codecache.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/jit_codecache.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/jit_codegen.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/jit_codegen.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/jit_codegen.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/jit_codegen.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/jit_codegen.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/jit_codegen.h similarity index 85% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/jit_codegen.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/jit_codegen.h index 666a239a6fe..735cddab624 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/jit_codegen.h +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/jit_codegen.h @@ -65,6 +65,14 @@ jit_codegen_gen_native(JitCompContext *cc); bool jit_codegen_lower(JitCompContext *cc); +#if WASM_ENABLE_LAZY_JIT != 0 && WASM_ENABLE_JIT != 0 +void * +jit_codegen_compile_call_to_llvm_jit(const WASMType *func_type); + +void * +jit_codegen_compile_call_to_fast_jit(const WASMModule *module, uint32 func_idx); +#endif + /** * Dump native code in the given range to assembly. * @@ -75,7 +83,8 @@ void jit_codegen_dump_native(void *begin_addr, void *end_addr); int -jit_codegen_interp_jitted_glue(void *self, JitInterpSwitchInfo *info, void *pc); +jit_codegen_interp_jitted_glue(void *self, JitInterpSwitchInfo *info, + uint32 func_idx, void *pc); #ifdef __cplusplus } diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/jit_compiler.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/jit_compiler.c new file mode 100644 index 00000000000..958d0e987b8 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/jit_compiler.c @@ -0,0 +1,291 @@ +/* + * Copyright (C) 2021 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "jit_compiler.h" +#include "jit_ir.h" +#include "jit_codegen.h" +#include "jit_codecache.h" +#include "../interpreter/wasm.h" + +typedef struct JitCompilerPass { + /* Name of the pass */ + const char *name; + /* The entry of the compiler pass */ + bool (*run)(JitCompContext *cc); +} JitCompilerPass; + +/* clang-format off */ +static JitCompilerPass compiler_passes[] = { + { NULL, NULL }, +#define REG_PASS(name) { #name, jit_pass_##name } + REG_PASS(dump), + REG_PASS(update_cfg), + REG_PASS(frontend), + REG_PASS(lower_cg), + REG_PASS(regalloc), + REG_PASS(codegen), + REG_PASS(register_jitted_code) +#undef REG_PASS +}; + +/* Number of compiler passes */ +#define COMPILER_PASS_NUM (sizeof(compiler_passes) / sizeof(compiler_passes[0])) + +#if WASM_ENABLE_FAST_JIT_DUMP == 0 +static const uint8 compiler_passes_without_dump[] = { + 3, 4, 5, 6, 7, 0 +}; +#else +static const uint8 compiler_passes_with_dump[] = { + 3, 2, 1, 4, 1, 5, 1, 6, 1, 7, 0 +}; +#endif + +/* The exported global data of JIT compiler */ +static JitGlobals jit_globals = { +#if WASM_ENABLE_FAST_JIT_DUMP == 0 + .passes = compiler_passes_without_dump, +#else + .passes = compiler_passes_with_dump, +#endif + .return_to_interp_from_jitted = NULL, +#if WASM_ENABLE_LAZY_JIT != 0 + .compile_fast_jit_and_then_call = NULL, +#endif +}; +/* clang-format on */ + +static bool +apply_compiler_passes(JitCompContext *cc) +{ + const uint8 *p = jit_globals.passes; + + for (; *p; p++) { + /* Set the pass NO */ + cc->cur_pass_no = p - jit_globals.passes; + bh_assert(*p < COMPILER_PASS_NUM); + + if (!compiler_passes[*p].run(cc) || jit_get_last_error(cc)) { + LOG_VERBOSE("JIT: compilation failed at pass[%td] = %s\n", + p - jit_globals.passes, compiler_passes[*p].name); + return false; + } + } + + return true; +} + +bool +jit_compiler_init(const JitCompOptions *options) +{ + uint32 code_cache_size = options->code_cache_size > 0 + ? options->code_cache_size + : FAST_JIT_DEFAULT_CODE_CACHE_SIZE; + + LOG_VERBOSE("JIT: compiler init with code cache size: %u\n", + code_cache_size); + + if (!jit_code_cache_init(code_cache_size)) + return false; + + if (!jit_codegen_init()) + goto fail1; + + return true; + +fail1: + jit_code_cache_destroy(); + return false; +} + +void +jit_compiler_destroy() +{ + jit_codegen_destroy(); + + jit_code_cache_destroy(); +} + +JitGlobals * +jit_compiler_get_jit_globals() +{ + return &jit_globals; +} + +const char * +jit_compiler_get_pass_name(unsigned i) +{ + return i < COMPILER_PASS_NUM ? compiler_passes[i].name : NULL; +} + +bool +jit_compiler_compile(WASMModule *module, uint32 func_idx) +{ + JitCompContext *cc = NULL; + char *last_error; + bool ret = false; + uint32 i = func_idx - module->import_function_count; + uint32 j = i % WASM_ORC_JIT_BACKEND_THREAD_NUM; + + /* Lock to avoid duplicated compilation by other threads */ + os_mutex_lock(&module->fast_jit_thread_locks[j]); + + if (jit_compiler_is_compiled(module, func_idx)) { + /* Function has been compiled */ + os_mutex_unlock(&module->fast_jit_thread_locks[j]); + return true; + } + + /* Initialize the compilation context */ + if (!(cc = jit_calloc(sizeof(*cc)))) { + goto fail; + } + + if (!jit_cc_init(cc, 64)) { + goto fail; + } + + cc->cur_wasm_module = module; + cc->cur_wasm_func = module->functions[i]; + cc->cur_wasm_func_idx = func_idx; + cc->mem_space_unchanged = (!cc->cur_wasm_func->has_op_memory_grow + && !cc->cur_wasm_func->has_op_func_call) + || (!module->possible_memory_grow); + + /* Apply compiler passes */ + if (!apply_compiler_passes(cc) || jit_get_last_error(cc)) { + last_error = jit_get_last_error(cc); + +#if WASM_ENABLE_CUSTOM_NAME_SECTION != 0 + char *function_name = cc->cur_wasm_func->field_name; + os_printf("fast jit compilation failed: %s (function_name=%s)\n", + last_error ? last_error : "unknown error", function_name); +#else + os_printf("fast jit compilation failed: %s\n", + last_error ? last_error : "unknown error"); +#endif + + goto fail; + } + + ret = true; + +fail: + /* Destroy the compilation context */ + if (cc) + jit_cc_delete(cc); + + os_mutex_unlock(&module->fast_jit_thread_locks[j]); + + return ret; +} + +bool +jit_compiler_compile_all(WASMModule *module) +{ + uint32 i; + + for (i = 0; i < module->function_count; i++) { + if (!jit_compiler_compile(module, module->import_function_count + i)) { + return false; + } + } + + return true; +} + +bool +jit_compiler_is_compiled(const WASMModule *module, uint32 func_idx) +{ + uint32 i = func_idx - module->import_function_count; + + bh_assert(func_idx >= module->import_function_count + && func_idx + < module->import_function_count + module->function_count); + +#if WASM_ENABLE_LAZY_JIT == 0 + return module->fast_jit_func_ptrs[i] ? true : false; +#else + return module->fast_jit_func_ptrs[i] + != jit_globals.compile_fast_jit_and_then_call + ? true + : false; +#endif +} + +#if WASM_ENABLE_LAZY_JIT != 0 && WASM_ENABLE_JIT != 0 +bool +jit_compiler_set_call_to_llvm_jit(WASMModule *module, uint32 func_idx) +{ + uint32 i = func_idx - module->import_function_count; + uint32 j = i % WASM_ORC_JIT_BACKEND_THREAD_NUM; + WASMType *func_type = module->functions[i]->func_type; + uint32 k = + ((uint32)(uintptr_t)func_type >> 3) % WASM_ORC_JIT_BACKEND_THREAD_NUM; + void *func_ptr = NULL; + + /* Compile code block of call_to_llvm_jit_from_fast_jit of + this kind of function type if it hasn't been compiled */ + if (!(func_ptr = func_type->call_to_llvm_jit_from_fast_jit)) { + os_mutex_lock(&module->fast_jit_thread_locks[k]); + if (!(func_ptr = func_type->call_to_llvm_jit_from_fast_jit)) { + if (!(func_ptr = func_type->call_to_llvm_jit_from_fast_jit = + jit_codegen_compile_call_to_llvm_jit(func_type))) { + os_mutex_unlock(&module->fast_jit_thread_locks[k]); + return false; + } + } + os_mutex_unlock(&module->fast_jit_thread_locks[k]); + } + + /* Switch current fast jit func ptr to the code block */ + os_mutex_lock(&module->fast_jit_thread_locks[j]); + module->fast_jit_func_ptrs[i] = func_ptr; + os_mutex_unlock(&module->fast_jit_thread_locks[j]); + return true; +} + +bool +jit_compiler_set_call_to_fast_jit(WASMModule *module, uint32 func_idx) +{ + void *func_ptr = NULL; + + func_ptr = jit_codegen_compile_call_to_fast_jit(module, func_idx); + if (func_ptr) { + uint32 i = func_idx - module->import_function_count; + module->functions[i]->call_to_fast_jit_from_llvm_jit = func_ptr; + jit_compiler_set_llvm_jit_func_ptr(module, func_idx, func_ptr); + } + + return func_ptr ? true : false; +} + +void +jit_compiler_set_llvm_jit_func_ptr(WASMModule *module, uint32 func_idx, + void *func_ptr) +{ + WASMModuleInstance *instance; + uint32 i = func_idx - module->import_function_count; + + os_mutex_lock(&module->instance_list_lock); + + module->func_ptrs[i] = func_ptr; + + instance = module->instance_list; + while (instance) { + if (instance->e->running_mode == Mode_Multi_Tier_JIT) + instance->func_ptrs[func_idx] = func_ptr; + instance = instance->e->next; + } + os_mutex_unlock(&module->instance_list_lock); +} +#endif /* end of WASM_ENABLE_LAZY_JIT != 0 && WASM_ENABLE_JIT != 0 */ + +int +jit_interp_switch_to_jitted(void *exec_env, JitInterpSwitchInfo *info, + uint32 func_idx, void *pc) +{ + return jit_codegen_interp_jitted_glue(exec_env, info, func_idx, pc); +} diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/jit_compiler.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/jit_compiler.h similarity index 84% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/jit_compiler.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/jit_compiler.h index 602494db9d7..9a49cffdd1a 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/jit_compiler.h +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/jit_compiler.h @@ -18,6 +18,9 @@ typedef struct JitGlobals { /* Compiler pass sequence, the last element must be 0 */ const uint8 *passes; char *return_to_interp_from_jitted; +#if WASM_ENABLE_LAZY_JIT != 0 + char *compile_fast_jit_and_then_call; +#endif } JitGlobals; /** @@ -87,8 +90,24 @@ jit_compiler_compile(WASMModule *module, uint32 func_idx); bool jit_compiler_compile_all(WASMModule *module); +bool +jit_compiler_is_compiled(const WASMModule *module, uint32 func_idx); + +#if WASM_ENABLE_LAZY_JIT != 0 && WASM_ENABLE_JIT != 0 +bool +jit_compiler_set_call_to_llvm_jit(WASMModule *module, uint32 func_idx); + +bool +jit_compiler_set_call_to_fast_jit(WASMModule *module, uint32 func_idx); + +void +jit_compiler_set_llvm_jit_func_ptr(WASMModule *module, uint32 func_idx, + void *func_ptr); +#endif + int -jit_interp_switch_to_jitted(void *self, JitInterpSwitchInfo *info, void *pc); +jit_interp_switch_to_jitted(void *self, JitInterpSwitchInfo *info, + uint32 func_idx, void *pc); /* * Pass declarations: diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/jit_dump.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/jit_dump.c similarity index 97% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/jit_dump.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/jit_dump.c index 4dba5c3b77e..d61ed5dc787 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/jit_dump.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/jit_dump.c @@ -114,7 +114,10 @@ jit_dump_insn(JitCompContext *cc, JitInsn *insn) switch (insn->opcode) { #define INSN(NAME, OPND_KIND, OPND_NUM, FIRST_USE) \ case JIT_OP_##NAME: \ - os_printf(" %-15s", #NAME); \ + if (insn->flags_u8 & 0x1) \ + os_printf(" ATOMIC %-8s", #NAME); \ + else \ + os_printf(" %-15s", #NAME); \ jit_dump_insn_##OPND_KIND(cc, insn, OPND_NUM); \ break; #include "jit_ir.def" @@ -319,7 +322,9 @@ jit_pass_dump(JitCompContext *cc) os_printf("JIT.COMPILER.DUMP: PASS_NO=%d PREV_PASS=%s\n\n", pass_no, pass_name); + jit_dump_cc(cc); + os_printf("\n"); return true; } diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/jit_dump.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/jit_dump.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/jit_dump.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/jit_dump.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/jit_frontend.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/jit_frontend.c similarity index 86% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/jit_frontend.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/jit_frontend.c index 90e20da3112..ec68ad91d8e 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/jit_frontend.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/jit_frontend.c @@ -18,30 +18,105 @@ #include "fe/jit_emit_variable.h" #include "../interpreter/wasm_interp.h" #include "../interpreter/wasm_opcode.h" +#include "../interpreter/wasm_runtime.h" #include "../common/wasm_exec_env.h" -/* clang-format off */ -static const char *jit_exception_msgs[] = { - "unreachable", /* JIT_EXCE_UNREACHABLE */ - "allocate memory failed", /* JIT_EXCE_OUT_OF_MEMORY */ - "out of bounds memory access", /* JIT_EXCE_OUT_OF_BOUNDS_MEMORY_ACCESS */ - "integer overflow", /* JIT_EXCE_INTEGER_OVERFLOW */ - "integer divide by zero", /* JIT_EXCE_INTEGER_DIVIDE_BY_ZERO */ - "invalid conversion to integer", /* JIT_EXCE_INVALID_CONVERSION_TO_INTEGER */ - "indirect call type mismatch", /* JIT_EXCE_INVALID_FUNCTION_TYPE_INDEX */ - "invalid function index", /* JIT_EXCE_INVALID_FUNCTION_INDEX */ - "undefined element", /* JIT_EXCE_UNDEFINED_ELEMENT */ - "uninitialized element", /* JIT_EXCE_UNINITIALIZED_ELEMENT */ - "failed to call unlinked import function", /* JIT_EXCE_CALL_UNLINKED_IMPORT_FUNC */ - "native stack overflow", /* JIT_EXCE_NATIVE_STACK_OVERFLOW */ - "unaligned atomic", /* JIT_EXCE_UNALIGNED_ATOMIC */ - "wasm auxiliary stack overflow", /* JIT_EXCE_AUX_STACK_OVERFLOW */ - "wasm auxiliary stack underflow", /* JIT_EXCE_AUX_STACK_UNDERFLOW */ - "out of bounds table access", /* JIT_EXCE_OUT_OF_BOUNDS_TABLE_ACCESS */ - "wasm operand stack overflow", /* JIT_EXCE_OPERAND_STACK_OVERFLOW */ - "", /* JIT_EXCE_ALREADY_THROWN */ -}; -/* clang-format on */ +static uint32 +get_global_base_offset(const WASMModule *module) +{ + uint32 module_inst_struct_size = + (uint32)offsetof(WASMModuleInstance, global_table_data.bytes); + uint32 mem_inst_size = + (uint32)sizeof(WASMMemoryInstance) + * (module->import_memory_count + module->memory_count); + +#if WASM_ENABLE_JIT != 0 + /* If the module dosen't have memory, reserve one mem_info space + with empty content to align with llvm jit compiler */ + if (mem_inst_size == 0) + mem_inst_size = (uint32)sizeof(WASMMemoryInstance); +#endif + + /* Size of module inst and memory instances */ + return module_inst_struct_size + mem_inst_size; +} + +static uint32 +get_first_table_inst_offset(const WASMModule *module) +{ + return get_global_base_offset(module) + module->global_data_size; +} + +uint32 +jit_frontend_get_global_data_offset(const WASMModule *module, uint32 global_idx) +{ + uint32 global_base_offset = get_global_base_offset(module); + + if (global_idx < module->import_global_count) { + const WASMGlobalImport *import_global = + &((module->import_globals + global_idx)->u.global); + return global_base_offset + import_global->data_offset; + } + else { + const WASMGlobal *global = + module->globals + (global_idx - module->import_global_count); + return global_base_offset + global->data_offset; + } +} + +uint32 +jit_frontend_get_table_inst_offset(const WASMModule *module, uint32 tbl_idx) +{ + uint32 offset, i = 0; + + offset = get_first_table_inst_offset(module); + + while (i < tbl_idx && i < module->import_table_count) { + WASMTableImport *import_table = &module->import_tables[i].u.table; + + offset += (uint32)offsetof(WASMTableInstance, elems); +#if WASM_ENABLE_MULTI_MODULE != 0 + offset += (uint32)sizeof(uint32) * import_table->max_size; +#else + offset += (uint32)sizeof(uint32) + * (import_table->possible_grow ? import_table->max_size + : import_table->init_size); +#endif + + i++; + } + + if (i == tbl_idx) { + return offset; + } + + tbl_idx -= module->import_table_count; + i -= module->import_table_count; + while (i < tbl_idx && i < module->table_count) { + WASMTable *table = module->tables + i; + + offset += (uint32)offsetof(WASMTableInstance, elems); +#if WASM_ENABLE_MULTI_MODULE != 0 + offset += (uint32)sizeof(uint32) * table->max_size; +#else + offset += (uint32)sizeof(uint32) + * (table->possible_grow ? table->max_size : table->init_size); +#endif + + i++; + } + + return offset; +} + +uint32 +jit_frontend_get_module_inst_extra_offset(const WASMModule *module) +{ + uint32 offset = jit_frontend_get_table_inst_offset( + module, module->import_table_count + module->table_count); + + return align_uint(offset, 8); +} JitReg get_module_inst_reg(JitFrame *frame) @@ -115,20 +190,6 @@ get_func_type_indexes_reg(JitFrame *frame) return frame->func_type_indexes_reg; } -JitReg -get_global_data_reg(JitFrame *frame) -{ - JitCompContext *cc = frame->cc; - JitReg module_inst_reg = get_module_inst_reg(frame); - - if (!frame->global_data_reg) { - frame->global_data_reg = cc->global_data_reg; - GEN_INSN(LDPTR, frame->global_data_reg, module_inst_reg, - NEW_CONST(I32, offsetof(WASMModuleInstance, global_data))); - } - return frame->global_data_reg; -} - JitReg get_aux_stack_bound_reg(JitFrame *frame) { @@ -158,48 +219,41 @@ get_aux_stack_bottom_reg(JitFrame *frame) } JitReg -get_memories_reg(JitFrame *frame) +get_memory_data_reg(JitFrame *frame, uint32 mem_idx) { JitCompContext *cc = frame->cc; JitReg module_inst_reg = get_module_inst_reg(frame); + uint32 memory_data_offset; - if (!frame->memories_reg) { - frame->memories_reg = cc->memories_reg; - GEN_INSN(LDPTR, frame->memories_reg, module_inst_reg, - NEW_CONST(I32, offsetof(WASMModuleInstance, memories))); - } - return frame->memories_reg; -} - -JitReg -get_memory_inst_reg(JitFrame *frame, uint32 mem_idx) -{ - JitCompContext *cc = frame->cc; - JitReg memories_reg = get_memories_reg(frame); - - if (!frame->memory_regs[mem_idx].memory_inst) { - frame->memory_regs[mem_idx].memory_inst = - cc->memory_regs[mem_idx].memory_inst; - GEN_INSN( - LDPTR, frame->memory_regs[mem_idx].memory_inst, memories_reg, - NEW_CONST(I32, (uint32)sizeof(WASMMemoryInstance *) * mem_idx)); + bh_assert(mem_idx == 0); +#if WASM_ENABLE_SHARED_MEMORY != 0 + uint32 memories_offset = (uint32)offsetof(WASMModuleInstance, memories); + JitReg memories_addr = jit_cc_new_reg_ptr(cc); + JitReg memories_0_addr = jit_cc_new_reg_ptr(cc); + memory_data_offset = (uint32)offsetof(WASMMemoryInstance, memory_data); + if (!frame->memory_regs[mem_idx].memory_data) { + frame->memory_regs[mem_idx].memory_data = + cc->memory_regs[mem_idx].memory_data; + /* module_inst->memories */ + GEN_INSN(LDPTR, memories_addr, module_inst_reg, + NEW_CONST(I32, memories_offset)); + /* module_inst->memories[0] */ + GEN_INSN(LDPTR, memories_0_addr, memories_addr, NEW_CONST(I32, 0)); + /* memories[0]->memory_data */ + GEN_INSN(LDPTR, frame->memory_regs[mem_idx].memory_data, + memories_0_addr, NEW_CONST(I32, memory_data_offset)); } - return frame->memory_regs[mem_idx].memory_inst; -} - -JitReg -get_memory_data_reg(JitFrame *frame, uint32 mem_idx) -{ - JitCompContext *cc = frame->cc; - JitReg memory_inst_reg = get_memory_inst_reg(frame, mem_idx); - +#else + memory_data_offset = + (uint32)offsetof(WASMModuleInstance, global_table_data.bytes) + + (uint32)offsetof(WASMMemoryInstance, memory_data); if (!frame->memory_regs[mem_idx].memory_data) { frame->memory_regs[mem_idx].memory_data = cc->memory_regs[mem_idx].memory_data; GEN_INSN(LDPTR, frame->memory_regs[mem_idx].memory_data, - memory_inst_reg, - NEW_CONST(I32, offsetof(WASMMemoryInstance, memory_data))); + module_inst_reg, NEW_CONST(I32, memory_data_offset)); } +#endif return frame->memory_regs[mem_idx].memory_data; } @@ -207,14 +261,18 @@ JitReg get_memory_data_end_reg(JitFrame *frame, uint32 mem_idx) { JitCompContext *cc = frame->cc; - JitReg memory_inst_reg = get_memory_inst_reg(frame, mem_idx); + JitReg module_inst_reg = get_module_inst_reg(frame); + uint32 memory_data_end_offset = + (uint32)offsetof(WASMModuleInstance, global_table_data.bytes) + + (uint32)offsetof(WASMMemoryInstance, memory_data_end); + + bh_assert(mem_idx == 0); if (!frame->memory_regs[mem_idx].memory_data_end) { frame->memory_regs[mem_idx].memory_data_end = cc->memory_regs[mem_idx].memory_data_end; GEN_INSN(LDPTR, frame->memory_regs[mem_idx].memory_data_end, - memory_inst_reg, - NEW_CONST(I32, offsetof(WASMMemoryInstance, memory_data_end))); + module_inst_reg, NEW_CONST(I32, memory_data_end_offset)); } return frame->memory_regs[mem_idx].memory_data_end; } @@ -223,21 +281,22 @@ JitReg get_mem_bound_check_1byte_reg(JitFrame *frame, uint32 mem_idx) { JitCompContext *cc = frame->cc; - JitReg memory_inst_reg = get_memory_inst_reg(frame, mem_idx); + JitReg module_inst_reg = get_module_inst_reg(frame); + uint32 mem_bound_check_1byte_offset = + (uint32)offsetof(WASMModuleInstance, global_table_data.bytes) + + (uint32)offsetof(WASMMemoryInstance, mem_bound_check_1byte); + + bh_assert(mem_idx == 0); if (!frame->memory_regs[mem_idx].mem_bound_check_1byte) { frame->memory_regs[mem_idx].mem_bound_check_1byte = cc->memory_regs[mem_idx].mem_bound_check_1byte; #if UINTPTR_MAX == UINT64_MAX GEN_INSN(LDI64, frame->memory_regs[mem_idx].mem_bound_check_1byte, - memory_inst_reg, - NEW_CONST( - I32, offsetof(WASMMemoryInstance, mem_bound_check_1byte))); + module_inst_reg, NEW_CONST(I32, mem_bound_check_1byte_offset)); #else GEN_INSN(LDI32, frame->memory_regs[mem_idx].mem_bound_check_1byte, - memory_inst_reg, - NEW_CONST( - I32, offsetof(WASMMemoryInstance, mem_bound_check_1byte))); + module_inst_reg, NEW_CONST(I32, mem_bound_check_1byte_offset)); #endif } return frame->memory_regs[mem_idx].mem_bound_check_1byte; @@ -247,21 +306,24 @@ JitReg get_mem_bound_check_2bytes_reg(JitFrame *frame, uint32 mem_idx) { JitCompContext *cc = frame->cc; - JitReg memory_inst_reg = get_memory_inst_reg(frame, mem_idx); + JitReg module_inst_reg = get_module_inst_reg(frame); + uint32 mem_bound_check_2bytes_offset = + (uint32)offsetof(WASMModuleInstance, global_table_data.bytes) + + (uint32)offsetof(WASMMemoryInstance, mem_bound_check_2bytes); + + bh_assert(mem_idx == 0); if (!frame->memory_regs[mem_idx].mem_bound_check_2bytes) { frame->memory_regs[mem_idx].mem_bound_check_2bytes = cc->memory_regs[mem_idx].mem_bound_check_2bytes; #if UINTPTR_MAX == UINT64_MAX GEN_INSN(LDI64, frame->memory_regs[mem_idx].mem_bound_check_2bytes, - memory_inst_reg, - NEW_CONST(I32, offsetof(WASMMemoryInstance, - mem_bound_check_2bytes))); + module_inst_reg, + NEW_CONST(I32, mem_bound_check_2bytes_offset)); #else GEN_INSN(LDI32, frame->memory_regs[mem_idx].mem_bound_check_2bytes, - memory_inst_reg, - NEW_CONST(I32, offsetof(WASMMemoryInstance, - mem_bound_check_2bytes))); + module_inst_reg, + NEW_CONST(I32, mem_bound_check_2bytes_offset)); #endif } return frame->memory_regs[mem_idx].mem_bound_check_2bytes; @@ -271,21 +333,24 @@ JitReg get_mem_bound_check_4bytes_reg(JitFrame *frame, uint32 mem_idx) { JitCompContext *cc = frame->cc; - JitReg memory_inst_reg = get_memory_inst_reg(frame, mem_idx); + JitReg module_inst_reg = get_module_inst_reg(frame); + uint32 mem_bound_check_4bytes_offset = + (uint32)offsetof(WASMModuleInstance, global_table_data.bytes) + + (uint32)offsetof(WASMMemoryInstance, mem_bound_check_4bytes); + + bh_assert(mem_idx == 0); if (!frame->memory_regs[mem_idx].mem_bound_check_4bytes) { frame->memory_regs[mem_idx].mem_bound_check_4bytes = cc->memory_regs[mem_idx].mem_bound_check_4bytes; #if UINTPTR_MAX == UINT64_MAX GEN_INSN(LDI64, frame->memory_regs[mem_idx].mem_bound_check_4bytes, - memory_inst_reg, - NEW_CONST(I32, offsetof(WASMMemoryInstance, - mem_bound_check_4bytes))); + module_inst_reg, + NEW_CONST(I32, mem_bound_check_4bytes_offset)); #else GEN_INSN(LDI32, frame->memory_regs[mem_idx].mem_bound_check_4bytes, - memory_inst_reg, - NEW_CONST(I32, offsetof(WASMMemoryInstance, - mem_bound_check_4bytes))); + module_inst_reg, + NEW_CONST(I32, mem_bound_check_4bytes_offset)); #endif } return frame->memory_regs[mem_idx].mem_bound_check_4bytes; @@ -295,21 +360,24 @@ JitReg get_mem_bound_check_8bytes_reg(JitFrame *frame, uint32 mem_idx) { JitCompContext *cc = frame->cc; - JitReg memory_inst_reg = get_memory_inst_reg(frame, mem_idx); + JitReg module_inst_reg = get_module_inst_reg(frame); + uint32 mem_bound_check_8bytes_offset = + (uint32)offsetof(WASMModuleInstance, global_table_data.bytes) + + (uint32)offsetof(WASMMemoryInstance, mem_bound_check_8bytes); + + bh_assert(mem_idx == 0); if (!frame->memory_regs[mem_idx].mem_bound_check_8bytes) { frame->memory_regs[mem_idx].mem_bound_check_8bytes = cc->memory_regs[mem_idx].mem_bound_check_8bytes; #if UINTPTR_MAX == UINT64_MAX GEN_INSN(LDI64, frame->memory_regs[mem_idx].mem_bound_check_8bytes, - memory_inst_reg, - NEW_CONST(I32, offsetof(WASMMemoryInstance, - mem_bound_check_8bytes))); + module_inst_reg, + NEW_CONST(I32, mem_bound_check_8bytes_offset)); #else GEN_INSN(LDI32, frame->memory_regs[mem_idx].mem_bound_check_8bytes, - memory_inst_reg, - NEW_CONST(I32, offsetof(WASMMemoryInstance, - mem_bound_check_8bytes))); + module_inst_reg, + NEW_CONST(I32, mem_bound_check_8bytes_offset)); #endif } return frame->memory_regs[mem_idx].mem_bound_check_8bytes; @@ -319,81 +387,61 @@ JitReg get_mem_bound_check_16bytes_reg(JitFrame *frame, uint32 mem_idx) { JitCompContext *cc = frame->cc; - JitReg memory_inst_reg = get_memory_inst_reg(frame, mem_idx); + JitReg module_inst_reg = get_module_inst_reg(frame); + uint32 mem_bound_check_16bytes_offset = + (uint32)offsetof(WASMModuleInstance, global_table_data.bytes) + + (uint32)offsetof(WASMMemoryInstance, mem_bound_check_16bytes); + + bh_assert(mem_idx == 0); if (!frame->memory_regs[mem_idx].mem_bound_check_16bytes) { frame->memory_regs[mem_idx].mem_bound_check_16bytes = cc->memory_regs[mem_idx].mem_bound_check_16bytes; #if UINTPTR_MAX == UINT64_MAX GEN_INSN(LDI64, frame->memory_regs[mem_idx].mem_bound_check_16bytes, - memory_inst_reg, - NEW_CONST(I32, offsetof(WASMMemoryInstance, - mem_bound_check_16bytes))); + module_inst_reg, + NEW_CONST(I32, mem_bound_check_16bytes_offset)); #else GEN_INSN(LDI32, frame->memory_regs[mem_idx].mem_bound_check_16bytes, - memory_inst_reg, - NEW_CONST(I32, offsetof(WASMMemoryInstance, - mem_bound_check_16bytes))); + module_inst_reg, + NEW_CONST(I32, mem_bound_check_16bytes_offset)); #endif } return frame->memory_regs[mem_idx].mem_bound_check_16bytes; } JitReg -get_tables_reg(JitFrame *frame) -{ - JitCompContext *cc = frame->cc; - JitReg inst_reg = get_module_inst_reg(frame); - - if (!frame->tables_reg) { - frame->tables_reg = cc->tables_reg; - GEN_INSN(LDPTR, frame->tables_reg, inst_reg, - NEW_CONST(I32, offsetof(WASMModuleInstance, tables))); - } - return frame->tables_reg; -} - -JitReg -get_table_inst_reg(JitFrame *frame, uint32 tbl_idx) -{ - JitCompContext *cc = frame->cc; - JitReg tables_reg = get_tables_reg(frame); - - if (!frame->table_regs[tbl_idx].table_inst) { - frame->table_regs[tbl_idx].table_inst = - cc->table_regs[tbl_idx].table_inst; - GEN_INSN(LDPTR, frame->table_regs[tbl_idx].table_inst, tables_reg, - NEW_CONST(I32, sizeof(WASMTableInstance *) * tbl_idx)); - } - return frame->table_regs[tbl_idx].table_inst; -} - -JitReg -get_table_data_reg(JitFrame *frame, uint32 tbl_idx) +get_table_elems_reg(JitFrame *frame, uint32 tbl_idx) { JitCompContext *cc = frame->cc; - JitReg table_reg = get_table_inst_reg(frame, tbl_idx); - - if (!frame->table_regs[tbl_idx].table_data) { - frame->table_regs[tbl_idx].table_data = - cc->table_regs[tbl_idx].table_data; - GEN_INSN(ADD, frame->table_regs[tbl_idx].table_data, table_reg, - NEW_CONST(I64, offsetof(WASMTableInstance, base_addr))); + JitReg module_inst = get_module_inst_reg(frame); + uint32 offset = + jit_frontend_get_table_inst_offset(cc->cur_wasm_module, tbl_idx) + + (uint32)offsetof(WASMTableInstance, elems); + + if (!frame->table_regs[tbl_idx].table_elems) { + frame->table_regs[tbl_idx].table_elems = + cc->table_regs[tbl_idx].table_elems; + GEN_INSN(ADD, frame->table_regs[tbl_idx].table_elems, module_inst, + NEW_CONST(PTR, offset)); } - return frame->table_regs[tbl_idx].table_data; + return frame->table_regs[tbl_idx].table_elems; } JitReg get_table_cur_size_reg(JitFrame *frame, uint32 tbl_idx) { JitCompContext *cc = frame->cc; - JitReg table_reg = get_table_inst_reg(frame, tbl_idx); + JitReg module_inst = get_module_inst_reg(frame); + uint32 offset = + jit_frontend_get_table_inst_offset(cc->cur_wasm_module, tbl_idx) + + (uint32)offsetof(WASMTableInstance, cur_size); if (!frame->table_regs[tbl_idx].table_cur_size) { frame->table_regs[tbl_idx].table_cur_size = cc->table_regs[tbl_idx].table_cur_size; - GEN_INSN(LDI32, frame->table_regs[tbl_idx].table_cur_size, table_reg, - NEW_CONST(I32, offsetof(WASMTableInstance, cur_size))); + GEN_INSN(LDI32, frame->table_regs[tbl_idx].table_cur_size, module_inst, + NEW_CONST(I32, offset)); } return frame->table_regs[tbl_idx].table_cur_size; } @@ -409,15 +457,11 @@ clear_fixed_virtual_regs(JitFrame *frame) frame->import_func_ptrs_reg = 0; frame->fast_jit_func_ptrs_reg = 0; frame->func_type_indexes_reg = 0; - frame->global_data_reg = 0; frame->aux_stack_bound_reg = 0; frame->aux_stack_bottom_reg = 0; - frame->memories_reg = 0; - frame->tables_reg = 0; count = module->import_memory_count + module->memory_count; for (i = 0; i < count; i++) { - frame->memory_regs[i].memory_inst = 0; frame->memory_regs[i].memory_data = 0; frame->memory_regs[i].memory_data_end = 0; frame->memory_regs[i].mem_bound_check_1byte = 0; @@ -429,8 +473,7 @@ clear_fixed_virtual_regs(JitFrame *frame) count = module->import_table_count + module->table_count; for (i = 0; i < count; i++) { - frame->table_regs[i].table_inst = 0; - frame->table_regs[i].table_data = 0; + frame->table_regs[i].table_elems = 0; frame->table_regs[i].table_cur_size = 0; } } @@ -586,15 +629,6 @@ gen_commit_sp_ip(JitFrame *frame) #endif } -static void -jit_set_exception_with_id(WASMModuleInstance *module_inst, uint32 id) -{ - if (id < JIT_EXCE_NUM) - wasm_set_exception(module_inst, jit_exception_msgs[id]); - else - wasm_set_exception(module_inst, "unknown exception"); -} - static bool create_fixed_virtual_regs(JitCompContext *cc) { @@ -607,11 +641,8 @@ create_fixed_virtual_regs(JitCompContext *cc) cc->import_func_ptrs_reg = jit_cc_new_reg_ptr(cc); cc->fast_jit_func_ptrs_reg = jit_cc_new_reg_ptr(cc); cc->func_type_indexes_reg = jit_cc_new_reg_ptr(cc); - cc->global_data_reg = jit_cc_new_reg_ptr(cc); cc->aux_stack_bound_reg = jit_cc_new_reg_I32(cc); cc->aux_stack_bottom_reg = jit_cc_new_reg_I32(cc); - cc->memories_reg = jit_cc_new_reg_ptr(cc); - cc->tables_reg = jit_cc_new_reg_ptr(cc); count = module->import_memory_count + module->memory_count; if (count > 0) { @@ -623,7 +654,6 @@ create_fixed_virtual_regs(JitCompContext *cc) } for (i = 0; i < count; i++) { - cc->memory_regs[i].memory_inst = jit_cc_new_reg_ptr(cc); cc->memory_regs[i].memory_data = jit_cc_new_reg_ptr(cc); cc->memory_regs[i].memory_data_end = jit_cc_new_reg_ptr(cc); cc->memory_regs[i].mem_bound_check_1byte = jit_cc_new_reg_ptr(cc); @@ -644,8 +674,7 @@ create_fixed_virtual_regs(JitCompContext *cc) } for (i = 0; i < count; i++) { - cc->table_regs[i].table_inst = jit_cc_new_reg_ptr(cc); - cc->table_regs[i].table_data = jit_cc_new_reg_ptr(cc); + cc->table_regs[i].table_elems = jit_cc_new_reg_ptr(cc); cc->table_regs[i].table_cur_size = jit_cc_new_reg_I32(cc); } } @@ -681,7 +710,7 @@ form_and_translate_func(JitCompContext *cc) jit_basic_block_append_insn(jit_cc_entry_basic_block(cc), insn); /* Patch INSNs jumping to exception basic blocks. */ - for (i = 0; i < JIT_EXCE_NUM; i++) { + for (i = 0; i < EXCE_NUM; i++) { incoming_insn = cc->incoming_insns_for_exec_bbs[i]; if (incoming_insn) { if (!(cc->exce_basic_blocks[i] = jit_cc_new_basic_block(cc, 0))) { @@ -703,7 +732,7 @@ form_and_translate_func(JitCompContext *cc) incoming_insn = incoming_insn_next; } cc->cur_basic_block = cc->exce_basic_blocks[i]; - if (i != JIT_EXCE_ALREADY_THROWN) { + if (i != EXCE_ALREADY_THROWN) { JitReg module_inst_reg = jit_cc_new_reg_ptr(cc); GEN_INSN(LDPTR, module_inst_reg, cc->exec_env_reg, NEW_CONST(I32, offsetof(WASMExecEnv, module_inst))); @@ -775,6 +804,13 @@ init_func_translation(JitCompContext *cc) uint32 frame_size, outs_size, local_size, count; uint32 i, local_off; uint64 total_size; +#if WASM_ENABLE_DUMP_CALL_STACK != 0 || WASM_ENABLE_PERF_PROFILING != 0 + JitReg module_inst, func_inst; + uint32 func_insts_offset; +#if WASM_ENABLE_PERF_PROFILING != 0 + JitReg time_started; +#endif +#endif if ((uint64)max_locals + (uint64)max_stacks >= UINT32_MAX || total_cell_num >= UINT32_MAX @@ -824,7 +860,7 @@ init_func_translation(JitCompContext *cc) cc->spill_cache_offset = wasm_interp_interp_frame_size(total_cell_num); /* Set spill cache size according to max local cell num, max stack cell num and virtual fixed register num */ - cc->spill_cache_size = (max_locals + max_stacks) * 4 + sizeof(void *) * 4; + cc->spill_cache_size = (max_locals + max_stacks) * 4 + sizeof(void *) * 16; cc->total_frame_size = cc->spill_cache_offset + cc->spill_cache_size; cc->jitted_return_address_offset = offsetof(WASMInterpFrame, jitted_return_addr); @@ -840,6 +876,21 @@ init_func_translation(JitCompContext *cc) frame_boundary = jit_cc_new_reg_ptr(cc); frame_sp = jit_cc_new_reg_ptr(cc); +#if WASM_ENABLE_DUMP_CALL_STACK != 0 || WASM_ENABLE_PERF_PROFILING != 0 + module_inst = jit_cc_new_reg_ptr(cc); + func_inst = jit_cc_new_reg_ptr(cc); +#if WASM_ENABLE_PERF_PROFILING != 0 + time_started = jit_cc_new_reg_I64(cc); + /* Call os_time_get_boot_microsecond() to get time_started firstly + as there is stack frame switching below, calling native in them + may cause register spilling work inproperly */ + if (!jit_emit_callnative(cc, os_time_get_boot_microsecond, time_started, + NULL, 0)) { + return NULL; + } +#endif +#endif + /* top = exec_env->wasm_stack.s.top */ GEN_INSN(LDPTR, top, cc->exec_env_reg, NEW_CONST(I32, offsetof(WASMExecEnv, wasm_stack.s.top))); @@ -850,7 +901,7 @@ init_func_translation(JitCompContext *cc) GEN_INSN(ADD, frame_boundary, top, NEW_CONST(PTR, frame_size + outs_size)); /* if frame_boundary > top_boundary, throw stack overflow exception */ GEN_INSN(CMP, cc->cmp_reg, frame_boundary, top_boundary); - if (!jit_emit_exception(cc, JIT_EXCE_OPERAND_STACK_OVERFLOW, JIT_OP_BGTU, + if (!jit_emit_exception(cc, EXCE_OPERAND_STACK_OVERFLOW, JIT_OP_BGTU, cc->cmp_reg, NULL)) { return NULL; } @@ -870,11 +921,28 @@ init_func_translation(JitCompContext *cc) /* frame->prev_frame = fp_reg */ GEN_INSN(STPTR, cc->fp_reg, top, NEW_CONST(I32, offsetof(WASMInterpFrame, prev_frame))); - /* TODO: do we need to set frame->function? */ - /* +#if WASM_ENABLE_DUMP_CALL_STACK != 0 || WASM_ENABLE_PERF_PROFILING != 0 + /* module_inst = exec_env->module_inst */ + GEN_INSN(LDPTR, module_inst, cc->exec_env_reg, + NEW_CONST(I32, offsetof(WASMExecEnv, module_inst))); + func_insts_offset = + jit_frontend_get_module_inst_extra_offset(cur_wasm_module) + + (uint32)offsetof(WASMModuleInstanceExtra, functions); + /* func_inst = module_inst->e->functions */ + GEN_INSN(LDPTR, func_inst, module_inst, NEW_CONST(I32, func_insts_offset)); + /* func_inst = func_inst + cur_wasm_func_idx */ + GEN_INSN(ADD, func_inst, func_inst, + NEW_CONST(PTR, (uint32)sizeof(WASMFunctionInstance) + * cur_wasm_func_idx)); + /* frame->function = func_inst */ GEN_INSN(STPTR, func_inst, top, NEW_CONST(I32, offsetof(WASMInterpFrame, function))); - */ +#if WASM_ENABLE_PERF_PROFILING != 0 + /* frame->time_started = time_started */ + GEN_INSN(STI64, time_started, top, + NEW_CONST(I32, offsetof(WASMInterpFrame, time_started))); +#endif +#endif /* exec_env->cur_frame = top */ GEN_INSN(STPTR, top, cc->exec_env_reg, NEW_CONST(I32, offsetof(WASMExecEnv, cur_frame))); @@ -1029,6 +1097,39 @@ read_leb(JitCompContext *cc, const uint8 *buf, const uint8 *buf_end, res = (int64)res64; \ } while (0) +#if WASM_ENABLE_SHARED_MEMORY != 0 +#define COMPILE_ATOMIC_RMW(OP, NAME) \ + case WASM_OP_ATOMIC_RMW_I32_##NAME: \ + bytes = 4; \ + op_type = VALUE_TYPE_I32; \ + goto OP_ATOMIC_##OP; \ + case WASM_OP_ATOMIC_RMW_I64_##NAME: \ + bytes = 8; \ + op_type = VALUE_TYPE_I64; \ + goto OP_ATOMIC_##OP; \ + case WASM_OP_ATOMIC_RMW_I32_##NAME##8_U: \ + bytes = 1; \ + op_type = VALUE_TYPE_I32; \ + goto OP_ATOMIC_##OP; \ + case WASM_OP_ATOMIC_RMW_I32_##NAME##16_U: \ + bytes = 2; \ + op_type = VALUE_TYPE_I32; \ + goto OP_ATOMIC_##OP; \ + case WASM_OP_ATOMIC_RMW_I64_##NAME##8_U: \ + bytes = 1; \ + op_type = VALUE_TYPE_I64; \ + goto OP_ATOMIC_##OP; \ + case WASM_OP_ATOMIC_RMW_I64_##NAME##16_U: \ + bytes = 2; \ + op_type = VALUE_TYPE_I64; \ + goto OP_ATOMIC_##OP; \ + case WASM_OP_ATOMIC_RMW_I64_##NAME##32_U: \ + bytes = 4; \ + op_type = VALUE_TYPE_I64; \ + OP_ATOMIC_##OP : bin_op = AtomicRMWBinOp##OP; \ + goto build_atomic_rmw; +#endif + static bool jit_compile_func(JitCompContext *cc) { @@ -1237,11 +1338,8 @@ jit_compile_func(JitCompContext *cc) #if WASM_ENABLE_TAIL_CALL != 0 case WASM_OP_RETURN_CALL: - if (!cc->enable_tail_call) { - jit_set_last_error(cc, "unsupported opcode"); - return false; - } read_leb_uint32(frame_ip, frame_ip_end, func_idx); + if (!jit_compile_op_call(cc, func_idx, true)) return false; if (!jit_compile_op_return(cc, &frame_ip)) @@ -1252,11 +1350,6 @@ jit_compile_func(JitCompContext *cc) { uint32 tbl_idx; - if (!cc->enable_tail_call) { - jit_set_last_error(cc, "unsupported opcode"); - return false; - } - read_leb_uint32(frame_ip, frame_ip_end, type_idx); #if WASM_ENABLE_REF_TYPES != 0 read_leb_uint32(frame_ip, frame_ip_end, tbl_idx); @@ -2055,6 +2148,8 @@ jit_compile_func(JitCompContext *cc) case WASM_OP_ATOMIC_FENCE: /* Skip memory index */ frame_ip++; + if (!jit_compiler_op_atomic_fence(cc)) + return false; break; case WASM_OP_ATOMIC_I32_LOAD: bytes = 4; @@ -2151,15 +2246,12 @@ jit_compile_func(JitCompContext *cc) return false; break; - /* TODO */ - /* COMPILE_ATOMIC_RMW(Add, ADD); COMPILE_ATOMIC_RMW(Sub, SUB); COMPILE_ATOMIC_RMW(And, AND); COMPILE_ATOMIC_RMW(Or, OR); COMPILE_ATOMIC_RMW(Xor, XOR); COMPILE_ATOMIC_RMW(Xchg, XCHG); - */ build_atomic_rmw: if (!jit_compile_op_atomic_rmw(cc, bin_op, op_type, @@ -2214,6 +2306,12 @@ jit_frontend_translate_func(JitCompContext *cc) return basic_block_entry; } +uint32 +jit_frontend_get_jitted_return_addr_offset() +{ + return (uint32)offsetof(WASMInterpFrame, jitted_return_addr); +} + #if 0 #if WASM_ENABLE_THREAD_MGR != 0 bool diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/jit_frontend.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/jit_frontend.h similarity index 86% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/jit_frontend.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/jit_frontend.h index eeecf48fbdc..7aa460fd9b3 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/jit_frontend.h +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/jit_frontend.h @@ -13,6 +13,10 @@ #include "../aot/aot_runtime.h" #endif +#ifdef __cplusplus +extern "C" { +#endif + #if WASM_ENABLE_AOT == 0 typedef enum IntCond { INT_EQZ = 0, @@ -104,27 +108,16 @@ typedef enum FloatArithmetic { FLOAT_MAX, } FloatArithmetic; -typedef enum JitExceptionID { - JIT_EXCE_UNREACHABLE = 0, - JIT_EXCE_OUT_OF_MEMORY, - JIT_EXCE_OUT_OF_BOUNDS_MEMORY_ACCESS, - JIT_EXCE_INTEGER_OVERFLOW, - JIT_EXCE_INTEGER_DIVIDE_BY_ZERO, - JIT_EXCE_INVALID_CONVERSION_TO_INTEGER, - JIT_EXCE_INVALID_FUNCTION_TYPE_INDEX, - JIT_EXCE_INVALID_FUNCTION_INDEX, - JIT_EXCE_UNDEFINED_ELEMENT, - JIT_EXCE_UNINITIALIZED_ELEMENT, - JIT_EXCE_CALL_UNLINKED_IMPORT_FUNC, - JIT_EXCE_NATIVE_STACK_OVERFLOW, - JIT_EXCE_UNALIGNED_ATOMIC, - JIT_EXCE_AUX_STACK_OVERFLOW, - JIT_EXCE_AUX_STACK_UNDERFLOW, - JIT_EXCE_OUT_OF_BOUNDS_TABLE_ACCESS, - JIT_EXCE_OPERAND_STACK_OVERFLOW, - JIT_EXCE_ALREADY_THROWN, - JIT_EXCE_NUM, -} JitExceptionID; +#if WASM_ENABLE_SHARED_MEMORY != 0 +typedef enum AtomicRMWBinOp { + AtomicRMWBinOpAdd, + AtomicRMWBinOpSub, + AtomicRMWBinOpAnd, + AtomicRMWBinOpOr, + AtomicRMWBinOpXor, + AtomicRMWBinOpXchg +} AtomicRMWBinOp; +#endif /** * Translate instructions in a function. The translated block must @@ -155,22 +148,6 @@ typedef enum JitExceptionID { JitBasicBlock * jit_frontend_translate_func(JitCompContext *cc); -/** - * Generate a block leaving the compiled code, which must store the - * target bcip and other necessary information for switching to - * interpreter or other compiled code and then jump to the exit of the - * cc. - * - * @param cc the compilation context - * @param bcip the target bytecode instruction pointer - * @param sp_offset stack pointer offset at the beginning of the block - * - * @return the leaving block if succeeds, NULL otherwise - */ -JitBlock * -jit_frontend_gen_leaving_block(JitCompContext *cc, void *bcip, - unsigned sp_offset); - /** * Lower the IR of the given compilation context. * @@ -181,6 +158,19 @@ jit_frontend_gen_leaving_block(JitCompContext *cc, void *bcip, bool jit_frontend_lower(JitCompContext *cc); +uint32 +jit_frontend_get_jitted_return_addr_offset(); + +uint32 +jit_frontend_get_global_data_offset(const WASMModule *module, + uint32 global_idx); + +uint32 +jit_frontend_get_table_inst_offset(const WASMModule *module, uint32 tbl_idx); + +uint32 +jit_frontend_get_module_inst_extra_offset(const WASMModule *module); + JitReg get_module_inst_reg(JitFrame *frame); @@ -196,21 +186,12 @@ get_fast_jit_func_ptrs_reg(JitFrame *frame); JitReg get_func_type_indexes_reg(JitFrame *frame); -JitReg -get_global_data_reg(JitFrame *frame); - JitReg get_aux_stack_bound_reg(JitFrame *frame); JitReg get_aux_stack_bottom_reg(JitFrame *frame); -JitReg -get_memories_reg(JitFrame *frame); - -JitReg -get_memory_inst_reg(JitFrame *frame, uint32 mem_idx); - JitReg get_memory_data_reg(JitFrame *frame, uint32 mem_idx); @@ -233,13 +214,7 @@ JitReg get_mem_bound_check_16bytes_reg(JitFrame *frame, uint32 mem_idx); JitReg -get_tables_reg(JitFrame *frame); - -JitReg -get_table_inst_reg(JitFrame *frame, uint32 table_idx); - -JitReg -get_table_data_reg(JitFrame *frame, uint32 table_idx); +get_table_elems_reg(JitFrame *frame, uint32 table_idx); JitReg get_table_cur_size_reg(JitFrame *frame, uint32 table_idx); @@ -526,4 +501,8 @@ set_local_f64(JitFrame *frame, int n, JitReg val) #define PUSH_FUNCREF(v) PUSH(v, VALUE_TYPE_FUNCREF) #define PUSH_EXTERNREF(v) PUSH(v, VALUE_TYPE_EXTERNREF) +#ifdef __cplusplus +} +#endif + #endif diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/jit_ir.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/jit_ir.c similarity index 98% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/jit_ir.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/jit_ir.c index 6efc2effc46..68503e3f5f3 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/jit_ir.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/jit_ir.c @@ -10,7 +10,11 @@ /** * Operand kinds of instructions. */ -enum { JIT_OPND_KIND_Reg, JIT_OPND_KIND_VReg, JIT_OPND_KIND_LookupSwitch }; +enum { + JIT_OPND_KIND_Reg, + JIT_OPND_KIND_VReg, + JIT_OPND_KIND_LookupSwitch, +}; /** * Operand kind of each instruction. @@ -45,6 +49,18 @@ static const uint8 insn_opnd_first_use[] = { jit_calloc(offsetof(JitInsn, _opnd._opnd_VReg._reg) \ + sizeof(JitReg) * (OPND_NUM)) +JitInsn * +_jit_insn_new_Reg_0(JitOpcode opc) +{ + JitInsn *insn = JIT_INSN_NEW_Reg(0); + + if (insn) { + insn->opcode = opc; + } + + return insn; +} + JitInsn * _jit_insn_new_Reg_1(JitOpcode opc, JitReg r0) { @@ -382,6 +398,7 @@ jit_cc_init(JitCompContext *cc, unsigned htab_size) blocks respectively. */ if (!(entry_block = jit_cc_new_basic_block(cc, 0))) goto fail; + if (!(exit_block = jit_cc_new_basic_block(cc, 0))) { jit_basic_block_delete(entry_block); goto fail; @@ -395,11 +412,11 @@ jit_cc_init(JitCompContext *cc, unsigned htab_size) && jit_reg_no(cc->exit_label) == 1); if (!(cc->exce_basic_blocks = - jit_calloc(sizeof(JitBasicBlock *) * JIT_EXCE_NUM))) + jit_calloc(sizeof(JitBasicBlock *) * EXCE_NUM))) goto fail; if (!(cc->incoming_insns_for_exec_bbs = - jit_calloc(sizeof(JitIncomingInsnList) * JIT_EXCE_NUM))) + jit_calloc(sizeof(JitIncomingInsnList) * EXCE_NUM))) goto fail; cc->hreg_info = jit_codegen_get_hreg_info(); @@ -465,7 +482,7 @@ jit_cc_destroy(JitCompContext *cc) jit_free(cc->exce_basic_blocks); if (cc->incoming_insns_for_exec_bbs) { - for (i = 0; i < JIT_EXCE_NUM; i++) { + for (i = 0; i < EXCE_NUM; i++) { incoming_insn = cc->incoming_insns_for_exec_bbs[i]; while (incoming_insn) { incoming_insn_next = incoming_insn->next; @@ -559,6 +576,7 @@ address_of_const(JitCompContext *cc, JitReg reg, unsigned size) unsigned no = jit_reg_no(reg); unsigned idx = no & ~_JIT_REG_CONST_IDX_FLAG; + bh_assert(kind < JIT_REG_KIND_L32); bh_assert(jit_reg_is_const_idx(reg) && idx < cc->_const_val._num[kind]); return cc->_const_val._value[kind] + size * idx; @@ -571,6 +589,7 @@ next_of_const(JitCompContext *cc, JitReg reg) unsigned no = jit_reg_no(reg); unsigned idx = no & ~_JIT_REG_CONST_IDX_FLAG; + bh_assert(kind < JIT_REG_KIND_L32); bh_assert(jit_reg_is_const_idx(reg) && idx < cc->_const_val._num[kind]); return cc->_const_val._next[kind][idx]; diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/jit_ir.def b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/jit_ir.def similarity index 86% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/jit_ir.def rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/jit_ir.def index d16843328f5..046bea1ff58 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/jit_ir.def +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/jit_ir.def @@ -196,10 +196,54 @@ INSN(LOOKUPSWITCH, LookupSwitch, 1, 0) /* Call and return instructions */ INSN(CALLNATIVE, VReg, 2, 1) -INSN(CALLBC, Reg, 3, 2) +INSN(CALLBC, Reg, 4, 2) INSN(RETURNBC, Reg, 3, 0) INSN(RETURN, Reg, 1, 0) +#if WASM_ENABLE_SHARED_MEMORY != 0 +/* Atomic Memory Accesses */ +/* op1(replacement val) op2(expected val) op3(mem data) op4(offset) + * and in x86, the result is stored in register al/ax/eax/rax */ +INSN(AT_CMPXCHGU8, Reg, 4, 0) +INSN(AT_CMPXCHGU16, Reg, 4, 0) +INSN(AT_CMPXCHGI32, Reg, 4, 0) +INSN(AT_CMPXCHGU32, Reg, 4, 0) +INSN(AT_CMPXCHGI64, Reg, 4, 0) +/* rmw operations: + * op1(read value) op2(operand value) op3(mem data) op4(offset) */ +INSN(AT_ADDU8, Reg, 4, 1) +INSN(AT_ADDU16, Reg, 4, 1) +INSN(AT_ADDI32, Reg, 4, 1) +INSN(AT_ADDU32, Reg, 4, 1) +INSN(AT_ADDI64, Reg, 4, 1) +INSN(AT_SUBU8, Reg, 4, 1) +INSN(AT_SUBU16, Reg, 4, 1) +INSN(AT_SUBI32, Reg, 4, 1) +INSN(AT_SUBU32, Reg, 4, 1) +INSN(AT_SUBI64, Reg, 4, 1) +INSN(AT_ANDU8, Reg, 4, 1) +INSN(AT_ANDU16, Reg, 4, 1) +INSN(AT_ANDI32, Reg, 4, 1) +INSN(AT_ANDU32, Reg, 4, 1) +INSN(AT_ANDI64, Reg, 4, 1) +INSN(AT_ORU8, Reg, 4, 1) +INSN(AT_ORU16, Reg, 4, 1) +INSN(AT_ORI32, Reg, 4, 1) +INSN(AT_ORU32, Reg, 4, 1) +INSN(AT_ORI64, Reg, 4, 1) +INSN(AT_XORU8, Reg, 4, 1) +INSN(AT_XORU16, Reg, 4, 1) +INSN(AT_XORI32, Reg, 4, 1) +INSN(AT_XORU32, Reg, 4, 1) +INSN(AT_XORI64, Reg, 4, 1) +INSN(AT_XCHGU8, Reg, 4, 1) +INSN(AT_XCHGU16, Reg, 4, 1) +INSN(AT_XCHGI32, Reg, 4, 1) +INSN(AT_XCHGU32, Reg, 4, 1) +INSN(AT_XCHGI64, Reg, 4, 1) +INSN(FENCE, Reg, 0, 0) +#endif + #undef INSN /** diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/jit_ir.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/jit_ir.h similarity index 97% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/jit_ir.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/jit_ir.h index b00694fc021..e13a41d1d21 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/jit_ir.h +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/jit_ir.h @@ -313,7 +313,8 @@ typedef struct JitInsn { /* Opcode of the instruction. */ uint16 opcode; - /* Reserved field that may be used by optimizations locally. */ + /* Reserved field that may be used by optimizations locally. + * bit_0(Least Significant Bit) is atomic flag for load/store */ uint8 flags_u8; /* The unique ID of the instruction. */ @@ -346,6 +347,9 @@ typedef enum JitOpcode { * Helper functions for creating new instructions. Don't call them * directly. Use jit_insn_new_NAME, such as jit_insn_new_MOV instead. */ + +JitInsn * +_jit_insn_new_Reg_0(JitOpcode opc); JitInsn * _jit_insn_new_Reg_1(JitOpcode opc, JitReg r0); JitInsn * @@ -368,31 +372,35 @@ _jit_insn_new_LookupSwitch_1(JitOpcode opc, JitReg value, uint32 num); * Instruction creation functions jit_insn_new_NAME, where NAME is the * name of the instruction defined in jit_ir.def. */ +#define ARG_DECL_Reg_0 +#define ARG_LIST_Reg_0 #define ARG_DECL_Reg_1 JitReg r0 -#define ARG_LIST_Reg_1 r0 +#define ARG_LIST_Reg_1 , r0 #define ARG_DECL_Reg_2 JitReg r0, JitReg r1 -#define ARG_LIST_Reg_2 r0, r1 +#define ARG_LIST_Reg_2 , r0, r1 #define ARG_DECL_Reg_3 JitReg r0, JitReg r1, JitReg r2 -#define ARG_LIST_Reg_3 r0, r1, r2 +#define ARG_LIST_Reg_3 , r0, r1, r2 #define ARG_DECL_Reg_4 JitReg r0, JitReg r1, JitReg r2, JitReg r3 -#define ARG_LIST_Reg_4 r0, r1, r2, r3 +#define ARG_LIST_Reg_4 , r0, r1, r2, r3 #define ARG_DECL_Reg_5 JitReg r0, JitReg r1, JitReg r2, JitReg r3, JitReg r4 -#define ARG_LIST_Reg_5 r0, r1, r2, r3, r4 +#define ARG_LIST_Reg_5 , r0, r1, r2, r3, r4 #define ARG_DECL_VReg_1 JitReg r0, int n -#define ARG_LIST_VReg_1 r0, n +#define ARG_LIST_VReg_1 , r0, n #define ARG_DECL_VReg_2 JitReg r0, JitReg r1, int n -#define ARG_LIST_VReg_2 r0, r1, n +#define ARG_LIST_VReg_2 , r0, r1, n #define ARG_DECL_LookupSwitch_1 JitReg value, uint32 num -#define ARG_LIST_LookupSwitch_1 value, num -#define INSN(NAME, OPND_KIND, OPND_NUM, FIRST_USE) \ - static inline JitInsn *jit_insn_new_##NAME( \ - ARG_DECL_##OPND_KIND##_##OPND_NUM) \ - { \ - return _jit_insn_new_##OPND_KIND##_##OPND_NUM( \ - JIT_OP_##NAME, ARG_LIST_##OPND_KIND##_##OPND_NUM); \ +#define ARG_LIST_LookupSwitch_1 , value, num +#define INSN(NAME, OPND_KIND, OPND_NUM, FIRST_USE) \ + static inline JitInsn *jit_insn_new_##NAME( \ + ARG_DECL_##OPND_KIND##_##OPND_NUM) \ + { \ + return _jit_insn_new_##OPND_KIND##_##OPND_NUM( \ + JIT_OP_##NAME ARG_LIST_##OPND_KIND##_##OPND_NUM); \ } #include "jit_ir.def" #undef INSN +#undef ARG_DECL_Reg_0 +#undef ARG_LIST_Reg_0 #undef ARG_DECL_Reg_1 #undef ARG_LIST_Reg_1 #undef ARG_DECL_Reg_2 @@ -856,7 +864,6 @@ typedef struct JitValueSlot { } JitValueSlot; typedef struct JitMemRegs { - JitReg memory_inst; /* The following registers should be re-loaded after memory.grow, callbc and callnative */ JitReg memory_data; @@ -869,8 +876,7 @@ typedef struct JitMemRegs { } JitMemRegs; typedef struct JitTableRegs { - JitReg table_inst; - JitReg table_data; + JitReg table_elems; /* Should be re-loaded after table.grow, callbc and callnative */ JitReg table_cur_size; @@ -915,18 +921,12 @@ typedef struct JitFrame { JitReg fast_jit_func_ptrs_reg; /* module_inst->func_type_indexes */ JitReg func_type_indexes_reg; - /* Base address of global data */ - JitReg global_data_reg; /* Boundary of auxiliary stack */ JitReg aux_stack_bound_reg; /* Bottom of auxiliary stack */ JitReg aux_stack_bottom_reg; - /* Memory instances */ - JitReg memories_reg; /* Data of memory instances */ JitMemRegs *memory_regs; - /* Table instances */ - JitReg tables_reg; /* Data of table instances */ JitTableRegs *table_regs; @@ -1037,18 +1037,12 @@ typedef struct JitCompContext { JitReg fast_jit_func_ptrs_reg; /* module_inst->func_type_indexes */ JitReg func_type_indexes_reg; - /* Base address of global data */ - JitReg global_data_reg; /* Boundary of auxiliary stack */ JitReg aux_stack_bound_reg; /* Bottom of auxiliary stack */ JitReg aux_stack_bottom_reg; - /* Memory instances */ - JitReg memories_reg; /* Data of memory instances */ JitMemRegs *memory_regs; - /* Table instances */ - JitReg tables_reg; /* Data of table instances */ JitTableRegs *table_regs; @@ -1702,6 +1696,7 @@ jit_cc_is_hreg(JitCompContext *cc, JitReg reg) unsigned kind = jit_reg_kind(reg); unsigned no = jit_reg_no(reg); bh_assert(jit_reg_is_variable(reg)); + bh_assert(kind < JIT_REG_KIND_L32); return no < cc->hreg_info->info[kind].num; } @@ -1719,6 +1714,7 @@ jit_cc_is_hreg_fixed(JitCompContext *cc, JitReg reg) unsigned kind = jit_reg_kind(reg); unsigned no = jit_reg_no(reg); bh_assert(jit_cc_is_hreg(cc, reg)); + bh_assert(kind < JIT_REG_KIND_L32); return !!cc->hreg_info->info[kind].fixed[no]; } @@ -1736,6 +1732,7 @@ jit_cc_is_hreg_caller_saved_native(JitCompContext *cc, JitReg reg) unsigned kind = jit_reg_kind(reg); unsigned no = jit_reg_no(reg); bh_assert(jit_cc_is_hreg(cc, reg)); + bh_assert(kind < JIT_REG_KIND_L32); return !!cc->hreg_info->info[kind].caller_saved_native[no]; } @@ -1753,6 +1750,7 @@ jit_cc_is_hreg_caller_saved_jitted(JitCompContext *cc, JitReg reg) unsigned kind = jit_reg_kind(reg); unsigned no = jit_reg_no(reg); bh_assert(jit_cc_is_hreg(cc, reg)); + bh_assert(kind < JIT_REG_KIND_L32); return !!cc->hreg_info->info[kind].caller_saved_jitted[no]; } diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/jit_regalloc.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/jit_regalloc.c similarity index 96% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/jit_regalloc.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/jit_regalloc.c index 415b9e4b844..70ca228acfb 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/jit_regalloc.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/jit_regalloc.c @@ -156,6 +156,7 @@ rc_get_vr(RegallocContext *rc, JitReg vreg) unsigned no = jit_reg_no(vreg); bh_assert(jit_reg_is_variable(vreg)); + bh_assert(kind < JIT_REG_KIND_L32); return &rc->vregs[kind][no]; } @@ -175,6 +176,7 @@ rc_get_hr(RegallocContext *rc, JitReg hreg) unsigned no = jit_reg_no(hreg); bh_assert(jit_reg_is_variable(hreg) && jit_cc_is_hreg(rc->cc, hreg)); + bh_assert(kind < JIT_REG_KIND_L32); return &rc->hregs[kind][no]; } @@ -208,7 +210,9 @@ static unsigned get_reg_stride(JitReg reg) { static const uint8 strides[] = { 0, 1, 2, 1, 2, 2, 4, 8, 0 }; - return strides[jit_reg_kind(reg)]; + uint32 kind = jit_reg_kind(reg); + bh_assert(kind <= JIT_REG_KIND_L32); + return strides[kind]; } /** @@ -406,6 +410,13 @@ collect_distances(RegallocContext *rc, JitBasicBlock *basic_block) JIT_FOREACH_INSN(basic_block, insn) { +#if WASM_ENABLE_SHARED_MEMORY != 0 + /* fence insn doesn't have any operand, hence, no regs involved */ + if (insn->opcode == JIT_OP_FENCE) { + continue; + } +#endif + JitRegVec regvec = jit_insn_opnd_regs(insn); unsigned i; JitReg *regp; @@ -582,13 +593,17 @@ static JitReg allocate_hreg(RegallocContext *rc, JitReg vreg, JitInsn *insn, int distance) { const int kind = jit_reg_kind(vreg); - const HardReg *hregs = rc->hregs[kind]; - const unsigned hreg_num = jit_cc_hreg_num(rc->cc, kind); + const HardReg *hregs; + unsigned hreg_num; JitReg hreg, vreg_to_reload = 0; int min_distance = distance, vr_distance; VirtualReg *vr = rc_get_vr(rc, vreg); unsigned i; + bh_assert(kind < JIT_REG_KIND_L32); + hregs = rc->hregs[kind]; + hreg_num = jit_cc_hreg_num(rc->cc, kind); + if (hreg_num == 0) /* Unsupported hard register kind. */ { @@ -729,6 +744,13 @@ allocate_for_basic_block(RegallocContext *rc, JitBasicBlock *basic_block, JIT_FOREACH_INSN_REVERSE(basic_block, insn) { +#if WASM_ENABLE_SHARED_MEMORY != 0 + /* fence insn doesn't have any operand, hence, no regs involved */ + if (insn->opcode == JIT_OP_FENCE) { + continue; + } +#endif + JitRegVec regvec = jit_insn_opnd_regs(insn); unsigned first_use = jit_insn_opnd_first_use(insn); unsigned i; diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/jit_utils.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/jit_utils.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/jit_utils.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/jit_utils.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/jit_utils.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/jit_utils.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/fast-jit/jit_utils.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/fast-jit/jit_utils.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/include/aot_export.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/include/aot_export.h similarity index 92% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/include/aot_export.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/include/aot_export.h index b6045439820..e58873bfd8b 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/include/aot_export.h +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/include/aot_export.h @@ -55,14 +55,23 @@ typedef struct AOTCompOption { bool enable_aux_stack_frame; bool disable_llvm_intrinsics; bool disable_llvm_lto; + bool enable_stack_estimation; uint32_t opt_level; uint32_t size_level; uint32_t output_format; uint32_t bounds_checks; + uint32_t stack_bounds_checks; char **custom_sections; uint32_t custom_sections_count; + const char *stack_usage_file; } AOTCompOption, *aot_comp_option_t; +bool +aot_compiler_init(void); + +void +aot_compiler_destroy(void); + aot_comp_context_t aot_create_comp_context(aot_comp_data_t comp_data, aot_comp_option_t option); diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/include/lib_export.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/include/lib_export.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/include/lib_export.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/include/lib_export.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/include/wasm_c_api.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/include/wasm_c_api.h similarity index 94% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/include/wasm_c_api.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/include/wasm_c_api.h index 1c9d6a183e4..324a43bd52d 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/include/wasm_c_api.h +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/include/wasm_c_api.h @@ -145,6 +145,19 @@ WASM_API_EXTERN own wasm_config_t* wasm_config_new(void); WASM_DECLARE_OWN(engine) +/** + * Create a new engine + * + * Note: for the engine new/delete operations, including this, + * wasm_engine_new_with_config, wasm_engine_new_with_args, and + * wasm_engine_delete, if the platform has mutex initializer, + * then they are thread-safe: we use a global lock to lock the + * operations of the engine. Otherwise they are not thread-safe: + * when there are engine new/delete operations happening + * simultaneously in multiple threads, developer must create + * the lock by himself, and add the lock when calling these + * functions. + */ WASM_API_EXTERN own wasm_engine_t* wasm_engine_new(void); WASM_API_EXTERN own wasm_engine_t* wasm_engine_new_with_config(own wasm_config_t*); @@ -173,6 +186,9 @@ typedef union MemAllocOption { void *malloc_func; void *realloc_func; void *free_func; + /* allocator user data, only used when + WASM_MEM_ALLOC_WITH_USER_DATA is defined */ + void *user_data; } allocator; } MemAllocOption; #endif @@ -338,6 +354,7 @@ WASM_API_EXTERN own wasm_importtype_t* wasm_importtype_new( WASM_API_EXTERN const wasm_name_t* wasm_importtype_module(const wasm_importtype_t*); WASM_API_EXTERN const wasm_name_t* wasm_importtype_name(const wasm_importtype_t*); WASM_API_EXTERN const wasm_externtype_t* wasm_importtype_type(const wasm_importtype_t*); +WASM_API_EXTERN bool wasm_importtype_is_linked(const wasm_importtype_t*); // Export Types @@ -451,6 +468,7 @@ struct WASMModuleCommon; typedef struct WASMModuleCommon *wasm_module_t; #endif + WASM_API_EXTERN own wasm_module_t* wasm_module_new( wasm_store_t*, const wasm_byte_vec_t* binary); @@ -461,9 +479,14 @@ WASM_API_EXTERN bool wasm_module_validate(wasm_store_t*, const wasm_byte_vec_t* WASM_API_EXTERN void wasm_module_imports(const wasm_module_t*, own wasm_importtype_vec_t* out); WASM_API_EXTERN void wasm_module_exports(const wasm_module_t*, own wasm_exporttype_vec_t* out); -WASM_API_EXTERN void wasm_module_serialize(const wasm_module_t*, own wasm_byte_vec_t* out); +WASM_API_EXTERN void wasm_module_serialize(wasm_module_t*, own wasm_byte_vec_t* out); WASM_API_EXTERN own wasm_module_t* wasm_module_deserialize(wasm_store_t*, const wasm_byte_vec_t*); +typedef wasm_module_t wasm_shared_module_t; +WASM_API_EXTERN own wasm_shared_module_t* wasm_module_share(wasm_module_t*); +WASM_API_EXTERN own wasm_module_t* wasm_module_obtain(wasm_store_t*, wasm_shared_module_t*); +WASM_API_EXTERN void wasm_shared_module_delete(own wasm_shared_module_t*); + // Function Instances @@ -573,13 +596,13 @@ WASM_DECLARE_REF(instance) WASM_API_EXTERN own wasm_instance_t* wasm_instance_new( wasm_store_t*, const wasm_module_t*, const wasm_extern_vec_t *imports, - own wasm_trap_t** + own wasm_trap_t** trap ); // please refer to wasm_runtime_instantiate(...) in core/iwasm/include/wasm_export.h WASM_API_EXTERN own wasm_instance_t* wasm_instance_new_with_args( wasm_store_t*, const wasm_module_t*, const wasm_extern_vec_t *imports, - own wasm_trap_t**, const uint32_t stack_size, const uint32_t heap_size + own wasm_trap_t** trap, const uint32_t stack_size, const uint32_t heap_size ); WASM_API_EXTERN void wasm_instance_exports(const wasm_instance_t*, own wasm_extern_vec_t* out); @@ -775,6 +798,9 @@ static inline void* wasm_val_ptr(const wasm_val_t* val) { #define KILOBYTE(n) ((n) * 1024) +// Create placeholders filled in `wasm_externvec_t* imports` for `wasm_instance_new()` +WASM_API_EXTERN wasm_extern_t *wasm_extern_new_empty(wasm_store_t *, wasm_externkind_t); + /////////////////////////////////////////////////////////////////////////////// #undef own diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/include/wasm_export.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/include/wasm_export.h similarity index 84% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/include/wasm_export.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/include/wasm_export.h index b08ebd88e9c..f6c0107b9ff 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/include/wasm_export.h +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/include/wasm_export.h @@ -117,6 +117,9 @@ typedef union MemAllocOption { void *malloc_func; void *realloc_func; void *free_func; + /* allocator user data, only used when + WASM_MEM_ALLOC_WITH_USER_DATA is defined */ + void *user_data; } allocator; } MemAllocOption; #endif @@ -128,6 +131,14 @@ typedef struct mem_alloc_info_t { uint32_t highmark_size; } mem_alloc_info_t; +/* Running mode of runtime and module instance*/ +typedef enum RunningMode { + Mode_Interp = 1, + Mode_Fast_JIT, + Mode_LLVM_JIT, + Mode_Multi_Tier_JIT, +} RunningMode; + /* WASM runtime initialize arguments */ typedef struct RuntimeInitArgs { mem_alloc_type_t mem_alloc_type; @@ -149,6 +160,13 @@ typedef struct RuntimeInitArgs { /* Fast JIT code cache size */ uint32_t fast_jit_code_cache_size; + + /* Default running mode of the runtime */ + RunningMode running_mode; + + /* LLVM JIT opt and size level */ + uint32_t llvm_jit_opt_level; + uint32_t llvm_jit_size_level; } RuntimeInitArgs; #ifndef WASM_VALKIND_T_DEFINED @@ -192,9 +210,9 @@ WASM_RUNTIME_API_EXTERN bool wasm_runtime_init(void); /** - * Initialize the WASM runtime environment, and also initialize - * the memory allocator and register native symbols, which are specified - * with init arguments + * Initialize the WASM runtime environment, WASM running mode, + * and also initialize the memory allocator and register native symbols, + * which are specified with init arguments * * @param init_args specifies the init arguments * @@ -203,6 +221,28 @@ wasm_runtime_init(void); WASM_RUNTIME_API_EXTERN bool wasm_runtime_full_init(RuntimeInitArgs *init_args); +/** + * Query whether a certain running mode is supported for the runtime + * + * @param running_mode the running mode to query + * + * @return true if this running mode is supported, false otherwise + */ +WASM_RUNTIME_API_EXTERN bool +wasm_runtime_is_running_mode_supported(RunningMode running_mode); + +/** + * Set the default running mode for the runtime. It is inherited + * to set the running mode of a module instance when it is instantiated, + * and can be changed by calling wasm_runtime_set_running_mode + * + * @param running_mode the running mode to set + * + * @return true if success, false otherwise + */ +WASM_RUNTIME_API_EXTERN bool +wasm_runtime_set_default_running_mode(RunningMode running_mode); + /** * Destroy the WASM runtime environment. */ @@ -357,6 +397,43 @@ wasm_runtime_load_from_sections(wasm_section_list_t section_list, bool is_aot, WASM_RUNTIME_API_EXTERN void wasm_runtime_unload(wasm_module_t module); +/** + * Get the module hash of a WASM module, currently only available on + * linux-sgx platform when the remote attestation feature is enabled + * + * @param module the WASM module to retrieve + * + * @return the module hash of the WASM module + */ +char * +wasm_runtime_get_module_hash(wasm_module_t module); + +/** + * Set WASI parameters. + * + * While this API operates on a module, these parameters will be used + * only when the module is instantiated. That is, you can consider these + * as extra parameters for wasm_runtime_instantiate(). + * + * @param module The module to set WASI parameters. + * @param dir_list The list of directories to preopen. (real path) + * @param dir_count The number of elements in dir_list. + * @param map_dir_list The list of directories to preopen. (mapped path) + * @param map_dir_count The number of elements in map_dir_list. + * If map_dir_count is smaller than dir_count, + * mapped path is assumed to be same as the + * corresponding real path for the rest of entries. + * @param env The list of environment variables. + * @param env_count The number of elements in env. + * @param argv The list of command line arguments. + * @param argc The number of elements in argv. + * @param stdinfd The host file descriptor to back WASI STDIN_FILENO. + * If -1 is specified, STDIN_FILENO is used. + * @param stdoutfd The host file descriptor to back WASI STDOUT_FILENO. + * If -1 is specified, STDOUT_FILENO is used. + * @param stderrfd The host file descriptor to back WASI STDERR_FILENO. + * If -1 is specified, STDERR_FILENO is used. + */ WASM_RUNTIME_API_EXTERN void wasm_runtime_set_wasi_args_ex(wasm_module_t module, const char *dir_list[], uint32_t dir_count, @@ -365,6 +442,12 @@ wasm_runtime_set_wasi_args_ex(wasm_module_t module, char *argv[], int argc, int stdinfd, int stdoutfd, int stderrfd); +/** + * Set WASI parameters. + * + * Same as wasm_runtime_set_wasi_args_ex with stdinfd = -1, stdoutfd = -1, + * stderrfd = -1. + */ WASM_RUNTIME_API_EXTERN void wasm_runtime_set_wasi_args(wasm_module_t module, const char *dir_list[], uint32_t dir_count, @@ -384,14 +467,14 @@ wasm_runtime_set_wasi_ns_lookup_pool(wasm_module_t module, const char *ns_lookup * Instantiate a WASM module. * * @param module the WASM module to instantiate - * @param stack_size the default stack size of the module instance when the + * @param default_stack_size the default stack size of the module instance when the * exec env's operation stack isn't created by user, e.g. API * wasm_application_execute_main() and wasm_application_execute_func() * create the operation stack internally with the stack size specified * here. And API wasm_runtime_create_exec_env() creates the operation * stack with stack size specified by its parameter, the stack size * specified here is ignored. - * @param heap_size the default heap size of the module instance, a heap will + * @param host_managed_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. * @param error_buf buffer to output the error info if failed @@ -401,9 +484,37 @@ wasm_runtime_set_wasi_ns_lookup_pool(wasm_module_t module, const char *ns_lookup */ WASM_RUNTIME_API_EXTERN wasm_module_inst_t wasm_runtime_instantiate(const wasm_module_t module, - uint32_t stack_size, uint32_t heap_size, + uint32_t default_stack_size, uint32_t host_managed_heap_size, char *error_buf, uint32_t error_buf_size); +/** + * Set the running mode of a WASM module instance, override the + * default running mode of the runtime. Note that it only makes sense when + * the input is a wasm bytecode file: for the AOT file, runtime always runs + * it with AOT engine, and this function always returns true. + * + * @param module_inst the WASM module instance to set running mode + * @param running_mode the running mode to set + * + * @return true if success, false otherwise + */ +WASM_RUNTIME_API_EXTERN bool +wasm_runtime_set_running_mode(wasm_module_inst_t module_inst, + RunningMode running_mode); + +/** + * Get the running mode of a WASM module instance, if no running mode + * is explicitly set the default running mode of runtime will + * be used and returned. Note that it only makes sense when the input is a + * wasm bytecode file: for the AOT file, this function always returns 0. + * + * @param module_inst the WASM module instance to query for running mode + * + * @return the running mode this module instance currently use + */ +WASM_RUNTIME_API_EXTERN RunningMode +wasm_runtime_get_running_mode(wasm_module_inst_t module_inst); + /** * Deinstantiate a WASM module instance, destroy the resources. * @@ -412,12 +523,34 @@ wasm_runtime_instantiate(const wasm_module_t module, WASM_RUNTIME_API_EXTERN void wasm_runtime_deinstantiate(wasm_module_inst_t module_inst); +/** + * Get WASM module from WASM module instance + * + * @param module_inst the WASM module instance to retrieve + * + * @return the WASM module + */ +WASM_RUNTIME_API_EXTERN wasm_module_t +wasm_runtime_get_module(wasm_module_inst_t module_inst); + WASM_RUNTIME_API_EXTERN bool wasm_runtime_is_wasi_mode(wasm_module_inst_t module_inst); WASM_RUNTIME_API_EXTERN wasm_function_inst_t wasm_runtime_lookup_wasi_start_function(wasm_module_inst_t module_inst); +/** + * Get WASI exit code. + * + * After a WASI command completed its execution, an embedder can + * call this function to get its exit code. (that is, the value given + * to proc_exit.) + * + * @param module_inst the module instance + */ +WASM_RUNTIME_API_EXTERN uint32_t +wasm_runtime_get_wasi_exit_code(wasm_module_inst_t module_inst); + /** * Lookup an exported function in the WASM module instance. * @@ -667,6 +800,31 @@ wasm_runtime_call_wasm_v(wasm_exec_env_t exec_env, uint32_t num_results, wasm_val_t results[], uint32_t num_args, ...); +/** + * Call a function reference of a given WASM runtime instance with + * arguments. + * + * Note: this can be used to call a function which is not exported + * by the module explicitly. You might consider it as an abstraction + * violation. + * + * @param exec_env the execution environment to call the function + * which must be created from wasm_create_exec_env() + * @param element_index the function reference index, usually + * prvovided by the caller of a registed native function + * @param argc the number of arguments + * @param argv the arguments. If the function method has return value, + * the first (or first two in case 64-bit return value) element of + * argv stores the return value of the called WASM function after this + * function returns. + * + * @return true if success, false otherwise and exception will be thrown, + * the caller can call wasm_runtime_get_exception to get exception info. + */ +WASM_RUNTIME_API_EXTERN bool +wasm_runtime_call_indirect(wasm_exec_env_t exec_env, uint32_t element_index, + uint32_t argc, uint32_t argv[]); + /** * Find the unique main function from a WASM module instance * and execute that function. @@ -972,6 +1130,24 @@ wasm_runtime_register_natives_raw(const char *module_name, NativeSymbol *native_symbols, uint32_t n_native_symbols); + +/** + * Undo wasm_runtime_register_natives or wasm_runtime_register_natives_raw + * + * @param module_name Should be the same as the corresponding + * wasm_runtime_register_natives. + * (Same in term of strcmp.) + * + * @param native_symbols Should be the same as the corresponding + * wasm_runtime_register_natives. + * (Same in term of pointer comparison.) + * + * @return true if success, false otherwise + */ +WASM_RUNTIME_API_EXTERN bool +wasm_runtime_unregister_natives(const char *module_name, + NativeSymbol *native_symbols); + /** * Get attachment of native function from execution environment * @@ -1173,6 +1349,22 @@ wasm_runtime_get_custom_section(wasm_module_t const module_comm, */ WASM_RUNTIME_API_EXTERN void wasm_runtime_get_version(uint32_t *major, uint32_t *minor, uint32_t *patch); + +/** + * Check whether an import func `(import (func ...))` is linked or not + * with runtime registered natvie functions + */ +WASM_RUNTIME_API_EXTERN bool +wasm_runtime_is_import_func_linked(const char *module_name, + const char *func_name); + +/** + * Check whether an import global `(import (global ...))` is linked or not + * with runtime registered natvie globals + */ +WASM_RUNTIME_API_EXTERN bool +wasm_runtime_is_import_global_linked(const char *module_name, + const char *global_name); /* clang-format on */ #ifdef __cplusplus diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/interpreter/SConscript b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/SConscript similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/interpreter/SConscript rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/SConscript diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/interpreter/iwasm_interp.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/iwasm_interp.cmake similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/interpreter/iwasm_interp.cmake rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/iwasm_interp.cmake diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/interpreter/wasm.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm.h similarity index 75% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/interpreter/wasm.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm.h index 44b3973d641..0797a018b88 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/interpreter/wasm.h +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm.h @@ -124,6 +124,12 @@ typedef struct WASMType { uint16 param_cell_num; uint16 ret_cell_num; uint16 ref_count; +#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \ + && WASM_ENABLE_LAZY_JIT != 0 + /* Code block to call llvm jit functions of this + kind of function type from fast jit jitted code */ + void *call_to_llvm_jit_from_fast_jit; +#endif /* types of params and results */ uint8 types[1]; } WASMType; @@ -189,7 +195,6 @@ typedef struct WASMFunctionImport { WASMFunction *import_func_linked; #endif bool call_conv_wasm_c_api; - bool wasm_c_api_with_env; } WASMFunctionImport; typedef struct WASMGlobalImport { @@ -247,11 +252,6 @@ struct WASMFunction { uint32 max_stack_cell_num; uint32 max_block_num; - /* Whether function has opcode memory.grow */ - bool has_op_memory_grow; - /* Whether function has opcode call or - call_indirect */ - bool has_op_func_call; uint32 code_size; uint8 *code; #if WASM_ENABLE_FAST_INTERP != 0 @@ -260,8 +260,33 @@ struct WASMFunction { uint8 *consts; uint32 const_cell_num; #endif + +#if WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0 \ + || WASM_ENABLE_WAMR_COMPILER != 0 + /* Whether function has opcode memory.grow */ + bool has_op_memory_grow; + /* Whether function has opcode call or call_indirect */ + bool has_op_func_call; +#endif +#if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0 + /* Whether function has memory operation opcodes */ + bool has_memory_operations; + /* Whether function has opcode call_indirect */ + bool has_op_call_indirect; + /* Whether function has opcode set_global_aux_stack */ + bool has_op_set_global_aux_stack; +#endif + #if WASM_ENABLE_FAST_JIT != 0 + /* The compiled fast jit jitted code block of this function */ void *fast_jit_jitted_code; +#if WASM_ENABLE_JIT != 0 && WASM_ENABLE_LAZY_JIT != 0 + /* The compiled llvm jit func ptr of this function */ + void *llvm_jit_func_ptr; + /* Code block to call fast jit jitted code of this function + from the llvm jit jitted code */ + void *call_to_fast_jit_from_llvm_jit; +#endif #endif }; @@ -363,6 +388,22 @@ typedef struct WASMCustomSection { } WASMCustomSection; #endif +#if WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0 +struct AOTCompData; +struct AOTCompContext; + +/* Orc JIT thread arguments */ +typedef struct OrcJitThreadArg { +#if WASM_ENABLE_JIT != 0 + struct AOTCompContext *comp_ctx; +#endif + struct WASMModule *module; + uint32 group_idx; +} OrcJitThreadArg; +#endif + +struct WASMModuleInstance; + struct WASMModule { /* Module type, for module loaded from WASM bytecode binary, this field is Wasm_Module_Bytecode; @@ -407,6 +448,9 @@ struct WASMModule { WASMDataSeg **data_segments; uint32 start_function; + /* total global variable size */ + uint32 global_data_size; + /* the index of auxiliary __data_end global, -1 means unexported */ uint32 aux_data_end_global_index; @@ -466,18 +510,21 @@ struct WASMModule { uint64 load_size; #endif -#if WASM_ENABLE_DEBUG_INTERP != 0 +#if WASM_ENABLE_DEBUG_INTERP != 0 \ + || (WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \ + && WASM_ENABLE_LAZY_JIT != 0) /** - * Count how many instances reference this module. When source - * debugging feature enabled, the debugger may modify the code - * section of the module, so we need to report a warning if user - * create several instances based on the same module + * List of instances referred to this module. When source debugging + * feature is enabled, the debugger may modify the code section of + * the module, so we need to report a warning if user create several + * instances based on the same module. * - * Sub_instances created by lib-pthread or spawn API will not - * influence or check the ref count + * Also add the instance to the list for Fast JIT to LLVM JIT + * tier-up, since we need to lazily update the LLVM func pointers + * in the instance. */ - uint32 ref_count; - korp_mutex ref_count_lock; + struct WASMModuleInstance *instance_list; + korp_mutex instance_list_lock; #endif #if WASM_ENABLE_CUSTOM_NAME_SECTION != 0 @@ -490,8 +537,74 @@ struct WASMModule { #endif #if WASM_ENABLE_FAST_JIT != 0 - /* point to JITed functions */ + /** + * func pointers of Fast JITed (un-imported) functions + * for non Multi-Tier JIT mode: + * (1) when lazy jit is disabled, each pointer is set to the compiled + * fast jit jitted code + * (2) when lazy jit is enabled, each pointer is firstly inited as + * jit_global->compile_fast_jit_and_then_call, and then set to the + * compiled fast jit jitted code when it is called (the stub will + * compile the jit function and then update itself) + * for Multi-Tier JIT mode: + * each pointer is firstly inited as compile_fast_jit_and_then_call, + * and then set to the compiled fast jit jitted code when it is called, + * and when the llvm jit func ptr of the same function is compiled, it + * will be set to call_to_llvm_jit_from_fast_jit of this function type + * (tier-up from fast-jit to llvm-jit) + */ void **fast_jit_func_ptrs; + /* locks for Fast JIT lazy compilation */ + korp_mutex fast_jit_thread_locks[WASM_ORC_JIT_BACKEND_THREAD_NUM]; + bool fast_jit_thread_locks_inited[WASM_ORC_JIT_BACKEND_THREAD_NUM]; +#endif + +#if WASM_ENABLE_JIT != 0 + struct AOTCompData *comp_data; + struct AOTCompContext *comp_ctx; + /** + * func pointers of LLVM JITed (un-imported) functions + * for non Multi-Tier JIT mode: + * each pointer is set to the lookuped llvm jit func ptr, note that it + * is a stub and will trigger the actual compilation when it is called + * for Multi-Tier JIT mode: + * each pointer is inited as call_to_fast_jit code block, when the llvm + * jit func ptr is actually compiled, it is set to the compiled llvm jit + * func ptr + */ + void **func_ptrs; + /* whether the func pointers are compiled */ + bool *func_ptrs_compiled; +#endif + +#if WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0 + /* backend compilation threads */ + korp_tid orcjit_threads[WASM_ORC_JIT_BACKEND_THREAD_NUM]; + /* backend thread arguments */ + OrcJitThreadArg orcjit_thread_args[WASM_ORC_JIT_BACKEND_THREAD_NUM]; + /* whether to stop the compilation of backend threads */ + bool orcjit_stop_compiling; +#endif + +#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \ + && WASM_ENABLE_LAZY_JIT != 0 + /* wait lock/cond for the synchronization of + the llvm jit initialization */ + korp_mutex tierup_wait_lock; + korp_cond tierup_wait_cond; + bool tierup_wait_lock_inited; + korp_tid llvm_jit_init_thread; + /* whether the llvm jit is initialized */ + bool llvm_jit_inited; + /* Whether to enable llvm jit compilation: + it is set to true only when there is a module instance starts to + run with running mode Mode_LLVM_JIT or Mode_Multi_Tier_JIT, + since no need to enable llvm jit compilation for Mode_Interp and + Mode_Fast_JIT, so as to improve performance for them */ + bool enable_llvm_jit_compilation; + /* The count of groups which finish compiling the fast jit + functions in that group */ + uint32 fast_jit_ready_groups; #endif }; diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/interpreter/wasm_interp.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm_interp.h similarity index 85% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/interpreter/wasm_interp.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm_interp.h index 9010c942f98..d3692ff21b0 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/interpreter/wasm_interp.h +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm_interp.h @@ -89,18 +89,6 @@ wasm_interp_call_wasm(struct WASMModuleInstance *module_inst, struct WASMFunctionInstance *function, uint32 argc, uint32 argv[]); -/** - * @brief Restore the wasm stack frame to the last native frame or the begging - * of the whole stack - * @note e.g. for stack "begin --> interp --> interp", it will back to the - * "begin", for stack "begin --> interp --> native --> interp", it will become - * "begin --> interp --> native" - * - * @param exec_env the execution environment - */ -void -wasm_interp_restore_wasm_frame(struct WASMExecEnv *exec_env); - #ifdef __cplusplus } #endif diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/interpreter/wasm_interp_classic.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm_interp_classic.c similarity index 84% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/interpreter/wasm_interp_classic.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm_interp_classic.c index b7edcf7c2a8..4cc47014335 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/interpreter/wasm_interp_classic.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm_interp_classic.c @@ -8,6 +8,7 @@ #include "wasm_runtime.h" #include "wasm_opcode.h" #include "wasm_loader.h" +#include "wasm_memory.h" #include "../common/wasm_exec_env.h" #if WASM_ENABLE_SHARED_MEMORY != 0 #include "../common/wasm_shared_memory.h" @@ -27,12 +28,23 @@ typedef float64 CellType_F64; #define BR_TABLE_TMP_BUF_LEN 32 +#if WASM_ENABLE_THREAD_MGR == 0 +#define get_linear_mem_size() linear_mem_size +#else +/** + * Load memory data size in each time boundary check in + * multi-threading mode since it may be changed by other + * threads in memory.grow + */ +#define get_linear_mem_size() memory->memory_data_size +#endif + #if !defined(OS_ENABLE_HW_BOUND_CHECK) \ || WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 #define CHECK_MEMORY_OVERFLOW(bytes) \ do { \ uint64 offset1 = (uint64)offset + (uint64)addr; \ - if (offset1 + bytes <= (uint64)linear_mem_size) \ + if (offset1 + bytes <= (uint64)get_linear_mem_size()) \ /* If offset1 is in valid range, maddr must also \ be in valid range, no need to check it again. */ \ maddr = memory->memory_data + offset1; \ @@ -40,15 +52,15 @@ typedef float64 CellType_F64; goto out_of_bounds; \ } while (0) -#define CHECK_BULK_MEMORY_OVERFLOW(start, bytes, maddr) \ - do { \ - uint64 offset1 = (uint32)(start); \ - if (offset1 + bytes <= (uint64)linear_mem_size) \ - /* App heap space is not valid space for \ - bulk memory operation */ \ - maddr = memory->memory_data + offset1; \ - else \ - goto out_of_bounds; \ +#define CHECK_BULK_MEMORY_OVERFLOW(start, bytes, maddr) \ + do { \ + uint64 offset1 = (uint32)(start); \ + if (offset1 + bytes <= (uint64)get_linear_mem_size()) \ + /* App heap space is not valid space for \ + bulk memory operation */ \ + maddr = memory->memory_data + offset1; \ + else \ + goto out_of_bounds; \ } while (0) #else #define CHECK_MEMORY_OVERFLOW(bytes) \ @@ -70,6 +82,35 @@ typedef float64 CellType_F64; goto unaligned_atomic; \ } while (0) +#if WASM_ENABLE_DEBUG_INTERP != 0 +#define TRIGGER_WATCHPOINT_SIGTRAP() \ + do { \ + wasm_cluster_thread_send_signal(exec_env, WAMR_SIG_TRAP); \ + CHECK_SUSPEND_FLAGS(); \ + } while (0) + +#define CHECK_WATCHPOINT(list, current_addr) \ + do { \ + WASMDebugWatchPoint *watchpoint = bh_list_first_elem(list); \ + while (watchpoint) { \ + WASMDebugWatchPoint *next = bh_list_elem_next(watchpoint); \ + if (watchpoint->addr <= current_addr \ + && watchpoint->addr + watchpoint->length > current_addr) { \ + TRIGGER_WATCHPOINT_SIGTRAP(); \ + } \ + watchpoint = next; \ + } \ + } while (0) + +#define CHECK_READ_WATCHPOINT(addr, offset) \ + CHECK_WATCHPOINT(watch_point_list_read, WASM_ADDR_OFFSET(addr + offset)) +#define CHECK_WRITE_WATCHPOINT(addr, offset) \ + CHECK_WATCHPOINT(watch_point_list_write, WASM_ADDR_OFFSET(addr + offset)) +#else +#define CHECK_READ_WATCHPOINT(addr, offset) (void)0 +#define CHECK_WRITE_WATCHPOINT(addr, offset) (void)0 +#endif + static inline uint32 rotl32(uint32 n, uint32 c) { @@ -106,22 +147,48 @@ rotr64(uint64 n, uint64 c) return (n >> c) | (n << ((0 - c) & mask)); } -static inline double -wa_fmax(double a, double b) +static inline float32 +f32_min(float32 a, float32 b) +{ + if (isnan(a) || isnan(b)) + return NAN; + else if (a == 0 && a == b) + return signbit(a) ? a : b; + else + return a > b ? b : a; +} + +static inline float32 +f32_max(float32 a, float32 b) { - double c = fmax(a, b); - if (c == 0 && a == b) + if (isnan(a) || isnan(b)) + return NAN; + else if (a == 0 && a == b) return signbit(a) ? b : a; - return c; + else + return a > b ? a : b; } -static inline double -wa_fmin(double a, double b) +static inline float64 +f64_min(float64 a, float64 b) { - double c = fmin(a, b); - if (c == 0 && a == b) + if (isnan(a) || isnan(b)) + return NAN; + else if (a == 0 && a == b) return signbit(a) ? a : b; - return c; + else + return a > b ? b : a; +} + +static inline float64 +f64_max(float64 a, float64 b) +{ + if (isnan(a) || isnan(b)) + return NAN; + else if (a == 0 && a == b) + return signbit(a) ? b : a; + else + return a > b ? a : b; } static inline uint32 @@ -203,7 +270,7 @@ local_copysignf(float x, float y) { union { float f; - uint32_t i; + uint32 i; } ux = { x }, uy = { y }; ux.i &= 0x7fffffff; ux.i |= uy.i & 0x80000000; @@ -215,9 +282,9 @@ local_copysign(double x, double y) { union { double f; - uint64_t i; + uint64 i; } ux = { x }, uy = { y }; - ux.i &= -1ULL / 2; + ux.i &= UINT64_MAX / 2; ux.i |= uy.i & 1ULL << 63; return ux.f; } @@ -522,11 +589,11 @@ trunc_f32_to_int(WASMModuleInstance *module, uint32 *frame_sp, float32 src_min, if (!saturating) { if (isnan(src_value)) { wasm_set_exception(module, "invalid conversion to integer"); - return true; + return false; } else if (src_value <= src_min || src_value >= src_max) { wasm_set_exception(module, "integer overflow"); - return true; + return false; } } @@ -544,7 +611,7 @@ trunc_f32_to_int(WASMModuleInstance *module, uint32 *frame_sp, float32 src_min, dst_max, is_sign); PUSH_I64(dst_value_i64); } - return false; + return true; } static bool @@ -558,11 +625,11 @@ trunc_f64_to_int(WASMModuleInstance *module, uint32 *frame_sp, float64 src_min, if (!saturating) { if (isnan(src_value)) { wasm_set_exception(module, "invalid conversion to integer"); - return true; + return false; } else if (src_value <= src_min || src_value >= src_max) { wasm_set_exception(module, "integer overflow"); - return true; + return false; } } @@ -580,21 +647,21 @@ trunc_f64_to_int(WASMModuleInstance *module, uint32 *frame_sp, float64 src_min, dst_max, is_sign); PUSH_I64(dst_value_i64); } - return false; + return true; } -#define DEF_OP_TRUNC_F32(min, max, is_i32, is_sign) \ - do { \ - if (trunc_f32_to_int(module, frame_sp, min, max, false, is_i32, \ - is_sign)) \ - goto got_exception; \ +#define DEF_OP_TRUNC_F32(min, max, is_i32, is_sign) \ + do { \ + if (!trunc_f32_to_int(module, frame_sp, min, max, false, is_i32, \ + is_sign)) \ + goto got_exception; \ } while (0) -#define DEF_OP_TRUNC_F64(min, max, is_i32, is_sign) \ - do { \ - if (trunc_f64_to_int(module, frame_sp, min, max, false, is_i32, \ - is_sign)) \ - goto got_exception; \ +#define DEF_OP_TRUNC_F64(min, max, is_i32, is_sign) \ + do { \ + if (!trunc_f64_to_int(module, frame_sp, min, max, false, is_i32, \ + is_sign)) \ + goto got_exception; \ } while (0) #define DEF_OP_TRUNC_SAT_F32(min, max, is_i32, is_sign) \ @@ -641,28 +708,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(&memory->mem_lock); \ + os_mutex_lock(&node->shared_mem_lock); \ readv = (uint32)(*(uint8 *)maddr); \ *(uint8 *)maddr = (uint8)(readv op sval); \ - os_mutex_unlock(&memory->mem_lock); \ + os_mutex_unlock(&node->shared_mem_lock); \ } \ 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(&memory->mem_lock); \ + os_mutex_lock(&node->shared_mem_lock); \ readv = (uint32)LOAD_U16(maddr); \ STORE_U16(maddr, (uint16)(readv op sval)); \ - os_mutex_unlock(&memory->mem_lock); \ + os_mutex_unlock(&node->shared_mem_lock); \ } \ else { \ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); \ CHECK_ATOMIC_MEMORY_ACCESS(); \ \ - os_mutex_lock(&memory->mem_lock); \ + os_mutex_lock(&node->shared_mem_lock); \ readv = LOAD_I32(maddr); \ STORE_U32(maddr, readv op sval); \ - os_mutex_unlock(&memory->mem_lock); \ + os_mutex_unlock(&node->shared_mem_lock); \ } \ PUSH_I32(readv); \ break; \ @@ -681,39 +748,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(&memory->mem_lock); \ + os_mutex_lock(&node->shared_mem_lock); \ readv = (uint64)(*(uint8 *)maddr); \ *(uint8 *)maddr = (uint8)(readv op sval); \ - os_mutex_unlock(&memory->mem_lock); \ + os_mutex_unlock(&node->shared_mem_lock); \ } \ 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(&memory->mem_lock); \ + os_mutex_lock(&node->shared_mem_lock); \ readv = (uint64)LOAD_U16(maddr); \ STORE_U16(maddr, (uint16)(readv op sval)); \ - os_mutex_unlock(&memory->mem_lock); \ + os_mutex_unlock(&node->shared_mem_lock); \ } \ 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(&memory->mem_lock); \ + os_mutex_lock(&node->shared_mem_lock); \ readv = (uint64)LOAD_U32(maddr); \ STORE_U32(maddr, (uint32)(readv op sval)); \ - os_mutex_unlock(&memory->mem_lock); \ + os_mutex_unlock(&node->shared_mem_lock); \ } \ else { \ uint64 op_result; \ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr); \ CHECK_ATOMIC_MEMORY_ACCESS(); \ \ - os_mutex_lock(&memory->mem_lock); \ + os_mutex_lock(&node->shared_mem_lock); \ readv = (uint64)LOAD_I64(maddr); \ op_result = readv op sval; \ STORE_I64(maddr, op_result); \ - os_mutex_unlock(&memory->mem_lock); \ + os_mutex_unlock(&node->shared_mem_lock); \ } \ PUSH_I64(readv); \ break; \ @@ -805,26 +872,6 @@ FREE_FRAME(WASMExecEnv *exec_env, WASMInterpFrame *frame) wasm_exec_env_free_wasm_frame(exec_env, frame); } -void -wasm_interp_restore_wasm_frame(WASMExecEnv *exec_env) -{ - WASMInterpFrame *cur_frame, *prev_frame; - - cur_frame = wasm_exec_env_get_cur_frame(exec_env); - while (cur_frame) { - prev_frame = cur_frame->prev_frame; - if (cur_frame->ip) { - /* FREE_FRAME just set the wasm_stack.s.top pointer, we only need to - * call it once */ - FREE_FRAME(exec_env, cur_frame); - break; - } - cur_frame = prev_frame; - } - - wasm_exec_env_set_cur_frame(exec_env, cur_frame); -} - static void wasm_interp_call_func_native(WASMModuleInstance *module_inst, WASMExecEnv *exec_env, @@ -832,6 +879,7 @@ wasm_interp_call_func_native(WASMModuleInstance *module_inst, WASMInterpFrame *prev_frame) { WASMFunctionImport *func_import = cur_func->u.func_import; + CApiFuncImport *c_api_func_import = NULL; unsigned local_cell_num = 2; WASMInterpFrame *frame; uint32 argv_ret[2], cur_func_index; @@ -850,9 +898,15 @@ wasm_interp_call_func_native(WASMModuleInstance *module_inst, wasm_exec_env_set_cur_frame(exec_env, frame); - cur_func_index = (uint32)(cur_func - module_inst->functions); + cur_func_index = (uint32)(cur_func - module_inst->e->functions); bh_assert(cur_func_index < module_inst->module->import_function_count); - native_func_pointer = module_inst->import_func_ptrs[cur_func_index]; + if (!func_import->call_conv_wasm_c_api) { + native_func_pointer = module_inst->import_func_ptrs[cur_func_index]; + } + else if (module_inst->e->c_api_func_imports) { + c_api_func_import = module_inst->e->c_api_func_imports + cur_func_index; + native_func_pointer = c_api_func_import->func_ptr_linked; + } if (!native_func_pointer) { snprintf(buf, sizeof(buf), @@ -866,7 +920,7 @@ wasm_interp_call_func_native(WASMModuleInstance *module_inst, ret = wasm_runtime_invoke_c_api_native( (WASMModuleInstanceCommon *)module_inst, native_func_pointer, func_import->func_type, cur_func->param_cell_num, frame->lp, - func_import->wasm_c_api_with_env, func_import->attachment); + c_api_func_import->with_env_arg, c_api_func_import->env_arg); if (ret) { argv_ret[0] = frame->lp[0]; argv_ret[1] = frame->lp[1]; @@ -904,15 +958,15 @@ wasm_interp_call_func_native(WASMModuleInstance *module_inst, #if WASM_ENABLE_FAST_JIT != 0 bool -jit_invoke_native(WASMExecEnv *exec_env, uint32 func_idx, - WASMInterpFrame *prev_frame) +fast_jit_invoke_native(WASMExecEnv *exec_env, uint32 func_idx, + WASMInterpFrame *prev_frame) { WASMModuleInstance *module_inst = (WASMModuleInstance *)exec_env->module_inst; - WASMFunctionInstance *cur_func = module_inst->functions + func_idx; + WASMFunctionInstance *cur_func = module_inst->e->functions + func_idx; wasm_interp_call_func_native(module_inst, exec_env, cur_func, prev_frame); - return wasm_get_exception(module_inst) ? false : true; + return wasm_copy_exception(module_inst, NULL) ? false : true; } #endif @@ -981,7 +1035,7 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst, exec_env->module_inst = (WASMModuleInstanceCommon *)module_inst; /* transfer exception if it is thrown */ - if (wasm_get_exception(sub_module_inst)) { + if (wasm_copy_exception(sub_module_inst, NULL)) { bh_memcpy_s(module_inst->cur_exception, sizeof(module_inst->cur_exception), sub_module_inst->cur_exception, @@ -994,21 +1048,25 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst, #if WASM_ENABLE_DEBUG_INTERP != 0 #define CHECK_SUSPEND_FLAGS() \ do { \ + os_mutex_lock(&exec_env->wait_lock); \ if (IS_WAMR_TERM_SIG(exec_env->current_status->signal_flag)) { \ + os_mutex_unlock(&exec_env->wait_lock); \ return; \ } \ if (IS_WAMR_STOP_SIG(exec_env->current_status->signal_flag)) { \ SYNC_ALL_TO_FRAME(); \ - wasm_cluster_thread_stopped(exec_env); \ wasm_cluster_thread_waiting_run(exec_env); \ } \ + 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) { \ @@ -1016,6 +1074,7 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst, os_cond_wait(&exec_env->wait_cond, &exec_env->wait_lock); \ } \ } \ + os_mutex_unlock(&exec_env->wait_lock); \ } while (0) #endif /* WASM_ENABLE_DEBUG_INTERP */ #endif /* WASM_ENABLE_THREAD_MGR */ @@ -1031,13 +1090,14 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst, /* Record the current frame_ip, so when exception occurs, \ debugger can know the exact opcode who caused the exception */ \ frame_ip_orig = frame_ip; \ + os_mutex_lock(&exec_env->wait_lock); \ while (exec_env->current_status->signal_flag == WAMR_SIG_SINGSTEP \ && exec_env->current_status->step_count++ == 1) { \ exec_env->current_status->step_count = 0; \ SYNC_ALL_TO_FRAME(); \ - wasm_cluster_thread_stopped(exec_env); \ wasm_cluster_thread_waiting_run(exec_env); \ } \ + os_mutex_unlock(&exec_env->wait_lock); \ goto *handle_table[*frame_ip++]; \ } while (0) #else @@ -1048,13 +1108,14 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst, #define HANDLE_OP(opcode) case opcode: #if WASM_ENABLE_THREAD_MGR != 0 && WASM_ENABLE_DEBUG_INTERP != 0 #define HANDLE_OP_END() \ + os_mutex_lock(&exec_env->wait_lock); \ if (exec_env->current_status->signal_flag == WAMR_SIG_SINGSTEP \ && exec_env->current_status->step_count++ == 2) { \ exec_env->current_status->step_count = 0; \ SYNC_ALL_TO_FRAME(); \ - wasm_cluster_thread_stopped(exec_env); \ wasm_cluster_thread_waiting_run(exec_env); \ } \ + os_mutex_unlock(&exec_env->wait_lock); \ continue #else #define HANDLE_OP_END() continue @@ -1081,17 +1142,19 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, WASMFunctionInstance *cur_func, WASMInterpFrame *prev_frame) { - WASMMemoryInstance *memory = module->default_memory; - uint8 *global_data = module->global_data; +#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 \ || WASM_ENABLE_BULK_MEMORY != 0 - uint32 num_bytes_per_page = memory ? memory->num_bytes_per_page : 0; - uint32 linear_mem_size = - memory ? num_bytes_per_page * memory->cur_page_count : 0; + uint32 linear_mem_size = memory ? memory->memory_data_size : 0; #endif WASMType **wasm_types = module->module->types; - WASMGlobalInstance *globals = module->globals, *global; + WASMGlobalInstance *globals = module->e->globals, *global; + uint8 *global_data = module->global_data; uint8 opcode_IMPDEP = WASM_OP_IMPDEP; WASMInterpFrame *frame = NULL; /* Points to this special opcode so as to jump to the @@ -1104,7 +1167,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, uint8 *frame_ip_end = frame_ip + 1; uint8 opcode; uint32 i, depth, cond, count, fidx, tidx, lidx, frame_size = 0; - uint64 all_cell_num = 0; + uint32 all_cell_num = 0; int32 val; uint8 *else_addr, *end_addr, *maddr = NULL; uint32 local_idx, local_offset, global_idx; @@ -1114,6 +1177,11 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, #if WASM_ENABLE_DEBUG_INTERP != 0 uint8 *frame_ip_orig = NULL; + WASMDebugInstance *debug_instance = wasm_exec_env_get_instance(exec_env); + bh_list *watch_point_list_read = + debug_instance ? &debug_instance->watch_point_list_read : NULL; + bh_list *watch_point_list_write = + debug_instance ? &debug_instance->watch_point_list_write : NULL; #endif #if WASM_ENABLE_LABELS_AS_VALUES != 0 @@ -1318,7 +1386,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP(EXT_OP_BR_TABLE_CACHE) { - BrTableCache *node = + BrTableCache *node_cache = bh_list_first_elem(module->module->br_table_cache_list); BrTableCache *node_next; @@ -1327,13 +1395,13 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, #endif lidx = POP_I32(); - while (node) { - node_next = bh_list_elem_next(node); - if (node->br_table_op_addr == frame_ip - 1) { - depth = node->br_depths[lidx]; + while (node_cache) { + node_next = bh_list_elem_next(node_cache); + if (node_cache->br_table_op_addr == frame_ip - 1) { + depth = node_cache->br_depths[lidx]; goto label_pop_csp_n; } - node = node_next; + node_cache = node_next; } bh_assert(0); HANDLE_OP_END(); @@ -1355,13 +1423,13 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, #endif read_leb_uint32(frame_ip, frame_ip_end, fidx); #if WASM_ENABLE_MULTI_MODULE != 0 - if (fidx >= module->function_count) { + if (fidx >= module->e->function_count) { wasm_set_exception(module, "unknown function"); goto got_exception; } #endif - cur_func = module->functions + fidx; + cur_func = module->e->functions + fidx; goto call_func_from_interp; } @@ -1373,12 +1441,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, #endif read_leb_uint32(frame_ip, frame_ip_end, fidx); #if WASM_ENABLE_MULTI_MODULE != 0 - if (fidx >= module->function_count) { + if (fidx >= module->e->function_count) { wasm_set_exception(module, "unknown function"); goto got_exception; } #endif - cur_func = module->functions + fidx; + cur_func = module->e->functions + fidx; goto call_func_from_return_call; } @@ -1420,8 +1488,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, goto got_exception; } - fidx = ((uint32 *)tbl_inst->base_addr)[val]; - if (fidx == (uint32)-1) { + fidx = tbl_inst->elems[val]; + if (fidx == NULL_REF) { wasm_set_exception(module, "uninitialized element"); goto got_exception; } @@ -1431,13 +1499,13 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, * another module. In that case, we don't validate * the elem value while loading */ - if (fidx >= module->function_count) { + if (fidx >= module->e->function_count) { wasm_set_exception(module, "unknown function"); goto got_exception; } /* always call module own functions */ - cur_func = module->functions + fidx; + cur_func = module->e->functions + fidx; if (cur_func->is_import_func) cur_func_type = cur_func->u.func_import->func_type; @@ -1531,7 +1599,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, goto got_exception; } - PUSH_I32(((uint32 *)tbl_inst->base_addr)[elem_idx]); + PUSH_I32(tbl_inst->elems[elem_idx]); HANDLE_OP_END(); } @@ -1552,7 +1620,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, goto got_exception; } - ((uint32 *)(tbl_inst->base_addr))[elem_idx] = elem_val; + tbl_inst->elems[elem_idx] = elem_val; HANDLE_OP_END(); } @@ -1700,7 +1768,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP(WASM_OP_GET_GLOBAL) { read_leb_uint32(frame_ip, frame_ip_end, global_idx); - bh_assert(global_idx < module->global_count); + bh_assert(global_idx < module->e->global_count); global = globals + global_idx; global_addr = get_global_addr(global_data, global); PUSH_I32(*(uint32 *)global_addr); @@ -1710,7 +1778,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP(WASM_OP_GET_GLOBAL_64) { read_leb_uint32(frame_ip, frame_ip_end, global_idx); - bh_assert(global_idx < module->global_count); + bh_assert(global_idx < module->e->global_count); global = globals + global_idx; global_addr = get_global_addr(global_data, global); PUSH_I64(GET_I64_FROM_ADDR((uint32 *)global_addr)); @@ -1720,7 +1788,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP(WASM_OP_SET_GLOBAL) { read_leb_uint32(frame_ip, frame_ip_end, global_idx); - bh_assert(global_idx < module->global_count); + bh_assert(global_idx < module->e->global_count); global = globals + global_idx; global_addr = get_global_addr(global_data, global); *(int32 *)global_addr = POP_I32(); @@ -1732,7 +1800,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, uint32 aux_stack_top; read_leb_uint32(frame_ip, frame_ip_end, global_idx); - bh_assert(global_idx < module->global_count); + bh_assert(global_idx < module->e->global_count); global = globals + global_idx; global_addr = get_global_addr(global_data, global); aux_stack_top = *(uint32 *)(frame_sp - 1); @@ -1751,8 +1819,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, if (module->module->aux_stack_top_global_index != (uint32)-1) { uint32 aux_stack_used = module->module->aux_stack_bottom - *(uint32 *)global_addr; - if (aux_stack_used > module->max_aux_stack_used) - module->max_aux_stack_used = aux_stack_used; + if (aux_stack_used > module->e->max_aux_stack_used) + module->e->max_aux_stack_used = aux_stack_used; } #endif HANDLE_OP_END(); @@ -1761,7 +1829,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP(WASM_OP_SET_GLOBAL_64) { read_leb_uint32(frame_ip, frame_ip_end, global_idx); - bh_assert(global_idx < module->global_count); + bh_assert(global_idx < module->e->global_count); global = globals + global_idx; global_addr = get_global_addr(global_data, global); PUT_I64_TO_ADDR((uint32 *)global_addr, POP_I64()); @@ -1779,6 +1847,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, addr = POP_I32(); CHECK_MEMORY_OVERFLOW(4); PUSH_I32(LOAD_I32(maddr)); + CHECK_READ_WATCHPOINT(addr, offset); (void)flags; HANDLE_OP_END(); } @@ -1793,6 +1862,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, addr = POP_I32(); CHECK_MEMORY_OVERFLOW(8); PUSH_I64(LOAD_I64(maddr)); + CHECK_READ_WATCHPOINT(addr, offset); (void)flags; HANDLE_OP_END(); } @@ -1806,6 +1876,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, addr = POP_I32(); CHECK_MEMORY_OVERFLOW(1); PUSH_I32(sign_ext_8_32(*(int8 *)maddr)); + CHECK_READ_WATCHPOINT(addr, offset); (void)flags; HANDLE_OP_END(); } @@ -1819,6 +1890,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, addr = POP_I32(); CHECK_MEMORY_OVERFLOW(1); PUSH_I32((uint32)(*(uint8 *)maddr)); + CHECK_READ_WATCHPOINT(addr, offset); (void)flags; HANDLE_OP_END(); } @@ -1832,6 +1904,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, addr = POP_I32(); CHECK_MEMORY_OVERFLOW(2); PUSH_I32(sign_ext_16_32(LOAD_I16(maddr))); + CHECK_READ_WATCHPOINT(addr, offset); (void)flags; HANDLE_OP_END(); } @@ -1845,6 +1918,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, addr = POP_I32(); CHECK_MEMORY_OVERFLOW(2); PUSH_I32((uint32)(LOAD_U16(maddr))); + CHECK_READ_WATCHPOINT(addr, offset); (void)flags; HANDLE_OP_END(); } @@ -1858,6 +1932,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, addr = POP_I32(); CHECK_MEMORY_OVERFLOW(1); PUSH_I64(sign_ext_8_64(*(int8 *)maddr)); + CHECK_READ_WATCHPOINT(addr, offset); (void)flags; HANDLE_OP_END(); } @@ -1871,6 +1946,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, addr = POP_I32(); CHECK_MEMORY_OVERFLOW(1); PUSH_I64((uint64)(*(uint8 *)maddr)); + CHECK_READ_WATCHPOINT(addr, offset); (void)flags; HANDLE_OP_END(); } @@ -1884,6 +1960,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, addr = POP_I32(); CHECK_MEMORY_OVERFLOW(2); PUSH_I64(sign_ext_16_64(LOAD_I16(maddr))); + CHECK_READ_WATCHPOINT(addr, offset); (void)flags; HANDLE_OP_END(); } @@ -1897,6 +1974,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, addr = POP_I32(); CHECK_MEMORY_OVERFLOW(2); PUSH_I64((uint64)(LOAD_U16(maddr))); + CHECK_READ_WATCHPOINT(addr, offset); (void)flags; HANDLE_OP_END(); } @@ -1911,6 +1989,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, addr = POP_I32(); CHECK_MEMORY_OVERFLOW(4); PUSH_I64(sign_ext_32_64(LOAD_I32(maddr))); + CHECK_READ_WATCHPOINT(addr, offset); (void)flags; HANDLE_OP_END(); } @@ -1924,6 +2003,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, addr = POP_I32(); CHECK_MEMORY_OVERFLOW(4); PUSH_I64((uint64)(LOAD_U32(maddr))); + CHECK_READ_WATCHPOINT(addr, offset); (void)flags; HANDLE_OP_END(); } @@ -1940,6 +2020,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, addr = POP_I32(); CHECK_MEMORY_OVERFLOW(4); STORE_U32(maddr, frame_sp[1]); + CHECK_WRITE_WATCHPOINT(addr, offset); (void)flags; HANDLE_OP_END(); } @@ -1956,6 +2037,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, CHECK_MEMORY_OVERFLOW(8); PUT_I64_TO_ADDR((uint32 *)maddr, GET_I64_FROM_ADDR(frame_sp + 1)); + CHECK_WRITE_WATCHPOINT(addr, offset); (void)flags; HANDLE_OP_END(); } @@ -1980,7 +2062,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, CHECK_MEMORY_OVERFLOW(2); STORE_U16(maddr, (uint16)sval); } - + CHECK_WRITE_WATCHPOINT(addr, offset); (void)flags; HANDLE_OP_END(); } @@ -2010,6 +2092,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, CHECK_MEMORY_OVERFLOW(4); STORE_U32(maddr, (uint32)sval); } + CHECK_WRITE_WATCHPOINT(addr, offset); (void)flags; HANDLE_OP_END(); } @@ -2039,13 +2122,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, else { /* success, return previous page count */ PUSH_I32(prev_page_count); - /* update memory instance ptr and memory size */ - memory = module->default_memory; + /* update memory size, no need to update memory ptr as + it isn't changed in wasm_enlarge_memory */ #if !defined(OS_ENABLE_HW_BOUND_CHECK) \ || WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 \ || WASM_ENABLE_BULK_MEMORY != 0 - linear_mem_size = - num_bytes_per_page * memory->cur_page_count; + linear_mem_size = memory->memory_data_size; #endif } @@ -2680,12 +2762,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, b = POP_F32(); a = POP_F32(); - if (isnan(a)) - PUSH_F32(a); - else if (isnan(b)) - PUSH_F32(b); - else - PUSH_F32(wa_fmin(a, b)); + PUSH_F32(f32_min(a, b)); HANDLE_OP_END(); } @@ -2696,12 +2773,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, b = POP_F32(); a = POP_F32(); - if (isnan(a)) - PUSH_F32(a); - else if (isnan(b)) - PUSH_F32(b); - else - PUSH_F32(wa_fmax(a, b)); + PUSH_F32(f32_max(a, b)); HANDLE_OP_END(); } @@ -2794,12 +2866,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, b = POP_F64(); a = POP_F64(); - if (isnan(a)) - PUSH_F64(a); - else if (isnan(b)) - PUSH_F64(b); - else - PUSH_F64(wa_fmin(a, b)); + PUSH_F64(f64_min(a, b)); HANDLE_OP_END(); } @@ -2810,12 +2877,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, b = POP_F64(); a = POP_F64(); - if (isnan(a)) - PUSH_F64(a); - else if (isnan(b)) - PUSH_F64(b); - else - PUSH_F64(wa_fmax(a, b)); + PUSH_F64(f64_max(a, b)); HANDLE_OP_END(); } @@ -3069,6 +3131,10 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, offset = (uint64)(uint32)POP_I32(); addr = (uint32)POP_I32(); +#if WASM_ENABLE_THREAD_MGR != 0 + linear_mem_size = memory->memory_data_size; +#endif + #ifndef OS_ENABLE_HW_BOUND_CHECK CHECK_BULK_MEMORY_OVERFLOW(addr, bytes, maddr); #else @@ -3107,6 +3173,10 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, src = POP_I32(); dst = POP_I32(); +#if WASM_ENABLE_THREAD_MGR != 0 + linear_mem_size = memory->memory_data_size; +#endif + #ifndef OS_ENABLE_HW_BOUND_CHECK CHECK_BULK_MEMORY_OVERFLOW(src, len, msrc); CHECK_BULK_MEMORY_OVERFLOW(dst, len, mdst); @@ -3134,6 +3204,10 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, fill_val = POP_I32(); dst = POP_I32(); +#if WASM_ENABLE_THREAD_MGR != 0 + linear_mem_size = memory->memory_data_size; +#endif + #ifndef OS_ENABLE_HW_BOUND_CHECK CHECK_BULK_MEMORY_OVERFLOW(dst, len, mdst); #else @@ -3195,8 +3269,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, } bh_memcpy_s( - (uint8 *)(tbl_inst) - + offsetof(WASMTableInstance, base_addr) + (uint8 *)tbl_inst + + offsetof(WASMTableInstance, elems) + d * sizeof(uint32), (uint32)((tbl_inst->cur_size - d) * sizeof(uint32)), module->module->table_segments[elem_idx] @@ -3246,16 +3320,15 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, /* if s >= d, copy from front to back */ /* if s < d, copy from back to front */ /* merge all together */ - bh_memmove_s( - (uint8 *)(dst_tbl_inst) - + offsetof(WASMTableInstance, base_addr) - + d * sizeof(uint32), - (uint32)((dst_tbl_inst->cur_size - d) - * sizeof(uint32)), - (uint8 *)(src_tbl_inst) - + offsetof(WASMTableInstance, base_addr) - + s * sizeof(uint32), - (uint32)(n * sizeof(uint32))); + bh_memmove_s((uint8 *)dst_tbl_inst + + offsetof(WASMTableInstance, elems) + + d * sizeof(uint32), + (uint32)((dst_tbl_inst->cur_size - d) + * sizeof(uint32)), + (uint8 *)src_tbl_inst + + offsetof(WASMTableInstance, elems) + + s * sizeof(uint32), + (uint32)(n * sizeof(uint32))); break; } case WASM_OP_TABLE_GROW: @@ -3319,7 +3392,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, } for (; n != 0; i++, n--) { - ((uint32 *)(tbl_inst->base_addr))[i] = fill_val; + tbl_inst->elems[i] = fill_val; } break; @@ -3357,7 +3430,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, ret = wasm_runtime_atomic_notify( (WASMModuleInstanceCommon *)module, maddr, notify_count); - bh_assert((int32)ret >= 0); + if (ret == (uint32)-1) + goto got_exception; PUSH_I32(ret); break; @@ -3379,6 +3453,10 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, if (ret == (uint32)-1) goto got_exception; +#if WASM_ENABLE_THREAD_MGR != 0 + CHECK_SUSPEND_FLAGS(); +#endif + PUSH_I32(ret); break; } @@ -3399,6 +3477,10 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, if (ret == (uint32)-1) goto got_exception; +#if WASM_ENABLE_THREAD_MGR != 0 + CHECK_SUSPEND_FLAGS(); +#endif + PUSH_I32(ret); break; } @@ -3406,6 +3488,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, { /* Skip the memory index */ frame_ip++; + os_atomic_thread_fence(os_memory_order_seq_cst); break; } @@ -3420,23 +3503,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(&memory->mem_lock); + os_mutex_lock(&node->shared_mem_lock); readv = (uint32)(*(uint8 *)maddr); - os_mutex_unlock(&memory->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } else if (opcode == WASM_OP_ATOMIC_I32_LOAD16_U) { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr); CHECK_ATOMIC_MEMORY_ACCESS(); - os_mutex_lock(&memory->mem_lock); + os_mutex_lock(&node->shared_mem_lock); readv = (uint32)LOAD_U16(maddr); - os_mutex_unlock(&memory->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } else { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); CHECK_ATOMIC_MEMORY_ACCESS(); - os_mutex_lock(&memory->mem_lock); + os_mutex_lock(&node->shared_mem_lock); readv = LOAD_I32(maddr); - os_mutex_unlock(&memory->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } PUSH_I32(readv); @@ -3455,30 +3538,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(&memory->mem_lock); + os_mutex_lock(&node->shared_mem_lock); readv = (uint64)(*(uint8 *)maddr); - os_mutex_unlock(&memory->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } else if (opcode == WASM_OP_ATOMIC_I64_LOAD16_U) { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr); CHECK_ATOMIC_MEMORY_ACCESS(); - os_mutex_lock(&memory->mem_lock); + os_mutex_lock(&node->shared_mem_lock); readv = (uint64)LOAD_U16(maddr); - os_mutex_unlock(&memory->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } else if (opcode == WASM_OP_ATOMIC_I64_LOAD32_U) { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); CHECK_ATOMIC_MEMORY_ACCESS(); - os_mutex_lock(&memory->mem_lock); + os_mutex_lock(&node->shared_mem_lock); readv = (uint64)LOAD_U32(maddr); - os_mutex_unlock(&memory->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } else { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr); CHECK_ATOMIC_MEMORY_ACCESS(); - os_mutex_lock(&memory->mem_lock); + os_mutex_lock(&node->shared_mem_lock); readv = LOAD_I64(maddr); - os_mutex_unlock(&memory->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } PUSH_I64(readv); @@ -3497,23 +3580,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(&memory->mem_lock); + os_mutex_lock(&node->shared_mem_lock); *(uint8 *)maddr = (uint8)sval; - os_mutex_unlock(&memory->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } else if (opcode == WASM_OP_ATOMIC_I32_STORE16) { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr); CHECK_ATOMIC_MEMORY_ACCESS(); - os_mutex_lock(&memory->mem_lock); + os_mutex_lock(&node->shared_mem_lock); STORE_U16(maddr, (uint16)sval); - os_mutex_unlock(&memory->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } else { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); CHECK_ATOMIC_MEMORY_ACCESS(); - os_mutex_lock(&memory->mem_lock); - STORE_U32(maddr, frame_sp[1]); - os_mutex_unlock(&memory->mem_lock); + os_mutex_lock(&node->shared_mem_lock); + STORE_U32(maddr, sval); + os_mutex_unlock(&node->shared_mem_lock); } break; } @@ -3531,31 +3614,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(&memory->mem_lock); + os_mutex_lock(&node->shared_mem_lock); *(uint8 *)maddr = (uint8)sval; - os_mutex_unlock(&memory->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } else if (opcode == WASM_OP_ATOMIC_I64_STORE16) { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr); CHECK_ATOMIC_MEMORY_ACCESS(); - os_mutex_lock(&memory->mem_lock); + os_mutex_lock(&node->shared_mem_lock); STORE_U16(maddr, (uint16)sval); - os_mutex_unlock(&memory->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } else if (opcode == WASM_OP_ATOMIC_I64_STORE32) { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); CHECK_ATOMIC_MEMORY_ACCESS(); - os_mutex_lock(&memory->mem_lock); + os_mutex_lock(&node->shared_mem_lock); STORE_U32(maddr, (uint32)sval); - os_mutex_unlock(&memory->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } else { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr); CHECK_ATOMIC_MEMORY_ACCESS(); - os_mutex_lock(&memory->mem_lock); - PUT_I64_TO_ADDR((uint32 *)maddr, - GET_I64_FROM_ADDR(frame_sp + 1)); - os_mutex_unlock(&memory->mem_lock); + os_mutex_lock(&node->shared_mem_lock); + PUT_I64_TO_ADDR((uint32 *)maddr, sval); + os_mutex_unlock(&node->shared_mem_lock); } break; } @@ -3575,32 +3657,32 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, CHECK_ATOMIC_MEMORY_ACCESS(); expect = (uint8)expect; - os_mutex_lock(&memory->mem_lock); + os_mutex_lock(&node->shared_mem_lock); readv = (uint32)(*(uint8 *)maddr); if (readv == expect) *(uint8 *)maddr = (uint8)(sval); - os_mutex_unlock(&memory->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } 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(&memory->mem_lock); + os_mutex_lock(&node->shared_mem_lock); readv = (uint32)LOAD_U16(maddr); if (readv == expect) STORE_U16(maddr, (uint16)(sval)); - os_mutex_unlock(&memory->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } else { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); CHECK_ATOMIC_MEMORY_ACCESS(); - os_mutex_lock(&memory->mem_lock); + os_mutex_lock(&node->shared_mem_lock); readv = LOAD_I32(maddr); if (readv == expect) STORE_U32(maddr, sval); - os_mutex_unlock(&memory->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } PUSH_I32(readv); break; @@ -3621,44 +3703,43 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, CHECK_ATOMIC_MEMORY_ACCESS(); expect = (uint8)expect; - os_mutex_lock(&memory->mem_lock); + os_mutex_lock(&node->shared_mem_lock); readv = (uint64)(*(uint8 *)maddr); if (readv == expect) *(uint8 *)maddr = (uint8)(sval); - os_mutex_unlock(&memory->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } 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(&memory->mem_lock); + os_mutex_lock(&node->shared_mem_lock); readv = (uint64)LOAD_U16(maddr); if (readv == expect) STORE_U16(maddr, (uint16)(sval)); - os_mutex_unlock(&memory->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } 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(&memory->mem_lock); + os_mutex_lock(&node->shared_mem_lock); readv = (uint64)LOAD_U32(maddr); if (readv == expect) STORE_U32(maddr, (uint32)(sval)); - os_mutex_unlock(&memory->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } else { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr); CHECK_ATOMIC_MEMORY_ACCESS(); - os_mutex_lock(&memory->mem_lock); + os_mutex_lock(&node->shared_mem_lock); readv = (uint64)LOAD_I64(maddr); - if (readv == expect) { + if (readv == expect) STORE_I64(maddr, sval); - } - os_mutex_unlock(&memory->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } PUSH_I64(readv); break; @@ -3759,7 +3840,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, word_copy(frame->lp, frame_sp, cur_func->param_cell_num); } FREE_FRAME(exec_env, frame); - wasm_exec_env_set_cur_frame(exec_env, (WASMRuntimeFrame *)prev_frame); + wasm_exec_env_set_cur_frame(exec_env, prev_frame); goto call_func_from_entry; } #endif @@ -3794,15 +3875,15 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, cur_func = frame->function; UPDATE_ALL_FROM_FRAME(); - /* update memory instance ptr and memory size */ - memory = module->default_memory; + /* update memory size, no need to update memory ptr as + it isn't changed in wasm_enlarge_memory */ #if !defined(OS_ENABLE_HW_BOUND_CHECK) \ || WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 \ || WASM_ENABLE_BULK_MEMORY != 0 if (memory) - linear_mem_size = num_bytes_per_page * memory->cur_page_count; + linear_mem_size = memory->memory_data_size; #endif - if (wasm_get_exception(module)) + if (wasm_copy_exception(module, NULL)) goto got_exception; } else { @@ -3811,17 +3892,16 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, func_type = cur_wasm_func->func_type; - all_cell_num = (uint64)cur_func->param_cell_num - + (uint64)cur_func->local_cell_num - + (uint64)cur_wasm_func->max_stack_cell_num - + ((uint64)cur_wasm_func->max_block_num) - * sizeof(WASMBranchBlock) / 4; - if (all_cell_num >= UINT32_MAX) { - wasm_set_exception(module, "wasm operand stack overflow"); - goto got_exception; - } + all_cell_num = cur_func->param_cell_num + cur_func->local_cell_num + + cur_wasm_func->max_stack_cell_num + + cur_wasm_func->max_block_num + * (uint32)sizeof(WASMBranchBlock) / 4; + /* param_cell_num, local_cell_num, max_stack_cell_num and + max_block_num are all no larger than UINT16_MAX (checked + in loader), all_cell_num must be smaller than 1MB */ + bh_assert(all_cell_num < 1 * BH_MB); - frame_size = wasm_interp_interp_frame_size((uint32)all_cell_num); + frame_size = wasm_interp_interp_frame_size(all_cell_num); if (!(frame = ALLOC_FRAME(exec_env, frame_size, prev_frame))) { frame = prev_frame; goto got_exception; @@ -3851,18 +3931,18 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, cell_num = func_type->ret_cell_num; PUSH_CSP(LABEL_TYPE_FUNCTION, 0, cell_num, frame_ip_end - 1); - wasm_exec_env_set_cur_frame(exec_env, (WASMRuntimeFrame *)frame); + wasm_exec_env_set_cur_frame(exec_env, frame); + } #if WASM_ENABLE_THREAD_MGR != 0 - CHECK_SUSPEND_FLAGS(); + CHECK_SUSPEND_FLAGS(); #endif - } HANDLE_OP_END(); } return_func: { FREE_FRAME(exec_env, frame); - wasm_exec_env_set_cur_frame(exec_env, (WASMRuntimeFrame *)prev_frame); + wasm_exec_env_set_cur_frame(exec_env, prev_frame); if (!prev_frame->ip) /* Called from native. */ @@ -3905,6 +3985,188 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, #endif } +#if WASM_ENABLE_FAST_JIT != 0 +static void +fast_jit_call_func_bytecode(WASMModuleInstance *module_inst, + WASMExecEnv *exec_env, + WASMFunctionInstance *function, + WASMInterpFrame *frame) +{ + JitGlobals *jit_globals = jit_compiler_get_jit_globals(); + JitInterpSwitchInfo info; + WASMModule *module = module_inst->module; + WASMType *func_type = function->u.func->func_type; + uint8 type = func_type->result_count + ? func_type->types[func_type->param_count] + : VALUE_TYPE_VOID; + uint32 func_idx = (uint32)(function - module_inst->e->functions); + uint32 func_idx_non_import = func_idx - module->import_function_count; + int32 action; + +#if WASM_ENABLE_REF_TYPES != 0 + if (type == VALUE_TYPE_EXTERNREF || type == VALUE_TYPE_FUNCREF) + type = VALUE_TYPE_I32; +#endif + +#if WASM_ENABLE_LAZY_JIT != 0 + if (!jit_compiler_compile(module, func_idx)) { + wasm_set_exception(module_inst, "failed to compile fast jit function"); + return; + } +#endif + bh_assert(jit_compiler_is_compiled(module, func_idx)); + + /* Switch to jitted code to call the jit function */ + info.out.ret.last_return_type = type; + info.frame = frame; + frame->jitted_return_addr = + (uint8 *)jit_globals->return_to_interp_from_jitted; + action = jit_interp_switch_to_jitted( + exec_env, &info, func_idx, + module_inst->fast_jit_func_ptrs[func_idx_non_import]); + bh_assert(action == JIT_INTERP_ACTION_NORMAL + || (action == JIT_INTERP_ACTION_THROWN + && wasm_copy_exception( + (WASMModuleInstance *)exec_env->module_inst, NULL))); + + /* Get the return values form info.out.ret */ + if (func_type->result_count) { + switch (type) { + case VALUE_TYPE_I32: + *(frame->sp - function->ret_cell_num) = info.out.ret.ival[0]; + break; + case VALUE_TYPE_I64: + *(frame->sp - function->ret_cell_num) = info.out.ret.ival[0]; + *(frame->sp - function->ret_cell_num + 1) = + info.out.ret.ival[1]; + break; + case VALUE_TYPE_F32: + *(frame->sp - function->ret_cell_num) = info.out.ret.fval[0]; + break; + case VALUE_TYPE_F64: + *(frame->sp - function->ret_cell_num) = info.out.ret.fval[0]; + *(frame->sp - function->ret_cell_num + 1) = + info.out.ret.fval[1]; + break; + default: + bh_assert(0); + break; + } + } + (void)action; + (void)func_idx; +} +#endif /* end of WASM_ENABLE_FAST_JIT != 0 */ + +#if WASM_ENABLE_JIT != 0 +static bool +llvm_jit_call_func_bytecode(WASMModuleInstance *module_inst, + WASMExecEnv *exec_env, + WASMFunctionInstance *function, uint32 argc, + uint32 argv[]) +{ + WASMType *func_type = function->u.func->func_type; + uint32 result_count = func_type->result_count; + uint32 ext_ret_count = result_count > 1 ? result_count - 1 : 0; + uint32 func_idx = (uint32)(function - module_inst->e->functions); + bool ret; + +#if (WASM_ENABLE_DUMP_CALL_STACK != 0) || (WASM_ENABLE_PERF_PROFILING != 0) + if (!llvm_jit_alloc_frame(exec_env, function - module_inst->e->functions)) { + /* wasm operand stack overflow has been thrown, + no need to throw again */ + return false; + } +#endif + + if (ext_ret_count > 0) { + uint32 cell_num = 0, i; + uint8 *ext_ret_types = func_type->types + func_type->param_count + 1; + uint32 argv1_buf[32], *argv1 = argv1_buf, *ext_rets = NULL; + uint32 *argv_ret = argv; + uint32 ext_ret_cell = wasm_get_cell_num(ext_ret_types, ext_ret_count); + uint64 size; + + /* Allocate memory all arguments */ + size = + sizeof(uint32) * (uint64)argc /* original arguments */ + + sizeof(void *) + * (uint64)ext_ret_count /* extra result values' addr */ + + sizeof(uint32) * (uint64)ext_ret_cell; /* extra result values */ + if (size > sizeof(argv1_buf)) { + if (size > UINT32_MAX + || !(argv1 = wasm_runtime_malloc((uint32)size))) { + wasm_set_exception(module_inst, "allocate memory failed"); + return false; + } + } + + /* Copy original arguments */ + bh_memcpy_s(argv1, (uint32)size, argv, sizeof(uint32) * argc); + + /* Get the extra result value's address */ + ext_rets = + argv1 + argc + sizeof(void *) / sizeof(uint32) * ext_ret_count; + + /* Append each extra result value's address to original arguments */ + for (i = 0; i < ext_ret_count; i++) { + *(uintptr_t *)(argv1 + argc + sizeof(void *) / sizeof(uint32) * i) = + (uintptr_t)(ext_rets + cell_num); + cell_num += wasm_value_type_cell_num(ext_ret_types[i]); + } + + ret = wasm_runtime_invoke_native( + exec_env, module_inst->func_ptrs[func_idx], func_type, NULL, NULL, + argv1, argc, argv); + if (!ret) { + if (argv1 != argv1_buf) + wasm_runtime_free(argv1); + return ret; + } + + /* Get extra result values */ + switch (func_type->types[func_type->param_count]) { + case VALUE_TYPE_I32: + case VALUE_TYPE_F32: +#if WASM_ENABLE_REF_TYPES != 0 + case VALUE_TYPE_FUNCREF: + case VALUE_TYPE_EXTERNREF: +#endif + argv_ret++; + break; + case VALUE_TYPE_I64: + case VALUE_TYPE_F64: + argv_ret += 2; + break; +#if WASM_ENABLE_SIMD != 0 + case VALUE_TYPE_V128: + argv_ret += 4; + break; +#endif + default: + bh_assert(0); + break; + } + + ext_rets = + argv1 + argc + sizeof(void *) / sizeof(uint32) * ext_ret_count; + bh_memcpy_s(argv_ret, sizeof(uint32) * cell_num, ext_rets, + sizeof(uint32) * cell_num); + + if (argv1 != argv1_buf) + wasm_runtime_free(argv1); + return true; + } + else { + ret = wasm_runtime_invoke_native( + exec_env, module_inst->func_ptrs[func_idx], func_type, NULL, NULL, + argv, argc, argv); + + return ret && !wasm_copy_exception(module_inst, NULL) ? true : false; + } +} +#endif /* end of WASM_ENABLE_JIT != 0 */ + void wasm_interp_call_wasm(WASMModuleInstance *module_inst, WASMExecEnv *exec_env, WASMFunctionInstance *function, uint32 argc, @@ -3912,26 +4174,30 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, WASMExecEnv *exec_env, { WASMRuntimeFrame *prev_frame = wasm_exec_env_get_cur_frame(exec_env); WASMInterpFrame *frame, *outs_area; - /* Allocate sufficient cells for all kinds of return values. */ unsigned all_cell_num = - function->ret_cell_num > 2 ? function->ret_cell_num : 2, - i; + function->ret_cell_num > 2 ? function->ret_cell_num : 2; /* This frame won't be used by JITed code, so only allocate interp frame here. */ unsigned frame_size = wasm_interp_interp_frame_size(all_cell_num); + unsigned i; + bool copy_argv_from_frame = true; + char exception[EXCEPTION_BUF_LEN]; if (argc < function->param_cell_num) { char buf[128]; snprintf(buf, sizeof(buf), - "invalid argument count %u, must be no smaller than %u", argc, - function->param_cell_num); + "invalid argument count %" PRIu32 + ", must be no smaller than %u", + argc, function->param_cell_num); wasm_set_exception(module_inst, buf); return; } argc = function->param_cell_num; -#ifndef OS_ENABLE_HW_BOUND_CHECK + RECORD_STACK_USAGE(exec_env, (uint8 *)&prev_frame); +#if !(defined(OS_ENABLE_HW_BOUND_CHECK) \ + && WASM_DISABLE_STACK_HW_BOUND_CHECK == 0) if ((uint8 *)&prev_frame < exec_env->native_stack_boundary) { wasm_set_exception((WASMModuleInstance *)exec_env->module_inst, "native stack overflow"); @@ -3939,8 +4205,7 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, WASMExecEnv *exec_env, } #endif - if (!(frame = - ALLOC_FRAME(exec_env, frame_size, (WASMInterpFrame *)prev_frame))) + if (!(frame = ALLOC_FRAME(exec_env, frame_size, prev_frame))) return; outs_area = wasm_exec_env_wasm_stack_top(exec_env); @@ -3949,6 +4214,12 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, WASMExecEnv *exec_env, /* There is no local variable. */ frame->sp = frame->lp + 0; + if ((uint8 *)(outs_area->lp + function->param_cell_num) + > exec_env->wasm_stack.s.top_boundary) { + wasm_set_exception(module_inst, "wasm operand stack overflow"); + return; + } + if (argc > 0) word_copy(outs_area->lp, argv, argc); @@ -3969,62 +4240,64 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, WASMExecEnv *exec_env, } } else { -#if WASM_ENABLE_FAST_JIT == 0 - wasm_interp_call_func_bytecode(module_inst, exec_env, function, frame); -#else - JitGlobals *jit_globals = jit_compiler_get_jit_globals(); - JitInterpSwitchInfo info; - WASMType *func_type = function->u.func->func_type; - uint8 type = func_type->result_count - ? func_type->types[func_type->param_count] - : VALUE_TYPE_VOID; + RunningMode running_mode = + wasm_runtime_get_running_mode((wasm_module_inst_t)module_inst); -#if WASM_ENABLE_REF_TYPES != 0 - if (type == VALUE_TYPE_EXTERNREF || type == VALUE_TYPE_FUNCREF) - type = VALUE_TYPE_I32; -#endif - - info.out.ret.last_return_type = type; - info.frame = frame; - frame->jitted_return_addr = - (uint8 *)jit_globals->return_to_interp_from_jitted; - jit_interp_switch_to_jitted(exec_env, &info, - function->u.func->fast_jit_jitted_code); - if (func_type->result_count) { - switch (type) { - case VALUE_TYPE_I32: - *(frame->sp - function->ret_cell_num) = - info.out.ret.ival[0]; - break; - case VALUE_TYPE_I64: - *(frame->sp - function->ret_cell_num) = - info.out.ret.ival[0]; - *(frame->sp - function->ret_cell_num + 1) = - info.out.ret.ival[1]; - break; - case VALUE_TYPE_F32: - *(frame->sp - function->ret_cell_num) = - info.out.ret.fval[0]; - break; - case VALUE_TYPE_F64: - *(frame->sp - function->ret_cell_num) = - info.out.ret.fval[0]; - *(frame->sp - function->ret_cell_num + 1) = - info.out.ret.fval[1]; - break; - default: - bh_assert(0); - break; + if (running_mode == Mode_Interp) { + wasm_interp_call_func_bytecode(module_inst, exec_env, function, + frame); + } +#if WASM_ENABLE_FAST_JIT != 0 + else if (running_mode == Mode_Fast_JIT) { + fast_jit_call_func_bytecode(module_inst, exec_env, function, frame); + } +#endif +#if WASM_ENABLE_JIT != 0 + else if (running_mode == Mode_LLVM_JIT) { + llvm_jit_call_func_bytecode(module_inst, exec_env, function, argc, + argv); + /* For llvm jit, the results have been stored in argv, + no need to copy them from stack frame again */ + copy_argv_from_frame = false; + } +#endif +#if WASM_ENABLE_LAZY_JIT != 0 && WASM_ENABLE_FAST_JIT != 0 \ + && WASM_ENABLE_JIT != 0 + else if (running_mode == Mode_Multi_Tier_JIT) { + /* Tier-up from Fast JIT to LLVM JIT, call llvm jit function + if it is compiled, else call fast jit function */ + uint32 func_idx = (uint32)(function - module_inst->e->functions); + if (module_inst->module->func_ptrs_compiled + [func_idx - module_inst->module->import_function_count]) { + llvm_jit_call_func_bytecode(module_inst, exec_env, function, + argc, argv); + /* For llvm jit, the results have been stored in argv, + no need to copy them from stack frame again */ + copy_argv_from_frame = false; + } + else { + fast_jit_call_func_bytecode(module_inst, exec_env, function, + frame); } } +#endif + else { + /* There should always be a supported running mode selected */ + bh_assert(0); + } + (void)wasm_interp_call_func_bytecode; +#if WASM_ENABLE_FAST_JIT != 0 + (void)fast_jit_call_func_bytecode; #endif } /* Output the return value to the caller */ - if (!wasm_get_exception(module_inst)) { - for (i = 0; i < function->ret_cell_num; i++) { - argv[i] = *(frame->sp + i - function->ret_cell_num); + if (!wasm_copy_exception(module_inst, NULL)) { + if (copy_argv_from_frame) { + for (i = 0; i < function->ret_cell_num; i++) { + argv[i] = *(frame->sp + i - function->ret_cell_num); + } } } else { @@ -4033,7 +4306,8 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, WASMExecEnv *exec_env, wasm_interp_dump_call_stack(exec_env, true, NULL, 0); } #endif - LOG_DEBUG("meet an exception %s", wasm_get_exception(module_inst)); + wasm_copy_exception(module_inst, exception); + LOG_DEBUG("meet an exception %s", exception); } wasm_exec_env_set_cur_frame(exec_env, prev_frame); diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/interpreter/wasm_interp_fast.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm_interp_fast.c similarity index 92% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/interpreter/wasm_interp_fast.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm_interp_fast.c index 2f9c654a19e..6ddeaa9c0e4 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/interpreter/wasm_interp_fast.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm_interp_fast.c @@ -8,6 +8,7 @@ #include "wasm_runtime.h" #include "wasm_opcode.h" #include "wasm_loader.h" +#include "wasm_memory.h" #include "../common/wasm_exec_env.h" #if WASM_ENABLE_SHARED_MEMORY != 0 #include "../common/wasm_shared_memory.h" @@ -18,12 +19,23 @@ typedef int64 CellType_I64; typedef float32 CellType_F32; typedef float64 CellType_F64; +#if WASM_ENABLE_THREAD_MGR == 0 +#define get_linear_mem_size() linear_mem_size +#else +/** + * Load memory data size in each time boundary check in + * multi-threading mode since it may be changed by other + * threads in memory.grow + */ +#define get_linear_mem_size() memory->memory_data_size +#endif + #if !defined(OS_ENABLE_HW_BOUND_CHECK) \ || WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 #define CHECK_MEMORY_OVERFLOW(bytes) \ do { \ uint64 offset1 = (uint64)offset + (uint64)addr; \ - if (offset1 + bytes <= (uint64)linear_mem_size) \ + if (offset1 + bytes <= (uint64)get_linear_mem_size()) \ /* If offset1 is in valid range, maddr must also \ be in valid range, no need to check it again. */ \ maddr = memory->memory_data + offset1; \ @@ -34,7 +46,7 @@ typedef float64 CellType_F64; #define CHECK_BULK_MEMORY_OVERFLOW(start, bytes, maddr) \ do { \ uint64 offset1 = (uint32)(start); \ - if (offset1 + bytes <= linear_mem_size) \ + if (offset1 + bytes <= get_linear_mem_size()) \ /* App heap space is not valid space for \ bulk memory operation */ \ maddr = memory->memory_data + offset1; \ @@ -97,22 +109,48 @@ rotr64(uint64 n, uint64 c) return (n >> c) | (n << ((0 - c) & mask)); } -static inline double -wa_fmax(double a, double b) +static inline float32 +f32_min(float32 a, float32 b) +{ + if (isnan(a) || isnan(b)) + return NAN; + else if (a == 0 && a == b) + return signbit(a) ? a : b; + else + return a > b ? b : a; +} + +static inline float32 +f32_max(float32 a, float32 b) { - double c = fmax(a, b); - if (c == 0 && a == b) + if (isnan(a) || isnan(b)) + return NAN; + else if (a == 0 && a == b) return signbit(a) ? b : a; - return c; + else + return a > b ? a : b; } -static inline double -wa_fmin(double a, double b) +static inline float64 +f64_min(float64 a, float64 b) { - double c = fmin(a, b); - if (c == 0 && a == b) + if (isnan(a) || isnan(b)) + return NAN; + else if (a == 0 && a == b) return signbit(a) ? a : b; - return c; + else + return a > b ? b : a; +} + +static inline float64 +f64_max(float64 a, float64 b) +{ + if (isnan(a) || isnan(b)) + return NAN; + else if (a == 0 && a == b) + return signbit(a) ? b : a; + else + return a > b ? a : b; } static inline uint32 @@ -194,7 +232,7 @@ local_copysignf(float x, float y) { union { float f; - uint32_t i; + uint32 i; } ux = { x }, uy = { y }; ux.i &= 0x7fffffff; ux.i |= uy.i & 0x80000000; @@ -206,9 +244,9 @@ local_copysign(double x, double y) { union { double f; - uint64_t i; + uint64 i; } ux = { x }, uy = { y }; - ux.i &= -1ULL / 2; + ux.i &= UINT64_MAX / 2; ux.i |= uy.i & 1ULL << 63; return ux.f; } @@ -443,28 +481,28 @@ LOAD_PTR(void *addr) CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr); \ CHECK_ATOMIC_MEMORY_ACCESS(1); \ \ - os_mutex_lock(&memory->mem_lock); \ + os_mutex_lock(&node->shared_mem_lock); \ readv = (uint32)(*(uint8 *)maddr); \ *(uint8 *)maddr = (uint8)(readv op sval); \ - os_mutex_unlock(&memory->mem_lock); \ + os_mutex_unlock(&node->shared_mem_lock); \ } \ 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(&memory->mem_lock); \ + os_mutex_lock(&node->shared_mem_lock); \ readv = (uint32)LOAD_U16(maddr); \ STORE_U16(maddr, (uint16)(readv op sval)); \ - os_mutex_unlock(&memory->mem_lock); \ + os_mutex_unlock(&node->shared_mem_lock); \ } \ else { \ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); \ CHECK_ATOMIC_MEMORY_ACCESS(4); \ \ - os_mutex_lock(&memory->mem_lock); \ + os_mutex_lock(&node->shared_mem_lock); \ readv = LOAD_I32(maddr); \ STORE_U32(maddr, readv op sval); \ - os_mutex_unlock(&memory->mem_lock); \ + os_mutex_unlock(&node->shared_mem_lock); \ } \ PUSH_I32(readv); \ break; \ @@ -483,39 +521,39 @@ LOAD_PTR(void *addr) CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 1, maddr); \ CHECK_ATOMIC_MEMORY_ACCESS(1); \ \ - os_mutex_lock(&memory->mem_lock); \ + os_mutex_lock(&node->shared_mem_lock); \ readv = (uint64)(*(uint8 *)maddr); \ *(uint8 *)maddr = (uint8)(readv op sval); \ - os_mutex_unlock(&memory->mem_lock); \ + os_mutex_unlock(&node->shared_mem_lock); \ } \ 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(&memory->mem_lock); \ + os_mutex_lock(&node->shared_mem_lock); \ readv = (uint64)LOAD_U16(maddr); \ STORE_U16(maddr, (uint16)(readv op sval)); \ - os_mutex_unlock(&memory->mem_lock); \ + os_mutex_unlock(&node->shared_mem_lock); \ } \ 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(&memory->mem_lock); \ + os_mutex_lock(&node->shared_mem_lock); \ readv = (uint64)LOAD_U32(maddr); \ STORE_U32(maddr, (uint32)(readv op sval)); \ - os_mutex_unlock(&memory->mem_lock); \ + os_mutex_unlock(&node->shared_mem_lock); \ } \ else { \ uint64 op_result; \ CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr); \ CHECK_ATOMIC_MEMORY_ACCESS(8); \ \ - os_mutex_lock(&memory->mem_lock); \ + os_mutex_lock(&node->shared_mem_lock); \ readv = (uint64)LOAD_I64(maddr); \ op_result = readv op sval; \ STORE_I64(maddr, op_result); \ - os_mutex_unlock(&memory->mem_lock); \ + os_mutex_unlock(&node->shared_mem_lock); \ } \ PUSH_I64(readv); \ break; \ @@ -566,11 +604,11 @@ trunc_f32_to_int(WASMModuleInstance *module, uint8 *frame_ip, uint32 *frame_lp, if (!saturating) { if (isnan(src_value)) { wasm_set_exception(module, "invalid conversion to integer"); - return true; + return false; } else if (src_value <= src_min || src_value >= src_max) { wasm_set_exception(module, "integer overflow"); - return true; + return false; } } @@ -588,7 +626,7 @@ trunc_f32_to_int(WASMModuleInstance *module, uint8 *frame_ip, uint32 *frame_lp, dst_max, is_sign); SET_OPERAND(I64, 2, dst_value_i64); } - return false; + return true; } static bool @@ -603,11 +641,11 @@ trunc_f64_to_int(WASMModuleInstance *module, uint8 *frame_ip, uint32 *frame_lp, if (!saturating) { if (isnan(src_value)) { wasm_set_exception(module, "invalid conversion to integer"); - return true; + return false; } else if (src_value <= src_min || src_value >= src_max) { wasm_set_exception(module, "integer overflow"); - return true; + return false; } } @@ -625,23 +663,23 @@ trunc_f64_to_int(WASMModuleInstance *module, uint8 *frame_ip, uint32 *frame_lp, dst_max, is_sign); SET_OPERAND(I64, 2, dst_value_i64); } - return false; + return true; } -#define DEF_OP_TRUNC_F32(min, max, is_i32, is_sign) \ - do { \ - if (trunc_f32_to_int(module, frame_ip, frame_lp, min, max, false, \ - is_i32, is_sign)) \ - goto got_exception; \ - frame_ip += 4; \ +#define DEF_OP_TRUNC_F32(min, max, is_i32, is_sign) \ + do { \ + if (!trunc_f32_to_int(module, frame_ip, frame_lp, min, max, false, \ + is_i32, is_sign)) \ + goto got_exception; \ + frame_ip += 4; \ } while (0) -#define DEF_OP_TRUNC_F64(min, max, is_i32, is_sign) \ - do { \ - if (trunc_f64_to_int(module, frame_ip, frame_lp, min, max, false, \ - is_i32, is_sign)) \ - goto got_exception; \ - frame_ip += 4; \ +#define DEF_OP_TRUNC_F64(min, max, is_i32, is_sign) \ + do { \ + if (!trunc_f64_to_int(module, frame_ip, frame_lp, min, max, false, \ + is_i32, is_sign)) \ + goto got_exception; \ + frame_ip += 4; \ } while (0) #define DEF_OP_TRUNC_SAT_F32(min, max, is_i32, is_sign) \ @@ -869,26 +907,6 @@ FREE_FRAME(WASMExecEnv *exec_env, WASMInterpFrame *frame) wasm_exec_env_free_wasm_frame(exec_env, frame); } -void -wasm_interp_restore_wasm_frame(WASMExecEnv *exec_env) -{ - WASMInterpFrame *cur_frame, *prev_frame; - - cur_frame = wasm_exec_env_get_cur_frame(exec_env); - while (cur_frame) { - prev_frame = cur_frame->prev_frame; - if (cur_frame->ip) { - /* FREE_FRAME just set the wasm_stack.s.top pointer, we only need to - * call it once */ - FREE_FRAME(exec_env, cur_frame); - break; - } - cur_frame = prev_frame; - } - - wasm_exec_env_set_cur_frame(exec_env, cur_frame); -} - static void wasm_interp_call_func_native(WASMModuleInstance *module_inst, WASMExecEnv *exec_env, @@ -896,6 +914,7 @@ wasm_interp_call_func_native(WASMModuleInstance *module_inst, WASMInterpFrame *prev_frame) { WASMFunctionImport *func_import = cur_func->u.func_import; + CApiFuncImport *c_api_func_import = NULL; unsigned local_cell_num = 2; WASMInterpFrame *frame; uint32 argv_ret[2], cur_func_index; @@ -913,9 +932,15 @@ wasm_interp_call_func_native(WASMModuleInstance *module_inst, wasm_exec_env_set_cur_frame(exec_env, frame); - cur_func_index = (uint32)(cur_func - module_inst->functions); + cur_func_index = (uint32)(cur_func - module_inst->e->functions); bh_assert(cur_func_index < module_inst->module->import_function_count); - native_func_pointer = module_inst->import_func_ptrs[cur_func_index]; + if (!func_import->call_conv_wasm_c_api) { + native_func_pointer = module_inst->import_func_ptrs[cur_func_index]; + } + else if (module_inst->e->c_api_func_imports) { + c_api_func_import = module_inst->e->c_api_func_imports + cur_func_index; + native_func_pointer = c_api_func_import->func_ptr_linked; + } if (!native_func_pointer) { char buf[128]; @@ -930,7 +955,7 @@ wasm_interp_call_func_native(WASMModuleInstance *module_inst, ret = wasm_runtime_invoke_c_api_native( (WASMModuleInstanceCommon *)module_inst, native_func_pointer, func_import->func_type, cur_func->param_cell_num, frame->lp, - func_import->wasm_c_api_with_env, func_import->attachment); + c_api_func_import->with_env_arg, c_api_func_import->env_arg); if (ret) { argv_ret[0] = frame->lp[0]; argv_ret[1] = frame->lp[1]; @@ -1029,7 +1054,7 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst, exec_env->module_inst = (WASMModuleInstanceCommon *)module_inst; /* transfer exception if it is thrown */ - if (wasm_get_exception(sub_module_inst)) { + if (wasm_copy_exception(sub_module_inst, NULL)) { bh_memcpy_s(module_inst->cur_exception, sizeof(module_inst->cur_exception), sub_module_inst->cur_exception, @@ -1041,13 +1066,16 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst, #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); \ } while (0) #endif @@ -1138,16 +1166,19 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, WASMFunctionInstance *cur_func, WASMInterpFrame *prev_frame) { - WASMMemoryInstance *memory = module->default_memory; +#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 \ || WASM_ENABLE_BULK_MEMORY != 0 - uint32 num_bytes_per_page = memory ? memory->num_bytes_per_page : 0; - uint32 linear_mem_size = - memory ? num_bytes_per_page * memory->cur_page_count : 0; + uint32 linear_mem_size = memory ? memory->memory_data_size : 0; #endif + WASMGlobalInstance *globals = module->e ? module->e->globals : NULL; + WASMGlobalInstance *global; uint8 *global_data = module->global_data; - WASMGlobalInstance *globals = module->globals, *global; uint8 opcode_IMPDEP = WASM_OP_IMPDEP; WASMInterpFrame *frame = NULL; /* Points to this special opcode so as to jump to the @@ -1162,7 +1193,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, #endif uint8 *frame_ip_end = frame_ip + 1; uint32 cond, count, fidx, tidx, frame_size = 0; - uint64 all_cell_num = 0; + uint32 all_cell_num = 0; int16 addr1, addr2, addr_ret = 0; int32 didx, val; uint8 *maddr = NULL; @@ -1345,8 +1376,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, goto got_exception; } - fidx = ((uint32 *)tbl_inst->base_addr)[val]; - if (fidx == (uint32)-1) { + fidx = tbl_inst->elems[val]; + if (fidx == NULL_REF) { wasm_set_exception(module, "uninitialized element"); goto got_exception; } @@ -1356,13 +1387,13 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, * another module. in that case, we don't validate * the elem value while loading */ - if (fidx >= module->function_count) { + if (fidx >= module->e->function_count) { wasm_set_exception(module, "unknown function"); goto got_exception; } /* always call module own functions */ - cur_func = module->functions + fidx; + cur_func = module->e->functions + fidx; if (cur_func->is_import_func) cur_func_type = cur_func->u.func_import->func_type; @@ -1437,7 +1468,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, goto got_exception; } - PUSH_I32(((uint32 *)tbl_inst->base_addr)[elem_idx]); + PUSH_I32(tbl_inst->elems[elem_idx]); HANDLE_OP_END(); } @@ -1458,7 +1489,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, goto got_exception; } - ((uint32 *)tbl_inst->base_addr)[elem_idx] = elem_val; + tbl_inst->elems[elem_idx] = elem_val; HANDLE_OP_END(); } @@ -1522,7 +1553,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP(WASM_OP_GET_GLOBAL) { global_idx = read_uint32(frame_ip); - bh_assert(global_idx < module->global_count); + bh_assert(global_idx < module->e->global_count); global = globals + global_idx; global_addr = get_global_addr(global_data, global); addr_ret = GET_OFFSET(); @@ -1533,7 +1564,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP(WASM_OP_GET_GLOBAL_64) { global_idx = read_uint32(frame_ip); - bh_assert(global_idx < module->global_count); + bh_assert(global_idx < module->e->global_count); global = globals + global_idx; global_addr = get_global_addr(global_data, global); addr_ret = GET_OFFSET(); @@ -1545,7 +1576,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP(WASM_OP_SET_GLOBAL) { global_idx = read_uint32(frame_ip); - bh_assert(global_idx < module->global_count); + bh_assert(global_idx < module->e->global_count); global = globals + global_idx; global_addr = get_global_addr(global_data, global); addr1 = GET_OFFSET(); @@ -1558,7 +1589,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, uint32 aux_stack_top; global_idx = read_uint32(frame_ip); - bh_assert(global_idx < module->global_count); + bh_assert(global_idx < module->e->global_count); global = globals + global_idx; global_addr = get_global_addr(global_data, global); aux_stack_top = frame_lp[GET_OFFSET()]; @@ -1576,8 +1607,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, if (module->module->aux_stack_top_global_index != (uint32)-1) { uint32 aux_stack_used = module->module->aux_stack_bottom - *(uint32 *)global_addr; - if (aux_stack_used > module->max_aux_stack_used) - module->max_aux_stack_used = aux_stack_used; + if (aux_stack_used > module->e->max_aux_stack_used) + module->e->max_aux_stack_used = aux_stack_used; } #endif HANDLE_OP_END(); @@ -1586,7 +1617,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, HANDLE_OP(WASM_OP_SET_GLOBAL_64) { global_idx = read_uint32(frame_ip); - bh_assert(global_idx < module->global_count); + bh_assert(global_idx < module->e->global_count); global = globals + global_idx; global_addr = get_global_addr(global_data, global); addr1 = GET_OFFSET(); @@ -1860,13 +1891,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, else { /* success, return previous page count */ frame_lp[addr_ret] = prev_page_count; - /* update memory instance ptr and memory size */ - memory = module->default_memory; + /* update memory size, no need to update memory ptr as + it isn't changed in wasm_enlarge_memory */ #if !defined(OS_ENABLE_HW_BOUND_CHECK) \ || WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 \ || WASM_ENABLE_BULK_MEMORY != 0 - linear_mem_size = - num_bytes_per_page * memory->cur_page_count; + linear_mem_size = memory->memory_data_size; #endif } @@ -2516,13 +2546,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, b = *(float32 *)(frame_lp + GET_OFFSET()); a = *(float32 *)(frame_lp + GET_OFFSET()); - if (isnan(a)) - *(float32 *)(frame_lp + GET_OFFSET()) = a; - else if (isnan(b)) - *(float32 *)(frame_lp + GET_OFFSET()) = b; - else - *(float32 *)(frame_lp + GET_OFFSET()) = - (float32)wa_fmin(a, b); + *(float32 *)(frame_lp + GET_OFFSET()) = f32_min(a, b); HANDLE_OP_END(); } @@ -2533,13 +2557,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, b = *(float32 *)(frame_lp + GET_OFFSET()); a = *(float32 *)(frame_lp + GET_OFFSET()); - if (isnan(a)) - *(float32 *)(frame_lp + GET_OFFSET()) = a; - else if (isnan(b)) - *(float32 *)(frame_lp + GET_OFFSET()) = b; - else - *(float32 *)(frame_lp + GET_OFFSET()) = - (float32)wa_fmax(a, b); + *(float32 *)(frame_lp + GET_OFFSET()) = f32_max(a, b); HANDLE_OP_END(); } @@ -2634,12 +2652,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, b = POP_F64(); a = POP_F64(); - if (isnan(a)) - PUSH_F64(a); - else if (isnan(b)) - PUSH_F64(b); - else - PUSH_F64(wa_fmin(a, b)); + PUSH_F64(f64_min(a, b)); HANDLE_OP_END(); } @@ -2650,12 +2663,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, b = POP_F64(); a = POP_F64(); - if (isnan(a)) - PUSH_F64(a); - else if (isnan(b)) - PUSH_F64(b); - else - PUSH_F64(wa_fmax(a, b)); + PUSH_F64(f64_max(a, b)); HANDLE_OP_END(); } @@ -2970,6 +2978,10 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, offset = (uint64)POP_I32(); addr = POP_I32(); +#if WASM_ENABLE_THREAD_MGR + linear_mem_size = memory->memory_data_size; +#endif + #ifndef OS_ENABLE_HW_BOUND_CHECK CHECK_BULK_MEMORY_OVERFLOW(addr, bytes, maddr); #else @@ -3007,6 +3019,10 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, src = POP_I32(); dst = POP_I32(); +#if WASM_ENABLE_THREAD_MGR + linear_mem_size = memory->memory_data_size; +#endif + #ifndef OS_ENABLE_HW_BOUND_CHECK CHECK_BULK_MEMORY_OVERFLOW(src, len, msrc); CHECK_BULK_MEMORY_OVERFLOW(dst, len, mdst); @@ -3033,6 +3049,10 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, fill_val = POP_I32(); dst = POP_I32(); +#if WASM_ENABLE_THREAD_MGR + linear_mem_size = memory->memory_data_size; +#endif + #ifndef OS_ENABLE_HW_BOUND_CHECK CHECK_BULK_MEMORY_OVERFLOW(dst, len, mdst); #else @@ -3093,7 +3113,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, bh_memcpy_s( (uint8 *)tbl_inst - + offsetof(WASMTableInstance, base_addr) + + offsetof(WASMTableInstance, elems) + d * sizeof(uint32), (uint32)((tbl_inst->cur_size - d) * sizeof(uint32)), module->module->table_segments[elem_idx] @@ -3141,16 +3161,15 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, /* if s >= d, copy from front to back */ /* if s < d, copy from back to front */ /* merge all together */ - bh_memmove_s( - (uint8 *)dst_tbl_inst - + offsetof(WASMTableInstance, base_addr) - + d * sizeof(uint32), - (uint32)((dst_tbl_inst->cur_size - d) - * sizeof(uint32)), - (uint8 *)src_tbl_inst - + offsetof(WASMTableInstance, base_addr) - + s * sizeof(uint32), - (uint32)(n * sizeof(uint32))); + bh_memmove_s((uint8 *)dst_tbl_inst + + offsetof(WASMTableInstance, elems) + + d * sizeof(uint32), + (uint32)((dst_tbl_inst->cur_size - d) + * sizeof(uint32)), + (uint8 *)src_tbl_inst + + offsetof(WASMTableInstance, elems) + + s * sizeof(uint32), + (uint32)(n * sizeof(uint32))); break; } case WASM_OP_TABLE_GROW: @@ -3211,7 +3230,7 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, } for (; n != 0; i++, n--) { - ((uint32 *)(tbl_inst->base_addr))[i] = fill_val; + tbl_inst->elems[i] = fill_val; } break; @@ -3248,7 +3267,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, ret = wasm_runtime_atomic_notify( (WASMModuleInstanceCommon *)module, maddr, notify_count); - bh_assert((int32)ret >= 0); + if (ret == (uint32)-1) + goto got_exception; PUSH_I32(ret); break; @@ -3270,6 +3290,10 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, if (ret == (uint32)-1) goto got_exception; +#if WASM_ENABLE_THREAD_MGR != 0 + CHECK_SUSPEND_FLAGS(); +#endif + PUSH_I32(ret); break; } @@ -3290,9 +3314,18 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, if (ret == (uint32)-1) goto got_exception; +#if WASM_ENABLE_THREAD_MGR != 0 + CHECK_SUSPEND_FLAGS(); +#endif + PUSH_I32(ret); break; } + case WASM_OP_ATOMIC_FENCE: + { + os_atomic_thread_fence(os_memory_order_seq_cst); + break; + } case WASM_OP_ATOMIC_I32_LOAD: case WASM_OP_ATOMIC_I32_LOAD8_U: @@ -3305,23 +3338,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(&memory->mem_lock); + os_mutex_lock(&node->shared_mem_lock); readv = (uint32)(*(uint8 *)maddr); - os_mutex_unlock(&memory->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } 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(&memory->mem_lock); + os_mutex_lock(&node->shared_mem_lock); readv = (uint32)LOAD_U16(maddr); - os_mutex_unlock(&memory->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } else { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); CHECK_ATOMIC_MEMORY_ACCESS(4); - os_mutex_lock(&memory->mem_lock); + os_mutex_lock(&node->shared_mem_lock); readv = LOAD_I32(maddr); - os_mutex_unlock(&memory->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } PUSH_I32(readv); @@ -3340,30 +3373,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(&memory->mem_lock); + os_mutex_lock(&node->shared_mem_lock); readv = (uint64)(*(uint8 *)maddr); - os_mutex_unlock(&memory->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } 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(&memory->mem_lock); + os_mutex_lock(&node->shared_mem_lock); readv = (uint64)LOAD_U16(maddr); - os_mutex_unlock(&memory->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } 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(&memory->mem_lock); + os_mutex_lock(&node->shared_mem_lock); readv = (uint64)LOAD_U32(maddr); - os_mutex_unlock(&memory->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } else { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr); CHECK_ATOMIC_MEMORY_ACCESS(8); - os_mutex_lock(&memory->mem_lock); + os_mutex_lock(&node->shared_mem_lock); readv = LOAD_I64(maddr); - os_mutex_unlock(&memory->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } PUSH_I64(readv); @@ -3381,23 +3414,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(&memory->mem_lock); + os_mutex_lock(&node->shared_mem_lock); *(uint8 *)maddr = (uint8)sval; - os_mutex_unlock(&memory->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } else if (opcode == WASM_OP_ATOMIC_I32_STORE16) { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr); CHECK_ATOMIC_MEMORY_ACCESS(2); - os_mutex_lock(&memory->mem_lock); + os_mutex_lock(&node->shared_mem_lock); STORE_U16(maddr, (uint16)sval); - os_mutex_unlock(&memory->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } else { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); CHECK_ATOMIC_MEMORY_ACCESS(4); - os_mutex_lock(&memory->mem_lock); + os_mutex_lock(&node->shared_mem_lock); STORE_U32(maddr, sval); - os_mutex_unlock(&memory->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } break; } @@ -3415,30 +3448,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(&memory->mem_lock); + os_mutex_lock(&node->shared_mem_lock); *(uint8 *)maddr = (uint8)sval; - os_mutex_unlock(&memory->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } else if (opcode == WASM_OP_ATOMIC_I64_STORE16) { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 2, maddr); CHECK_ATOMIC_MEMORY_ACCESS(2); - os_mutex_lock(&memory->mem_lock); + os_mutex_lock(&node->shared_mem_lock); STORE_U16(maddr, (uint16)sval); - os_mutex_unlock(&memory->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } else if (opcode == WASM_OP_ATOMIC_I64_STORE32) { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); CHECK_ATOMIC_MEMORY_ACCESS(4); - os_mutex_lock(&memory->mem_lock); + os_mutex_lock(&node->shared_mem_lock); STORE_U32(maddr, (uint32)sval); - os_mutex_unlock(&memory->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } else { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr); CHECK_ATOMIC_MEMORY_ACCESS(8); - os_mutex_lock(&memory->mem_lock); + os_mutex_lock(&node->shared_mem_lock); STORE_I64(maddr, sval); - os_mutex_unlock(&memory->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } break; } @@ -3458,32 +3491,32 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, CHECK_ATOMIC_MEMORY_ACCESS(1); expect = (uint8)expect; - os_mutex_lock(&memory->mem_lock); + os_mutex_lock(&node->shared_mem_lock); readv = (uint32)(*(uint8 *)maddr); if (readv == expect) *(uint8 *)maddr = (uint8)(sval); - os_mutex_unlock(&memory->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } 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(&memory->mem_lock); + os_mutex_lock(&node->shared_mem_lock); readv = (uint32)LOAD_U16(maddr); if (readv == expect) STORE_U16(maddr, (uint16)(sval)); - os_mutex_unlock(&memory->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } else { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 4, maddr); CHECK_ATOMIC_MEMORY_ACCESS(4); - os_mutex_lock(&memory->mem_lock); + os_mutex_lock(&node->shared_mem_lock); readv = LOAD_I32(maddr); if (readv == expect) STORE_U32(maddr, sval); - os_mutex_unlock(&memory->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } PUSH_I32(readv); break; @@ -3504,44 +3537,43 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, CHECK_ATOMIC_MEMORY_ACCESS(1); expect = (uint8)expect; - os_mutex_lock(&memory->mem_lock); + os_mutex_lock(&node->shared_mem_lock); readv = (uint64)(*(uint8 *)maddr); if (readv == expect) *(uint8 *)maddr = (uint8)(sval); - os_mutex_unlock(&memory->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } 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(&memory->mem_lock); + os_mutex_lock(&node->shared_mem_lock); readv = (uint64)LOAD_U16(maddr); if (readv == expect) STORE_U16(maddr, (uint16)(sval)); - os_mutex_unlock(&memory->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } 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(&memory->mem_lock); + os_mutex_lock(&node->shared_mem_lock); readv = (uint64)LOAD_U32(maddr); if (readv == expect) STORE_U32(maddr, (uint32)(sval)); - os_mutex_unlock(&memory->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } else { CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr); CHECK_ATOMIC_MEMORY_ACCESS(8); - os_mutex_lock(&memory->mem_lock); + os_mutex_lock(&node->shared_mem_lock); readv = (uint64)LOAD_I64(maddr); - if (readv == expect) { + if (readv == expect) STORE_I64(maddr, sval); - } - os_mutex_unlock(&memory->mem_lock); + os_mutex_unlock(&node->shared_mem_lock); } PUSH_I64(readv); break; @@ -3575,12 +3607,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, #endif fidx = read_uint32(frame_ip); #if WASM_ENABLE_MULTI_MODULE != 0 - if (fidx >= module->function_count) { + if (fidx >= module->e->function_count) { wasm_set_exception(module, "unknown function"); goto got_exception; } #endif - cur_func = module->functions + fidx; + cur_func = module->e->functions + fidx; goto call_func_from_interp; } @@ -3592,12 +3624,12 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, #endif fidx = read_uint32(frame_ip); #if WASM_ENABLE_MULTI_MODULE != 0 - if (fidx >= module->function_count) { + if (fidx >= module->e->function_count) { wasm_set_exception(module, "unknown function"); goto got_exception; } #endif - cur_func = module->functions + fidx; + cur_func = module->e->functions + fidx; goto call_func_from_return_call; } #endif /* WASM_ENABLE_TAIL_CALL */ @@ -3782,30 +3814,29 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, cur_func = frame->function; UPDATE_ALL_FROM_FRAME(); - /* update memory instance ptr and memory size */ - memory = module->default_memory; + /* update memory size, no need to update memory ptr as + it isn't changed in wasm_enlarge_memory */ #if !defined(OS_ENABLE_HW_BOUND_CHECK) \ || WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 \ || WASM_ENABLE_BULK_MEMORY != 0 if (memory) - linear_mem_size = num_bytes_per_page * memory->cur_page_count; + linear_mem_size = memory->memory_data_size; #endif - if (wasm_get_exception(module)) + if (wasm_copy_exception(module, NULL)) goto got_exception; } else { WASMFunction *cur_wasm_func = cur_func->u.func; - all_cell_num = (uint64)cur_func->param_cell_num - + (uint64)cur_func->local_cell_num - + (uint64)cur_func->const_cell_num - + (uint64)cur_wasm_func->max_stack_cell_num; - if (all_cell_num >= UINT32_MAX) { - wasm_set_exception(module, "wasm operand stack overflow"); - goto got_exception; - } + all_cell_num = cur_func->param_cell_num + cur_func->local_cell_num + + cur_func->const_cell_num + + cur_wasm_func->max_stack_cell_num; + /* param_cell_num, local_cell_num, const_cell_num and + max_stack_cell_num are all no larger than UINT16_MAX (checked + in loader), all_cell_num must be smaller than 1MB */ + bh_assert(all_cell_num < 1 * BH_MB); - frame_size = wasm_interp_interp_frame_size((uint32)all_cell_num); + frame_size = wasm_interp_interp_frame_size(all_cell_num); if (!(frame = ALLOC_FRAME(exec_env, frame_size, prev_frame))) { frame = prev_frame; goto got_exception; @@ -3831,6 +3862,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, wasm_exec_env_set_cur_frame(exec_env, (WASMRuntimeFrame *)frame); } +#if WASM_ENABLE_THREAD_MGR != 0 + CHECK_SUSPEND_FLAGS(); +#endif HANDLE_OP_END(); } @@ -3899,6 +3933,7 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, WASMExecEnv *exec_env, /* This frame won't be used by JITed code, so only allocate interp frame here. */ unsigned frame_size = wasm_interp_interp_frame_size(all_cell_num); + char exception[EXCEPTION_BUF_LEN]; if (argc < function->param_cell_num) { char buf[128]; @@ -3911,7 +3946,9 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, WASMExecEnv *exec_env, } argc = function->param_cell_num; -#ifndef OS_ENABLE_HW_BOUND_CHECK + RECORD_STACK_USAGE(exec_env, (uint8 *)&prev_frame); +#if !(defined(OS_ENABLE_HW_BOUND_CHECK) \ + && WASM_DISABLE_STACK_HW_BOUND_CHECK == 0) if ((uint8 *)&prev_frame < exec_env->native_stack_boundary) { wasm_set_exception((WASMModuleInstance *)exec_env->module_inst, "native stack overflow"); @@ -3962,7 +3999,7 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, WASMExecEnv *exec_env, } /* Output the return value to the caller */ - if (!wasm_get_exception(module_inst)) { + if (!wasm_copy_exception(module_inst, NULL)) { for (i = 0; i < function->ret_cell_num; i++) argv[i] = *(frame->lp + i); } @@ -3972,7 +4009,8 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst, WASMExecEnv *exec_env, wasm_interp_dump_call_stack(exec_env, true, NULL, 0); } #endif - LOG_DEBUG("meet an exception %s", wasm_get_exception(module_inst)); + wasm_copy_exception(module_inst, exception); + LOG_DEBUG("meet an exception %s", exception); } wasm_exec_env_set_cur_frame(exec_env, prev_frame); diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/interpreter/wasm_loader.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm_loader.c similarity index 93% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/interpreter/wasm_loader.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm_loader.c index e5941b7b360..a3c4f422490 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/interpreter/wasm_loader.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm_loader.c @@ -18,6 +18,9 @@ #include "../fast-jit/jit_compiler.h" #include "../fast-jit/jit_codecache.h" #endif +#if WASM_ENABLE_JIT != 0 +#include "../compilation/aot_llvm.h" +#endif /* Read a value of given type from the address pointed to by the given pointer and increase the pointer to the position just after the @@ -425,6 +428,12 @@ destroy_wasm_type(WASMType *type) return; } +#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \ + && WASM_ENABLE_LAZY_JIT != 0 + if (type->call_to_llvm_jit_from_fast_jit) + jit_code_cache_free(type->call_to_llvm_jit_from_fast_jit); +#endif + wasm_runtime_free(type); } @@ -675,7 +684,7 @@ adjust_table_max_size(uint32 init_size, uint32 max_size_flag, uint32 *max_size) } } -#if WASM_ENABLE_MULTI_MODULE != 0 +#if WASM_ENABLE_LIBC_WASI != 0 || WASM_ENABLE_MULTI_MODULE != 0 /** * Find export item of a module with export info: * module name, field name and export kind @@ -687,7 +696,6 @@ wasm_loader_find_export(const WASMModule *module, const char *module_name, { WASMExport *export; uint32 i; - uint32 export_index_boundary = 0; for (i = 0, export = module->exports; i < module->export_count; ++i, ++export) { @@ -710,37 +718,15 @@ wasm_loader_find_export(const WASMModule *module, const char *module_name, return NULL; } - switch (export_kind) { - case EXPORT_KIND_FUNC: - export_index_boundary = - module->import_function_count + module->function_count; - break; - case EXPORT_KIND_GLOBAL: - export_index_boundary = - module->import_global_count + module->global_count; - break; - case EXPORT_KIND_MEMORY: - export_index_boundary = - module->import_memory_count + module->memory_count; - break; - case EXPORT_KIND_TABLE: - export_index_boundary = - module->import_table_count + module->table_count; - break; - default: - bh_assert(0); - } - - if (export->index >= export_index_boundary) { - LOG_DEBUG("%s in the module %s is out of index (%d >= %d )", field_name, - module_name, export->index, export_index_boundary); - set_error_buf(error_buf, error_buf_size, "incompatible import type"); - return NULL; - } + (void)module_name; + /* since there is a validation in load_export_section(), it is for sure + * export->index is valid*/ return export; } +#endif +#if WASM_ENABLE_MULTI_MODULE != 0 static WASMFunction * wasm_loader_resolve_function(const char *module_name, const char *function_name, const WASMType *expected_function_type, @@ -1258,6 +1244,8 @@ load_table_import(const uint8 **p_buf, const uint8 *buf_end, table->init_size = declare_init_size; table->flags = declare_max_size_flag; table->max_size = declare_max_size; + + (void)parent_module; return true; fail: return false; @@ -1391,6 +1379,8 @@ load_memory_import(const uint8 **p_buf, const uint8 *buf_end, memory->num_bytes_per_page = DEFAULT_NUM_BYTES_PER_PAGE; *p_buf = p; + + (void)parent_module; return true; fail: return false; @@ -1409,6 +1399,7 @@ load_global_import(const uint8 **p_buf, const uint8 *buf_end, WASMModule *sub_module = NULL; WASMGlobal *linked_global = NULL; #endif + bool ret = false; CHECK_BUF(p, p_end, 2); declare_type = read_uint8(p); @@ -1421,15 +1412,16 @@ load_global_import(const uint8 **p_buf, const uint8 *buf_end, } #if WASM_ENABLE_LIBC_BUILTIN != 0 - global->is_linked = wasm_native_lookup_libc_builtin_global( - sub_module_name, global_name, global); - if (global->is_linked) { + ret = wasm_native_lookup_libc_builtin_global(sub_module_name, global_name, + global); + if (ret) { if (global->type != declare_type || global->is_mutable != declare_mutable) { set_error_buf(error_buf, error_buf_size, "incompatible import type"); return false; } + global->is_linked = true; } #endif #if WASM_ENABLE_MULTI_MODULE != 0 @@ -1457,6 +1449,9 @@ load_global_import(const uint8 **p_buf, const uint8 *buf_end, global->field_name = global_name; global->type = declare_type; global->is_mutable = (declare_mutable == 1); + + (void)parent_module; + (void)ret; return true; fail: return false; @@ -2399,6 +2394,7 @@ load_func_index_vec(const uint8 **p_buf, const uint8 *buf_end, } #else read_leb_uint32(p, p_end, function_index); + (void)use_init_expr; #endif /* since we are using -1 to indicate ref.null */ @@ -2708,6 +2704,7 @@ load_code_section(const uint8 *buf, const uint8 *buf_end, const uint8 *buf_func, } LOG_VERBOSE("Load code segment section success.\n"); + (void)module; return true; fail: return false; @@ -2812,8 +2809,8 @@ handle_name_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, read_leb_uint32(p, p_end, func_name_len); CHECK_BUF(p, p_end, func_name_len); /* Skip the import functions */ - if (func_index >= module->import_count) { - func_index -= module->import_count; + if (func_index >= module->import_function_count) { + func_index -= module->import_function_count; if (func_index >= module->function_count) { set_error_buf(error_buf, error_buf_size, "out-of-range function index"); @@ -2918,12 +2915,13 @@ load_user_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, LOG_VERBOSE("Ignore custom section [%s].", section_name); + (void)is_load_from_file_buf; + (void)module; return true; fail: return false; } -#if WASM_ENABLE_FAST_JIT != 0 static void calculate_global_data_offset(WASMModule *module) { @@ -2933,17 +2931,460 @@ calculate_global_data_offset(WASMModule *module) for (i = 0; i < module->import_global_count; i++) { WASMGlobalImport *import_global = &((module->import_globals + i)->u.global); +#if WASM_ENABLE_FAST_JIT != 0 import_global->data_offset = data_offset; +#endif data_offset += wasm_value_type_size(import_global->type); } for (i = 0; i < module->global_count; i++) { WASMGlobal *global = module->globals + i; +#if WASM_ENABLE_FAST_JIT != 0 global->data_offset = data_offset; +#endif data_offset += wasm_value_type_size(global->type); } + + module->global_data_size = data_offset; +} + +#if WASM_ENABLE_FAST_JIT != 0 +static bool +init_fast_jit_functions(WASMModule *module, char *error_buf, + uint32 error_buf_size) +{ +#if WASM_ENABLE_LAZY_JIT != 0 + JitGlobals *jit_globals = jit_compiler_get_jit_globals(); +#endif + uint32 i; + + if (!module->function_count) + return true; + + if (!(module->fast_jit_func_ptrs = + loader_malloc(sizeof(void *) * module->function_count, error_buf, + error_buf_size))) { + return false; + } + +#if WASM_ENABLE_LAZY_JIT != 0 + for (i = 0; i < module->function_count; i++) { + module->fast_jit_func_ptrs[i] = + jit_globals->compile_fast_jit_and_then_call; + } +#endif + + for (i = 0; i < WASM_ORC_JIT_BACKEND_THREAD_NUM; i++) { + if (os_mutex_init(&module->fast_jit_thread_locks[i]) != 0) { + set_error_buf(error_buf, error_buf_size, + "init fast jit thread lock failed"); + return false; + } + module->fast_jit_thread_locks_inited[i] = true; + } + + return true; +} +#endif /* end of WASM_ENABLE_FAST_JIT != 0 */ + +#if WASM_ENABLE_JIT != 0 +static bool +init_llvm_jit_functions_stage1(WASMModule *module, char *error_buf, + uint32 error_buf_size) +{ + LLVMJITOptions llvm_jit_options = wasm_runtime_get_llvm_jit_options(); + AOTCompOption option = { 0 }; + char *aot_last_error; + uint64 size; + + if (module->function_count == 0) + return true; + +#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_LLVM_JIT != 0 + if (os_mutex_init(&module->tierup_wait_lock) != 0) { + set_error_buf(error_buf, error_buf_size, "init jit tierup lock failed"); + return false; + } + if (os_cond_init(&module->tierup_wait_cond) != 0) { + set_error_buf(error_buf, error_buf_size, "init jit tierup cond failed"); + os_mutex_destroy(&module->tierup_wait_lock); + return false; + } + module->tierup_wait_lock_inited = true; +#endif + + size = sizeof(void *) * (uint64)module->function_count + + sizeof(bool) * (uint64)module->function_count; + if (!(module->func_ptrs = loader_malloc(size, error_buf, error_buf_size))) { + return false; + } + module->func_ptrs_compiled = + (bool *)((uint8 *)module->func_ptrs + + sizeof(void *) * module->function_count); + + module->comp_data = aot_create_comp_data(module); + if (!module->comp_data) { + aot_last_error = aot_get_last_error(); + bh_assert(aot_last_error != NULL); + set_error_buf(error_buf, error_buf_size, aot_last_error); + return false; + } + + option.is_jit_mode = true; + + llvm_jit_options = wasm_runtime_get_llvm_jit_options(); + option.opt_level = llvm_jit_options.opt_level; + option.size_level = llvm_jit_options.size_level; + +#if WASM_ENABLE_BULK_MEMORY != 0 + option.enable_bulk_memory = true; +#endif +#if WASM_ENABLE_THREAD_MGR != 0 + option.enable_thread_mgr = true; +#endif +#if WASM_ENABLE_TAIL_CALL != 0 + option.enable_tail_call = true; +#endif +#if WASM_ENABLE_SIMD != 0 + option.enable_simd = true; +#endif +#if WASM_ENABLE_REF_TYPES != 0 + option.enable_ref_types = true; +#endif + option.enable_aux_stack_check = true; +#if (WASM_ENABLE_PERF_PROFILING != 0) || (WASM_ENABLE_DUMP_CALL_STACK != 0) + option.enable_aux_stack_frame = true; +#endif +#if WASM_ENABLE_MEMORY_PROFILING != 0 + option.enable_stack_estimation = true; +#endif + + module->comp_ctx = aot_create_comp_context(module->comp_data, &option); + if (!module->comp_ctx) { + aot_last_error = aot_get_last_error(); + bh_assert(aot_last_error != NULL); + set_error_buf(error_buf, error_buf_size, aot_last_error); + return false; + } + + return true; +} + +static bool +init_llvm_jit_functions_stage2(WASMModule *module, char *error_buf, + uint32 error_buf_size) +{ + char *aot_last_error; + uint32 i; + + if (module->function_count == 0) + return true; + + if (!aot_compile_wasm(module->comp_ctx)) { + aot_last_error = aot_get_last_error(); + bh_assert(aot_last_error != NULL); + set_error_buf(error_buf, error_buf_size, aot_last_error); + return false; + } + +#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_LAZY_JIT != 0 + if (module->orcjit_stop_compiling) + return false; +#endif + + bh_print_time("Begin to lookup llvm jit functions"); + + for (i = 0; i < module->function_count; i++) { + LLVMOrcJITTargetAddress func_addr = 0; + LLVMErrorRef error; + char func_name[48]; + + snprintf(func_name, sizeof(func_name), "%s%d", AOT_FUNC_PREFIX, i); + error = LLVMOrcLLLazyJITLookup(module->comp_ctx->orc_jit, &func_addr, + func_name); + if (error != LLVMErrorSuccess) { + char *err_msg = LLVMGetErrorMessage(error); + set_error_buf_v(error_buf, error_buf_size, + "failed to compile llvm jit function: %s", err_msg); + LLVMDisposeErrorMessage(err_msg); + return false; + } + + /** + * No need to lock the func_ptr[func_idx] here as it is basic + * data type, the load/store for it can be finished by one cpu + * instruction, and there can be only one cpu instruction + * loading/storing at the same time. + */ + module->func_ptrs[i] = (void *)func_addr; + +#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_LAZY_JIT != 0 + module->functions[i]->llvm_jit_func_ptr = (void *)func_addr; + + if (module->orcjit_stop_compiling) + return false; +#endif + } + + bh_print_time("End lookup llvm jit functions"); + + return true; +} +#endif /* end of WASM_ENABLE_JIT != 0 */ + +#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \ + && WASM_ENABLE_LAZY_JIT != 0 +static void * +init_llvm_jit_functions_stage2_callback(void *arg) +{ + WASMModule *module = (WASMModule *)arg; + char error_buf[128]; + uint32 error_buf_size = (uint32)sizeof(error_buf); + + if (!init_llvm_jit_functions_stage2(module, error_buf, error_buf_size)) { + module->orcjit_stop_compiling = true; + return NULL; + } + + os_mutex_lock(&module->tierup_wait_lock); + module->llvm_jit_inited = true; + os_cond_broadcast(&module->tierup_wait_cond); + os_mutex_unlock(&module->tierup_wait_lock); + + return NULL; +} +#endif + +#if WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0 +/* The callback function to compile jit functions */ +static void * +orcjit_thread_callback(void *arg) +{ + OrcJitThreadArg *thread_arg = (OrcJitThreadArg *)arg; +#if WASM_ENABLE_JIT != 0 + AOTCompContext *comp_ctx = thread_arg->comp_ctx; +#endif + WASMModule *module = thread_arg->module; + uint32 group_idx = thread_arg->group_idx; + uint32 group_stride = WASM_ORC_JIT_BACKEND_THREAD_NUM; + uint32 func_count = module->function_count; + uint32 i; + +#if WASM_ENABLE_FAST_JIT != 0 + /* Compile fast jit funcitons of this group */ + for (i = group_idx; i < func_count; i += group_stride) { + if (!jit_compiler_compile(module, i + module->import_function_count)) { + os_printf("failed to compile fast jit function %u\n", i); + break; + } + + if (module->orcjit_stop_compiling) { + return NULL; + } + } +#if WASM_ENABLE_JIT != 0 && WASM_ENABLE_LAZY_JIT != 0 + os_mutex_lock(&module->tierup_wait_lock); + module->fast_jit_ready_groups++; + os_mutex_unlock(&module->tierup_wait_lock); +#endif +#endif + +#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \ + && WASM_ENABLE_LAZY_JIT != 0 + /* For JIT tier-up, set each llvm jit func to call_to_fast_jit */ + for (i = group_idx; i < func_count; + i += group_stride * WASM_ORC_JIT_COMPILE_THREAD_NUM) { + uint32 j; + + for (j = 0; j < WASM_ORC_JIT_COMPILE_THREAD_NUM; j++) { + if (i + j * group_stride < func_count) { + if (!jit_compiler_set_call_to_fast_jit( + module, + i + j * group_stride + module->import_function_count)) { + os_printf( + "failed to compile call_to_fast_jit for func %u\n", + i + j * group_stride + module->import_function_count); + module->orcjit_stop_compiling = true; + return NULL; + } + } + if (module->orcjit_stop_compiling) { + return NULL; + } + } + } + + /* Wait until init_llvm_jit_functions_stage2 finishes and all + fast jit functions are compiled */ + os_mutex_lock(&module->tierup_wait_lock); + while (!(module->llvm_jit_inited && module->enable_llvm_jit_compilation + && module->fast_jit_ready_groups >= group_stride)) { + os_cond_reltimedwait(&module->tierup_wait_cond, + &module->tierup_wait_lock, 10000); + if (module->orcjit_stop_compiling) { + /* init_llvm_jit_functions_stage2 failed */ + os_mutex_unlock(&module->tierup_wait_lock); + return NULL; + } + } + os_mutex_unlock(&module->tierup_wait_lock); +#endif + +#if WASM_ENABLE_JIT != 0 + /* Compile llvm jit functions of this group */ + for (i = group_idx; i < func_count; + i += group_stride * WASM_ORC_JIT_COMPILE_THREAD_NUM) { + LLVMOrcJITTargetAddress func_addr = 0; + LLVMErrorRef error; + char func_name[48]; + typedef void (*F)(void); + union { + F f; + void *v; + } u; + uint32 j; + + snprintf(func_name, sizeof(func_name), "%s%d%s", AOT_FUNC_PREFIX, i, + "_wrapper"); + LOG_DEBUG("compile llvm jit func %s", func_name); + error = + LLVMOrcLLLazyJITLookup(comp_ctx->orc_jit, &func_addr, func_name); + if (error != LLVMErrorSuccess) { + char *err_msg = LLVMGetErrorMessage(error); + os_printf("failed to compile llvm jit function %u: %s", i, err_msg); + LLVMDisposeErrorMessage(err_msg); + break; + } + + /* Call the jit wrapper function to trigger its compilation, so as + to compile the actual jit functions, since we add the latter to + function list in the PartitionFunction callback */ + u.v = (void *)func_addr; + u.f(); + + for (j = 0; j < WASM_ORC_JIT_COMPILE_THREAD_NUM; j++) { + if (i + j * group_stride < func_count) { + module->func_ptrs_compiled[i + j * group_stride] = true; +#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_LAZY_JIT != 0 + snprintf(func_name, sizeof(func_name), "%s%d", AOT_FUNC_PREFIX, + i + j * group_stride); + error = LLVMOrcLLLazyJITLookup(comp_ctx->orc_jit, &func_addr, + func_name); + if (error != LLVMErrorSuccess) { + char *err_msg = LLVMGetErrorMessage(error); + os_printf("failed to compile llvm jit function %u: %s", i, + err_msg); + LLVMDisposeErrorMessage(err_msg); + /* Ignore current llvm jit func, as its func ptr is + previous set to call_to_fast_jit, which also works */ + continue; + } + + jit_compiler_set_llvm_jit_func_ptr( + module, + i + j * group_stride + module->import_function_count, + (void *)func_addr); + + /* Try to switch to call this llvm jit funtion instead of + fast jit function from fast jit jitted code */ + jit_compiler_set_call_to_llvm_jit( + module, + i + j * group_stride + module->import_function_count); +#endif + } + } + + if (module->orcjit_stop_compiling) { + break; + } + } +#endif + + return NULL; +} + +static void +orcjit_stop_compile_threads(WASMModule *module) +{ + uint32 i, thread_num = (uint32)(sizeof(module->orcjit_thread_args) + / sizeof(OrcJitThreadArg)); + + module->orcjit_stop_compiling = true; + for (i = 0; i < thread_num; i++) { + if (module->orcjit_threads[i]) + os_thread_join(module->orcjit_threads[i], NULL); + } } + +static bool +compile_jit_functions(WASMModule *module, char *error_buf, + uint32 error_buf_size) +{ + uint32 thread_num = + (uint32)(sizeof(module->orcjit_thread_args) / sizeof(OrcJitThreadArg)); + uint32 i, j; + + bh_print_time("Begin to compile jit functions"); + + /* Create threads to compile the jit functions */ + for (i = 0; i < thread_num && i < module->function_count; i++) { +#if WASM_ENABLE_JIT != 0 + module->orcjit_thread_args[i].comp_ctx = module->comp_ctx; +#endif + module->orcjit_thread_args[i].module = module; + module->orcjit_thread_args[i].group_idx = i; + + if (os_thread_create(&module->orcjit_threads[i], orcjit_thread_callback, + (void *)&module->orcjit_thread_args[i], + APP_THREAD_STACK_SIZE_DEFAULT) + != 0) { + set_error_buf(error_buf, error_buf_size, + "create orcjit compile thread failed"); + /* Terminate the threads created */ + module->orcjit_stop_compiling = true; + for (j = 0; j < i; j++) { + os_thread_join(module->orcjit_threads[j], NULL); + } + return false; + } + } + +#if WASM_ENABLE_LAZY_JIT == 0 + /* Wait until all jit functions are compiled for eager mode */ + for (i = 0; i < thread_num; i++) { + if (module->orcjit_threads[i]) + os_thread_join(module->orcjit_threads[i], NULL); + } + +#if WASM_ENABLE_FAST_JIT != 0 + /* Ensure all the fast-jit functions are compiled */ + for (i = 0; i < module->function_count; i++) { + if (!jit_compiler_is_compiled(module, + i + module->import_function_count)) { + set_error_buf(error_buf, error_buf_size, + "failed to compile fast jit function"); + return false; + } + } +#endif + +#if WASM_ENABLE_JIT != 0 + /* Ensure all the llvm-jit functions are compiled */ + for (i = 0; i < module->function_count; i++) { + if (!module->func_ptrs_compiled[i]) { + set_error_buf(error_buf, error_buf_size, + "failed to compile llvm jit function"); + return false; + } + } #endif +#endif /* end of WASM_ENABLE_LAZY_JIT == 0 */ + + bh_print_time("End compile jit functions"); + + return true; +} +#endif /* end of WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0 */ static bool wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, @@ -3352,17 +3793,41 @@ load_from_sections(WASMModule *module, WASMSection *sections, #endif } -#if WASM_ENABLE_FAST_JIT != 0 calculate_global_data_offset(module); - if (module->function_count - && !(module->fast_jit_func_ptrs = - loader_malloc(sizeof(void *) * module->function_count, - error_buf, error_buf_size))) { +#if WASM_ENABLE_FAST_JIT != 0 + if (!init_fast_jit_functions(module, error_buf, error_buf_size)) { + return false; + } +#endif + +#if WASM_ENABLE_JIT != 0 + if (!init_llvm_jit_functions_stage1(module, error_buf, error_buf_size)) { return false; } - if (!jit_compiler_compile_all(module)) { - set_error_buf(error_buf, error_buf_size, "fast jit compilation failed"); +#if !(WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_LAZY_JIT != 0) + if (!init_llvm_jit_functions_stage2(module, error_buf, error_buf_size)) { + return false; + } +#else + /* Run aot_compile_wasm in a backend thread, so as not to block the main + thread fast jit execution, since applying llvm optimizations in + aot_compile_wasm may cost a lot of time. + Create thread with enough native stack to apply llvm optimizations */ + if (os_thread_create(&module->llvm_jit_init_thread, + init_llvm_jit_functions_stage2_callback, + (void *)module, APP_THREAD_STACK_SIZE_DEFAULT * 8) + != 0) { + set_error_buf(error_buf, error_buf_size, + "create orcjit compile thread failed"); + return false; + } +#endif +#endif + +#if WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0 + /* Create threads to compile the jit functions */ + if (!compile_jit_functions(module, error_buf, error_buf_size)) { return false; } #endif @@ -3378,9 +3843,7 @@ create_module(char *error_buf, uint32 error_buf_size) { WASMModule *module = loader_malloc(sizeof(WASMModule), error_buf, error_buf_size); -#if WASM_ENABLE_FAST_INTERP == 0 bh_list_status ret; -#endif if (!module) { return NULL; @@ -3395,19 +3858,31 @@ create_module(char *error_buf, uint32 error_buf_size) module->br_table_cache_list = &module->br_table_cache_list_head; ret = bh_list_init(module->br_table_cache_list); bh_assert(ret == BH_LIST_SUCCESS); - (void)ret; #endif #if WASM_ENABLE_MULTI_MODULE != 0 module->import_module_list = &module->import_module_list_head; + ret = bh_list_init(module->import_module_list); + bh_assert(ret == BH_LIST_SUCCESS); #endif + #if WASM_ENABLE_DEBUG_INTERP != 0 - bh_list_init(&module->fast_opcode_list); - if (os_mutex_init(&module->ref_count_lock) != 0) { + ret = bh_list_init(&module->fast_opcode_list); + bh_assert(ret == BH_LIST_SUCCESS); +#endif + +#if WASM_ENABLE_DEBUG_INTERP != 0 \ + || (WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \ + && WASM_ENABLE_LAZY_JIT != 0) + if (os_mutex_init(&module->instance_list_lock) != 0) { + set_error_buf(error_buf, error_buf_size, + "init instance list lock failed"); wasm_runtime_free(module); return NULL; } #endif + + (void)ret; return module; } @@ -3612,24 +4087,19 @@ load(const uint8 *buf, uint32 size, WASMModule *module, char *error_buf, return false; } -#if (WASM_ENABLE_MULTI_MODULE != 0) && (WASM_ENABLE_LIBC_WASI != 0) +#if WASM_ENABLE_LIBC_WASI != 0 /** * refer to * https://github.com/WebAssembly/WASI/blob/main/design/application-abi.md */ static bool -check_wasi_abi_compatibility(const WASMModule *module, bool main_module, +check_wasi_abi_compatibility(const WASMModule *module, +#if WASM_ENABLE_MULTI_MODULE != 0 + bool main_module, +#endif char *error_buf, uint32 error_buf_size) { /** - * need to handle: - * - non-wasi compatiable modules - * - a fake wasi compatiable module - * - a command acts as a main_module - * - a command acts as a sub_module - * - a reactor acts as a main_module - * - a reactor acts as a sub_module - * * be careful with: * wasi compatiable modules(command/reactor) which don't import any wasi * APIs. Usually, a command has to import a "prox_exit" at least, but a @@ -3645,8 +4115,20 @@ check_wasi_abi_compatibility(const WASMModule *module, bool main_module, * - no one will define either `_start` or `_initialize` on purpose * - `_start` should always be `void _start(void)` * - `_initialize` should always be `void _initialize(void)` + * */ + /* clang-format off */ + /** + * + * | | import_wasi_api True | | import_wasi_api False | | + * | ----------- | -------------------- | ---------------- | --------------------- | ---------------- | + * | | \_initialize() Y | \_initialize() N | \_initialize() Y | \_initialize() N | + * | \_start() Y | N | COMMANDER | N | COMMANDER | + * | \_start() N | REACTOR | N | REACTOR | OTHERS | + */ + /* clang-format on */ + WASMExport *initialize = NULL, *memory = NULL, *start = NULL; /* (func (export "_start") (...) */ @@ -3685,10 +4167,8 @@ check_wasi_abi_compatibility(const WASMModule *module, bool main_module, /* should have one at least */ if (module->import_wasi_api && !start && !initialize) { - set_error_buf( - error_buf, error_buf_size, - "a module with WASI apis must be either a command or a reactor"); - return false; + LOG_WARNING("warning: a module with WASI apis should be either " + "a command or a reactor"); } /* @@ -3705,6 +4185,7 @@ check_wasi_abi_compatibility(const WASMModule *module, bool main_module, return false; } +#if WASM_ENABLE_MULTI_MODULE != 0 /* filter out commands (with `_start`) cases */ if (start && !main_module) { set_error_buf( @@ -3712,6 +4193,7 @@ check_wasi_abi_compatibility(const WASMModule *module, bool main_module, "a command (with _start function) can not be a sub-module"); return false; } +#endif /* * it is ok a reactor acts as a main module, @@ -3720,7 +4202,20 @@ check_wasi_abi_compatibility(const WASMModule *module, bool main_module, memory = wasm_loader_find_export(module, "", "memory", EXPORT_KIND_MEMORY, error_buf, error_buf_size); - if (!memory) { + if (!memory +#if WASM_ENABLE_LIB_WASI_THREADS != 0 + /* + * with wasi-threads, it's still an open question if a memory + * should be exported. + * + * https://github.com/WebAssembly/wasi-threads/issues/22 + * https://github.com/WebAssembly/WASI/issues/502 + * + * Note: this code assumes the number of memories is at most 1. + */ + && module->import_memory_count == 0 +#endif + ) { set_error_buf(error_buf, error_buf_size, "a module with WASI apis must export memory by default"); return false; @@ -3751,10 +4246,13 @@ wasm_loader_load(uint8 *buf, uint32 size, goto fail; } -#if (WASM_ENABLE_MULTI_MODULE != 0) && (WASM_ENABLE_LIBC_WASI != 0) +#if WASM_ENABLE_LIBC_WASI != 0 /* Check the WASI application ABI */ - if (!check_wasi_abi_compatibility(module, main_module, error_buf, - error_buf_size)) { + if (!check_wasi_abi_compatibility(module, +#if WASM_ENABLE_MULTI_MODULE != 0 + main_module, +#endif + error_buf, error_buf_size)) { goto fail; } #endif @@ -3775,6 +4273,36 @@ wasm_loader_unload(WASMModule *module) if (!module) return; +#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \ + && WASM_ENABLE_LAZY_JIT != 0 + module->orcjit_stop_compiling = true; + if (module->llvm_jit_init_thread) + os_thread_join(module->llvm_jit_init_thread, NULL); +#endif + +#if WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0 + /* Stop Fast/LLVM JIT compilation firstly to avoid accessing + module internal data after they were freed */ + orcjit_stop_compile_threads(module); +#endif + +#if WASM_ENABLE_JIT != 0 + if (module->func_ptrs) + wasm_runtime_free(module->func_ptrs); + if (module->comp_ctx) + aot_destroy_comp_context(module->comp_ctx); + if (module->comp_data) + aot_destroy_comp_data(module->comp_data); +#endif + +#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \ + && WASM_ENABLE_LAZY_JIT != 0 + if (module->tierup_wait_lock_inited) { + os_mutex_destroy(&module->tierup_wait_lock); + os_cond_destroy(&module->tierup_wait_cond); + } +#endif + if (module->types) { for (i = 0; i < module->type_count; i++) { if (module->types[i]) @@ -3796,6 +4324,18 @@ wasm_loader_unload(WASMModule *module) wasm_runtime_free(module->functions[i]->code_compiled); if (module->functions[i]->consts) wasm_runtime_free(module->functions[i]->consts); +#endif +#if WASM_ENABLE_FAST_JIT != 0 + if (module->functions[i]->fast_jit_jitted_code) { + jit_code_cache_free( + module->functions[i]->fast_jit_jitted_code); + } +#if WASM_ENABLE_JIT != 0 && WASM_ENABLE_LAZY_JIT != 0 + if (module->functions[i]->call_to_fast_jit_from_llvm_jit) { + jit_code_cache_free( + module->functions[i]->call_to_fast_jit_from_llvm_jit); + } +#endif #endif wasm_runtime_free(module->functions[i]); } @@ -3883,7 +4423,12 @@ wasm_loader_unload(WASMModule *module) wasm_runtime_free(fast_opcode); fast_opcode = next; } - os_mutex_destroy(&module->ref_count_lock); +#endif + +#if WASM_ENABLE_DEBUG_INTERP != 0 \ + || (WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \ + && WASM_ENABLE_LAZY_JIT != 0) + os_mutex_destroy(&module->instance_list_lock); #endif #if WASM_ENABLE_LOAD_CUSTOM_SECTION != 0 @@ -3892,12 +4437,14 @@ wasm_loader_unload(WASMModule *module) #if WASM_ENABLE_FAST_JIT != 0 if (module->fast_jit_func_ptrs) { - for (i = 0; i < module->function_count; i++) { - if (module->fast_jit_func_ptrs[i]) - jit_code_cache_free(module->fast_jit_func_ptrs[i]); - } wasm_runtime_free(module->fast_jit_func_ptrs); } + + for (i = 0; i < WASM_ORC_JIT_BACKEND_THREAD_NUM; i++) { + if (module->fast_jit_thread_locks_inited[i]) { + os_mutex_destroy(&module->fast_jit_thread_locks[i]); + } + } #endif wasm_runtime_free(module); @@ -4482,6 +5029,7 @@ wasm_loader_find_block_addr(WASMExecEnv *exec_env, BlockAddr *block_addr_cache, } (void)u8; + (void)exec_env; return false; fail: return false; @@ -4877,8 +5425,14 @@ wasm_loader_push_frame_ref(WASMLoaderContext *ctx, uint8 type, char *error_buf, #endif check_stack_and_return: - if (ctx->stack_cell_num > ctx->max_stack_cell_num) + if (ctx->stack_cell_num > ctx->max_stack_cell_num) { ctx->max_stack_cell_num = ctx->stack_cell_num; + if (ctx->max_stack_cell_num > UINT16_MAX) { + set_error_buf(error_buf, error_buf_size, + "operand stack depth limit exceeded"); + return false; + } + } return true; } @@ -4953,8 +5507,14 @@ wasm_loader_push_frame_csp(WASMLoaderContext *ctx, uint8 label_type, #endif ctx->frame_csp++; ctx->csp_num++; - if (ctx->csp_num > ctx->max_csp_num) + if (ctx->csp_num > ctx->max_csp_num) { ctx->max_csp_num = ctx->csp_num; + if (ctx->max_csp_num > UINT16_MAX) { + set_error_buf(error_buf, error_buf_size, + "label stack depth limit exceeded"); + return false; + } + } return true; fail: return false; @@ -5333,6 +5893,8 @@ preserve_referenced_local(WASMLoaderContext *loader_ctx, uint8 opcode, i += 2; } + (void)error_buf; + (void)error_buf_size; return true; #if WASM_ENABLE_LABELS_AS_VALUES != 0 #if WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 @@ -5597,6 +6159,9 @@ wasm_loader_pop_frame_offset(WASMLoaderContext *ctx, uint8 type, ctx->dynamic_offset -= 2; } emit_operand(ctx, *(ctx->frame_offset)); + + (void)error_buf; + (void)error_buf_size; return true; } @@ -6756,8 +7321,7 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, } block_type.is_value_type = false; block_type.u.type = module->types[type_index]; -#if WASM_ENABLE_FAST_INTERP == 0 && WASM_ENABLE_WAMR_COMPILER == 0 \ - && WASM_ENABLE_JIT == 0 +#if WASM_ENABLE_FAST_INTERP == 0 /* If block use type index as block type, change the opcode * to new extended opcode so that interpreter can resolve * the block quickly. @@ -7221,7 +7785,10 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, SET_CUR_BLOCK_STACK_POLYMORPHIC_STATE(true); } #endif +#if WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0 \ + || WASM_ENABLE_WAMR_COMPILER != 0 func->has_op_func_call = true; +#endif break; } @@ -7315,7 +7882,13 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, SET_CUR_BLOCK_STACK_POLYMORPHIC_STATE(true); } #endif +#if WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0 \ + || WASM_ENABLE_WAMR_COMPILER != 0 func->has_op_func_call = true; +#endif +#if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0 + func->has_op_call_indirect = true; +#endif break; } @@ -7649,12 +8222,13 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, goto fail; } - if (func_idx == cur_func_idx + module->import_function_count) { + /* Refer to a forward-declared function */ + if (func_idx >= cur_func_idx + module->import_function_count) { WASMTableSeg *table_seg = module->table_segments; bool func_declared = false; uint32 j; - /* Check whether current function is declared */ + /* Check whether the function is declared in table segs */ for (i = 0; i < module->table_seg_count; i++, table_seg++) { if (table_seg->elem_type == VALUE_TYPE_FUNCREF && wasm_elem_is_declarative(table_seg->mode)) { @@ -7666,6 +8240,17 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, } } } + if (!func_declared) { + /* Check whether the function is exported */ + for (i = 0; i < module->export_count; i++) { + if (module->exports[i].kind == EXPORT_KIND_FUNC + && module->exports[i].index == func_idx) { + func_declared = true; + break; + } + } + } + if (!func_declared) { set_error_buf(error_buf, error_buf_size, "undeclared function reference"); @@ -7933,6 +8518,9 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, } #endif *p_org = WASM_OP_SET_GLOBAL_AUX_STACK; +#if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0 + func->has_op_set_global_aux_stack = true; +#endif } #else /* else of WASM_ENABLE_FAST_INTERP */ if (global_type == VALUE_TYPE_I64 @@ -8005,6 +8593,9 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, } #if WASM_ENABLE_FAST_INTERP != 0 emit_uint32(loader_ctx, mem_offset); +#endif +#if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0 + func->has_memory_operations = true; #endif switch (opcode) { /* load */ @@ -8069,6 +8660,9 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, PUSH_I32(); module->possible_memory_grow = true; +#if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0 + func->has_memory_operations = true; +#endif break; case WASM_OP_MEMORY_GROW: @@ -8081,8 +8675,14 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, } POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32); - func->has_op_memory_grow = true; module->possible_memory_grow = true; +#if WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0 \ + || WASM_ENABLE_WAMR_COMPILER != 0 + func->has_op_memory_grow = true; +#endif +#if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0 + func->has_memory_operations = true; +#endif break; case WASM_OP_I32_CONST: @@ -8432,6 +9032,9 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, POP_I32(); POP_I32(); POP_I32(); +#if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0 + func->has_memory_operations = true; +#endif break; } case WASM_OP_DATA_DROP: @@ -8449,6 +9052,9 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, if (module->data_seg_count1 == 0) goto fail_data_cnt_sec_require; +#if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0 + func->has_memory_operations = true; +#endif break; } case WASM_OP_MEMORY_COPY: @@ -8465,6 +9071,9 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, POP_I32(); POP_I32(); POP_I32(); +#if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0 + func->has_memory_operations = true; +#endif break; } case WASM_OP_MEMORY_FILL: @@ -8480,7 +9089,11 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, POP_I32(); POP_I32(); POP_I32(); +#if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0 + func->has_memory_operations = true; +#endif break; + } fail_zero_byte_expected: set_error_buf(error_buf, error_buf_size, "zero byte expected"); @@ -8494,7 +9107,6 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, set_error_buf(error_buf, error_buf_size, "data count section required"); goto fail; - } #endif /* WASM_ENABLE_BULK_MEMORY */ #if WASM_ENABLE_REF_TYPES != 0 case WASM_OP_TABLE_INIT: @@ -8670,6 +9282,9 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, read_leb_uint32(p, p_end, mem_offset); /* offset */ POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_V128); +#if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0 + func->has_memory_operations = true; +#endif break; } @@ -8687,6 +9302,9 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, POP_V128(); POP_I32(); +#if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0 + func->has_memory_operations = true; +#endif break; } @@ -8911,6 +9529,9 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, if (opcode < SIMD_v128_store8_lane) { PUSH_V128(); } +#if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0 + func->has_memory_operations = true; +#endif break; } @@ -8928,6 +9549,9 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, read_leb_uint32(p, p_end, mem_offset); /* offset */ POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_V128); +#if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0 + func->has_memory_operations = true; +#endif break; } @@ -9304,6 +9928,9 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, emit_uint32(loader_ctx, mem_offset); #endif } +#if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0 + func->has_memory_operations = true; +#endif switch (opcode) { case WASM_OP_ATOMIC_NOTIFY: POP2_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32); diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/interpreter/wasm_loader.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm_loader.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/interpreter/wasm_loader.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm_loader.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/interpreter/wasm_mini_loader.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm_mini_loader.c similarity index 92% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/interpreter/wasm_mini_loader.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm_mini_loader.c index a2f589563f2..aa5e18f6a8f 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/interpreter/wasm_mini_loader.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm_mini_loader.c @@ -15,6 +15,9 @@ #include "../fast-jit/jit_compiler.h" #include "../fast-jit/jit_codecache.h" #endif +#if WASM_ENABLE_JIT != 0 +#include "../compilation/aot_llvm.h" +#endif /* Read a value of given type from the address pointed to by the given pointer and increase the pointer to the position just after the @@ -258,6 +261,12 @@ destroy_wasm_type(WASMType *type) return; } +#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \ + && WASM_ENABLE_LAZY_JIT != 0 + if (type->call_to_llvm_jit_from_fast_jit) + jit_code_cache_free(type->call_to_llvm_jit_from_fast_jit); +#endif + wasm_runtime_free(type); } @@ -961,6 +970,11 @@ load_function_section(const uint8 *buf, const uint8 *buf_end, read_leb_uint32(p, p_end, type_index); bh_assert(type_index < module->type_count); +#if (WASM_ENABLE_WAMR_COMPILER != 0) || (WASM_ENABLE_JIT != 0) + type_index = wasm_get_smallest_type_idx( + module->types, module->type_count, type_index); +#endif + read_leb_uint32(p_code, buf_code_end, code_size); bh_assert(code_size > 0 && p_code + code_size <= buf_code_end); @@ -1694,8 +1708,8 @@ handle_name_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, read_leb_uint32(p, p_end, func_name_len); CHECK_BUF(p, p_end, func_name_len); /* Skip the import functions */ - if (func_index >= module->import_count) { - func_index -= module->import_count; + if (func_index >= module->import_function_count) { + func_index -= module->import_function_count; bh_assert(func_index < module->function_count); if (!(module->functions[func_index]->field_name = const_str_list_insert( @@ -1719,6 +1733,8 @@ handle_name_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, i++; } + (void)previous_name_type; + (void)previous_func_index; return true; } #endif @@ -1749,6 +1765,470 @@ load_user_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module, return true; } +static void +calculate_global_data_offset(WASMModule *module) +{ + uint32 i, data_offset; + + data_offset = 0; + for (i = 0; i < module->import_global_count; i++) { + WASMGlobalImport *import_global = + &((module->import_globals + i)->u.global); +#if WASM_ENABLE_FAST_JIT != 0 + import_global->data_offset = data_offset; +#endif + data_offset += wasm_value_type_size(import_global->type); + } + + for (i = 0; i < module->global_count; i++) { + WASMGlobal *global = module->globals + i; +#if WASM_ENABLE_FAST_JIT != 0 + global->data_offset = data_offset; +#endif + data_offset += wasm_value_type_size(global->type); + } + + module->global_data_size = data_offset; +} + +#if WASM_ENABLE_FAST_JIT != 0 +static bool +init_fast_jit_functions(WASMModule *module, char *error_buf, + uint32 error_buf_size) +{ +#if WASM_ENABLE_LAZY_JIT != 0 + JitGlobals *jit_globals = jit_compiler_get_jit_globals(); +#endif + uint32 i; + + if (!module->function_count) + return true; + + if (!(module->fast_jit_func_ptrs = + loader_malloc(sizeof(void *) * module->function_count, error_buf, + error_buf_size))) { + return false; + } + +#if WASM_ENABLE_LAZY_JIT != 0 + for (i = 0; i < module->function_count; i++) { + module->fast_jit_func_ptrs[i] = + jit_globals->compile_fast_jit_and_then_call; + } +#endif + + for (i = 0; i < WASM_ORC_JIT_BACKEND_THREAD_NUM; i++) { + if (os_mutex_init(&module->fast_jit_thread_locks[i]) != 0) { + set_error_buf(error_buf, error_buf_size, + "init fast jit thread lock failed"); + return false; + } + module->fast_jit_thread_locks_inited[i] = true; + } + + return true; +} +#endif /* end of WASM_ENABLE_FAST_JIT != 0 */ + +#if WASM_ENABLE_JIT != 0 +static bool +init_llvm_jit_functions_stage1(WASMModule *module, char *error_buf, + uint32 error_buf_size) +{ + LLVMJITOptions llvm_jit_options = wasm_runtime_get_llvm_jit_options(); + AOTCompOption option = { 0 }; + char *aot_last_error; + uint64 size; + + if (module->function_count == 0) + return true; + +#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_LLVM_JIT != 0 + if (os_mutex_init(&module->tierup_wait_lock) != 0) { + set_error_buf(error_buf, error_buf_size, "init jit tierup lock failed"); + return false; + } + if (os_cond_init(&module->tierup_wait_cond) != 0) { + set_error_buf(error_buf, error_buf_size, "init jit tierup cond failed"); + os_mutex_destroy(&module->tierup_wait_lock); + return false; + } + module->tierup_wait_lock_inited = true; +#endif + + size = sizeof(void *) * (uint64)module->function_count + + sizeof(bool) * (uint64)module->function_count; + if (!(module->func_ptrs = loader_malloc(size, error_buf, error_buf_size))) { + return false; + } + module->func_ptrs_compiled = + (bool *)((uint8 *)module->func_ptrs + + sizeof(void *) * module->function_count); + + module->comp_data = aot_create_comp_data(module); + if (!module->comp_data) { + aot_last_error = aot_get_last_error(); + bh_assert(aot_last_error != NULL); + set_error_buf(error_buf, error_buf_size, aot_last_error); + return false; + } + + option.is_jit_mode = true; + option.opt_level = llvm_jit_options.opt_level; + option.size_level = llvm_jit_options.size_level; + +#if WASM_ENABLE_BULK_MEMORY != 0 + option.enable_bulk_memory = true; +#endif +#if WASM_ENABLE_THREAD_MGR != 0 + option.enable_thread_mgr = true; +#endif +#if WASM_ENABLE_TAIL_CALL != 0 + option.enable_tail_call = true; +#endif +#if WASM_ENABLE_SIMD != 0 + option.enable_simd = true; +#endif +#if WASM_ENABLE_REF_TYPES != 0 + option.enable_ref_types = true; +#endif + option.enable_aux_stack_check = true; +#if (WASM_ENABLE_PERF_PROFILING != 0) || (WASM_ENABLE_DUMP_CALL_STACK != 0) + option.enable_aux_stack_frame = true; +#endif +#if WASM_ENABLE_MEMORY_PROFILING != 0 + option.enable_stack_estimation = true; +#endif + + module->comp_ctx = aot_create_comp_context(module->comp_data, &option); + if (!module->comp_ctx) { + aot_last_error = aot_get_last_error(); + bh_assert(aot_last_error != NULL); + set_error_buf(error_buf, error_buf_size, aot_last_error); + return false; + } + + return true; +} + +static bool +init_llvm_jit_functions_stage2(WASMModule *module, char *error_buf, + uint32 error_buf_size) +{ + char *aot_last_error; + uint32 i; + + if (module->function_count == 0) + return true; + + if (!aot_compile_wasm(module->comp_ctx)) { + aot_last_error = aot_get_last_error(); + bh_assert(aot_last_error != NULL); + set_error_buf(error_buf, error_buf_size, aot_last_error); + return false; + } + +#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_LAZY_JIT != 0 + if (module->orcjit_stop_compiling) + return false; +#endif + + bh_print_time("Begin to lookup llvm jit functions"); + + for (i = 0; i < module->function_count; i++) { + LLVMOrcJITTargetAddress func_addr = 0; + LLVMErrorRef error; + char func_name[48]; + + snprintf(func_name, sizeof(func_name), "%s%d", AOT_FUNC_PREFIX, i); + error = LLVMOrcLLLazyJITLookup(module->comp_ctx->orc_jit, &func_addr, + func_name); + if (error != LLVMErrorSuccess) { + char *err_msg = LLVMGetErrorMessage(error); + char buf[96]; + snprintf(buf, sizeof(buf), + "failed to compile llvm jit function: %s", err_msg); + set_error_buf(error_buf, error_buf_size, buf); + LLVMDisposeErrorMessage(err_msg); + return false; + } + + /** + * No need to lock the func_ptr[func_idx] here as it is basic + * data type, the load/store for it can be finished by one cpu + * instruction, and there can be only one cpu instruction + * loading/storing at the same time. + */ + module->func_ptrs[i] = (void *)func_addr; + +#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_LAZY_JIT != 0 + module->functions[i]->llvm_jit_func_ptr = (void *)func_addr; + + if (module->orcjit_stop_compiling) + return false; +#endif + } + + bh_print_time("End lookup llvm jit functions"); + + return true; +} +#endif /* end of WASM_ENABLE_JIT != 0 */ + +#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \ + && WASM_ENABLE_LAZY_JIT != 0 +static void * +init_llvm_jit_functions_stage2_callback(void *arg) +{ + WASMModule *module = (WASMModule *)arg; + char error_buf[128]; + uint32 error_buf_size = (uint32)sizeof(error_buf); + + if (!init_llvm_jit_functions_stage2(module, error_buf, error_buf_size)) { + module->orcjit_stop_compiling = true; + return NULL; + } + + os_mutex_lock(&module->tierup_wait_lock); + module->llvm_jit_inited = true; + os_cond_broadcast(&module->tierup_wait_cond); + os_mutex_unlock(&module->tierup_wait_lock); + + return NULL; +} +#endif + +#if WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0 +/* The callback function to compile jit functions */ +static void * +orcjit_thread_callback(void *arg) +{ + OrcJitThreadArg *thread_arg = (OrcJitThreadArg *)arg; +#if WASM_ENABLE_JIT != 0 + AOTCompContext *comp_ctx = thread_arg->comp_ctx; +#endif + WASMModule *module = thread_arg->module; + uint32 group_idx = thread_arg->group_idx; + uint32 group_stride = WASM_ORC_JIT_BACKEND_THREAD_NUM; + uint32 func_count = module->function_count; + uint32 i; + +#if WASM_ENABLE_FAST_JIT != 0 + /* Compile fast jit funcitons of this group */ + for (i = group_idx; i < func_count; i += group_stride) { + if (!jit_compiler_compile(module, i + module->import_function_count)) { + os_printf("failed to compile fast jit function %u\n", i); + break; + } + + if (module->orcjit_stop_compiling) { + return NULL; + } + } +#if WASM_ENABLE_JIT != 0 && WASM_ENABLE_LAZY_JIT != 0 + os_mutex_lock(&module->tierup_wait_lock); + module->fast_jit_ready_groups++; + os_mutex_unlock(&module->tierup_wait_lock); +#endif +#endif + +#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \ + && WASM_ENABLE_LAZY_JIT != 0 + /* For JIT tier-up, set each llvm jit func to call_to_fast_jit */ + for (i = group_idx; i < func_count; + i += group_stride * WASM_ORC_JIT_COMPILE_THREAD_NUM) { + uint32 j; + + for (j = 0; j < WASM_ORC_JIT_COMPILE_THREAD_NUM; j++) { + if (i + j * group_stride < func_count) { + if (!jit_compiler_set_call_to_fast_jit( + module, + i + j * group_stride + module->import_function_count)) { + os_printf( + "failed to compile call_to_fast_jit for func %u\n", + i + j * group_stride + module->import_function_count); + module->orcjit_stop_compiling = true; + return NULL; + } + } + if (module->orcjit_stop_compiling) { + return NULL; + } + } + } + + /* Wait until init_llvm_jit_functions_stage2 finishes and all + fast jit functions are compiled */ + os_mutex_lock(&module->tierup_wait_lock); + while (!(module->llvm_jit_inited && module->enable_llvm_jit_compilation + && module->fast_jit_ready_groups >= group_stride)) { + os_cond_reltimedwait(&module->tierup_wait_cond, + &module->tierup_wait_lock, 10000); + if (module->orcjit_stop_compiling) { + /* init_llvm_jit_functions_stage2 failed */ + os_mutex_unlock(&module->tierup_wait_lock); + return NULL; + } + } + os_mutex_unlock(&module->tierup_wait_lock); +#endif + +#if WASM_ENABLE_JIT != 0 + /* Compile llvm jit functions of this group */ + for (i = group_idx; i < func_count; + i += group_stride * WASM_ORC_JIT_COMPILE_THREAD_NUM) { + LLVMOrcJITTargetAddress func_addr = 0; + LLVMErrorRef error; + char func_name[48]; + typedef void (*F)(void); + union { + F f; + void *v; + } u; + uint32 j; + + snprintf(func_name, sizeof(func_name), "%s%d%s", AOT_FUNC_PREFIX, i, + "_wrapper"); + LOG_DEBUG("compile llvm jit func %s", func_name); + error = + LLVMOrcLLLazyJITLookup(comp_ctx->orc_jit, &func_addr, func_name); + if (error != LLVMErrorSuccess) { + char *err_msg = LLVMGetErrorMessage(error); + os_printf("failed to compile llvm jit function %u: %s", i, err_msg); + LLVMDisposeErrorMessage(err_msg); + break; + } + + /* Call the jit wrapper function to trigger its compilation, so as + to compile the actual jit functions, since we add the latter to + function list in the PartitionFunction callback */ + u.v = (void *)func_addr; + u.f(); + + for (j = 0; j < WASM_ORC_JIT_COMPILE_THREAD_NUM; j++) { + if (i + j * group_stride < func_count) { + module->func_ptrs_compiled[i + j * group_stride] = true; +#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_LAZY_JIT != 0 + snprintf(func_name, sizeof(func_name), "%s%d", AOT_FUNC_PREFIX, + i + j * group_stride); + error = LLVMOrcLLLazyJITLookup(comp_ctx->orc_jit, &func_addr, + func_name); + if (error != LLVMErrorSuccess) { + char *err_msg = LLVMGetErrorMessage(error); + os_printf("failed to compile llvm jit function %u: %s", i, + err_msg); + LLVMDisposeErrorMessage(err_msg); + /* Ignore current llvm jit func, as its func ptr is + previous set to call_to_fast_jit, which also works */ + continue; + } + + jit_compiler_set_llvm_jit_func_ptr( + module, + i + j * group_stride + module->import_function_count, + (void *)func_addr); + + /* Try to switch to call this llvm jit funtion instead of + fast jit function from fast jit jitted code */ + jit_compiler_set_call_to_llvm_jit( + module, + i + j * group_stride + module->import_function_count); +#endif + } + } + + if (module->orcjit_stop_compiling) { + break; + } + } +#endif + + return NULL; +} + +static void +orcjit_stop_compile_threads(WASMModule *module) +{ + uint32 i, thread_num = (uint32)(sizeof(module->orcjit_thread_args) + / sizeof(OrcJitThreadArg)); + + module->orcjit_stop_compiling = true; + for (i = 0; i < thread_num; i++) { + if (module->orcjit_threads[i]) + os_thread_join(module->orcjit_threads[i], NULL); + } +} + +static bool +compile_jit_functions(WASMModule *module, char *error_buf, + uint32 error_buf_size) +{ + uint32 thread_num = + (uint32)(sizeof(module->orcjit_thread_args) / sizeof(OrcJitThreadArg)); + uint32 i, j; + + bh_print_time("Begin to compile jit functions"); + + /* Create threads to compile the jit functions */ + for (i = 0; i < thread_num && i < module->function_count; i++) { +#if WASM_ENABLE_JIT != 0 + module->orcjit_thread_args[i].comp_ctx = module->comp_ctx; +#endif + module->orcjit_thread_args[i].module = module; + module->orcjit_thread_args[i].group_idx = i; + + if (os_thread_create(&module->orcjit_threads[i], orcjit_thread_callback, + (void *)&module->orcjit_thread_args[i], + APP_THREAD_STACK_SIZE_DEFAULT) + != 0) { + set_error_buf(error_buf, error_buf_size, + "create orcjit compile thread failed"); + /* Terminate the threads created */ + module->orcjit_stop_compiling = true; + for (j = 0; j < i; j++) { + os_thread_join(module->orcjit_threads[j], NULL); + } + return false; + } + } + +#if WASM_ENABLE_LAZY_JIT == 0 + /* Wait until all jit functions are compiled for eager mode */ + for (i = 0; i < thread_num; i++) { + if (module->orcjit_threads[i]) + os_thread_join(module->orcjit_threads[i], NULL); + } + +#if WASM_ENABLE_FAST_JIT != 0 + /* Ensure all the fast-jit functions are compiled */ + for (i = 0; i < module->function_count; i++) { + if (!jit_compiler_is_compiled(module, + i + module->import_function_count)) { + set_error_buf(error_buf, error_buf_size, + "failed to compile fast jit function"); + return false; + } + } +#endif + +#if WASM_ENABLE_JIT != 0 + /* Ensure all the llvm-jit functions are compiled */ + for (i = 0; i < module->function_count; i++) { + if (!module->func_ptrs_compiled[i]) { + set_error_buf(error_buf, error_buf_size, + "failed to compile llvm jit function"); + return false; + } + } +#endif +#endif /* end of WASM_ENABLE_LAZY_JIT == 0 */ + + bh_print_time("End compile jit functions"); + + return true; +} +#endif /* end of WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0 */ + #if WASM_ENABLE_REF_TYPES != 0 static bool get_table_elem_type(const WASMModule *module, uint32 table_idx, @@ -2185,14 +2665,41 @@ load_from_sections(WASMModule *module, WASMSection *sections, } } + calculate_global_data_offset(module); + #if WASM_ENABLE_FAST_JIT != 0 - if (!(module->fast_jit_func_ptrs = - loader_malloc(sizeof(void *) * module->function_count, error_buf, - error_buf_size))) { + if (!init_fast_jit_functions(module, error_buf, error_buf_size)) { + return false; + } +#endif + +#if WASM_ENABLE_JIT != 0 + if (!init_llvm_jit_functions_stage1(module, error_buf, error_buf_size)) { return false; } - if (!jit_compiler_compile_all(module)) { - set_error_buf(error_buf, error_buf_size, "fast jit compilation failed"); +#if !(WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_LAZY_JIT != 0) + if (!init_llvm_jit_functions_stage2(module, error_buf, error_buf_size)) { + return false; + } +#else + /* Run aot_compile_wasm in a backend thread, so as not to block the main + thread fast jit execution, since applying llvm optimizations in + aot_compile_wasm may cost a lot of time. + Create thread with enough native stack to apply llvm optimizations */ + if (os_thread_create(&module->llvm_jit_init_thread, + init_llvm_jit_functions_stage2_callback, + (void *)module, APP_THREAD_STACK_SIZE_DEFAULT * 8) + != 0) { + set_error_buf(error_buf, error_buf_size, + "create orcjit compile thread failed"); + return false; + } +#endif +#endif + +#if WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0 + /* Create threads to compile the jit functions */ + if (!compile_jit_functions(module, error_buf, error_buf_size)) { return false; } #endif @@ -2208,9 +2715,7 @@ create_module(char *error_buf, uint32 error_buf_size) { WASMModule *module = loader_malloc(sizeof(WASMModule), error_buf, error_buf_size); -#if WASM_ENABLE_FAST_INTERP == 0 bh_list_status ret; -#endif if (!module) { return NULL; @@ -2225,9 +2730,19 @@ create_module(char *error_buf, uint32 error_buf_size) module->br_table_cache_list = &module->br_table_cache_list_head; ret = bh_list_init(module->br_table_cache_list); bh_assert(ret == BH_LIST_SUCCESS); - (void)ret; #endif +#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \ + && WASM_ENABLE_LAZY_JIT != 0 + if (os_mutex_init(&module->instance_list_lock) != 0) { + set_error_buf(error_buf, error_buf_size, + "init instance list lock failed"); + wasm_runtime_free(module); + return NULL; + } +#endif + + (void)ret; return module; } @@ -2439,6 +2954,36 @@ wasm_loader_unload(WASMModule *module) if (!module) return; +#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \ + && WASM_ENABLE_LAZY_JIT != 0 + module->orcjit_stop_compiling = true; + if (module->llvm_jit_init_thread) + os_thread_join(module->llvm_jit_init_thread, NULL); +#endif + +#if WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0 + /* Stop Fast/LLVM JIT compilation firstly to avoid accessing + module internal data after they were freed */ + orcjit_stop_compile_threads(module); +#endif + +#if WASM_ENABLE_JIT != 0 + if (module->func_ptrs) + wasm_runtime_free(module->func_ptrs); + if (module->comp_ctx) + aot_destroy_comp_context(module->comp_ctx); + if (module->comp_data) + aot_destroy_comp_data(module->comp_data); +#endif + +#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \ + && WASM_ENABLE_LAZY_JIT != 0 + if (module->tierup_wait_lock_inited) { + os_mutex_destroy(&module->tierup_wait_lock); + os_cond_destroy(&module->tierup_wait_cond); + } +#endif + if (module->types) { for (i = 0; i < module->type_count; i++) { if (module->types[i]) @@ -2460,6 +3005,18 @@ wasm_loader_unload(WASMModule *module) wasm_runtime_free(module->functions[i]->code_compiled); if (module->functions[i]->consts) wasm_runtime_free(module->functions[i]->consts); +#endif +#if WASM_ENABLE_FAST_JIT != 0 + if (module->functions[i]->fast_jit_jitted_code) { + jit_code_cache_free( + module->functions[i]->fast_jit_jitted_code); + } +#if WASM_ENABLE_JIT != 0 && WASM_ENABLE_LAZY_JIT != 0 + if (module->functions[i]->call_to_fast_jit_from_llvm_jit) { + jit_code_cache_free( + module->functions[i]->call_to_fast_jit_from_llvm_jit); + } +#endif #endif wasm_runtime_free(module->functions[i]); } @@ -2516,14 +3073,21 @@ wasm_loader_unload(WASMModule *module) } #endif +#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \ + && WASM_ENABLE_LAZY_JIT != 0 + os_mutex_destroy(&module->instance_list_lock); +#endif + #if WASM_ENABLE_FAST_JIT != 0 if (module->fast_jit_func_ptrs) { - for (i = 0; i < module->function_count; i++) { - if (module->fast_jit_func_ptrs[i]) - jit_code_cache_free(module->fast_jit_func_ptrs[i]); - } wasm_runtime_free(module->fast_jit_func_ptrs); } + + for (i = 0; i < WASM_ORC_JIT_BACKEND_THREAD_NUM; i++) { + if (module->fast_jit_thread_locks_inited[i]) { + os_mutex_destroy(&module->fast_jit_thread_locks[i]); + } + } #endif wasm_runtime_free(module); @@ -3335,8 +3899,10 @@ wasm_loader_push_frame_ref(WASMLoaderContext *ctx, uint8 type, char *error_buf, return false; *ctx->frame_ref++ = type; ctx->stack_cell_num++; - if (ctx->stack_cell_num > ctx->max_stack_cell_num) + if (ctx->stack_cell_num > ctx->max_stack_cell_num) { ctx->max_stack_cell_num = ctx->stack_cell_num; + bh_assert(ctx->max_stack_cell_num <= UINT16_MAX); + } return true; } @@ -3402,8 +3968,10 @@ wasm_loader_push_frame_csp(WASMLoaderContext *ctx, uint8 label_type, #endif ctx->frame_csp++; ctx->csp_num++; - if (ctx->csp_num > ctx->max_csp_num) + if (ctx->csp_num > ctx->max_csp_num) { ctx->max_csp_num = ctx->csp_num; + bh_assert(ctx->max_csp_num <= UINT16_MAX); + } return true; fail: return false; @@ -4862,10 +5430,11 @@ copy_params_to_dynamic_space(WASMLoaderContext *loader_ctx, bool is_if_block, /* Free the emit data */ wasm_runtime_free(emit_data); - return true; fail: + /* Free the emit data */ + wasm_runtime_free(emit_data); return false; } #endif @@ -5035,8 +5604,7 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, bh_assert(type_index < module->type_count); block_type.is_value_type = false; block_type.u.type = module->types[type_index]; -#if WASM_ENABLE_FAST_INTERP == 0 && WASM_ENABLE_WAMR_COMPILER == 0 \ - && WASM_ENABLE_JIT == 0 +#if WASM_ENABLE_FAST_INTERP == 0 /* If block use type index as block type, change the opcode * to new extended opcode so that interpreter can resolve * the block quickly. @@ -5309,12 +5877,6 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, if (depth > 255) { /* The depth cannot be stored in one byte, create br_table cache to store each depth */ -#if WASM_ENABLE_DEBUG_INTERP != 0 - if (!record_fast_op(module, p_org, *p_org, - error_buf, error_buf_size)) { - goto fail; - } -#endif if (!(br_table_cache = loader_malloc( offsetof(BrTableCache, br_depths) + sizeof(uint32) @@ -5443,7 +6005,10 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, } } #endif +#if WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0 \ + || WASM_ENABLE_WAMR_COMPILER != 0 func->has_op_func_call = true; +#endif break; } @@ -5518,7 +6083,13 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, } #endif +#if WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0 \ + || WASM_ENABLE_WAMR_COMPILER != 0 func->has_op_func_call = true; +#endif +#if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0 + func->has_op_call_indirect = true; +#endif break; } @@ -5813,12 +6384,13 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, goto fail; } - if (func_idx == cur_func_idx + module->import_function_count) { + /* Refer to a forward-declared function */ + if (func_idx >= cur_func_idx + module->import_function_count) { WASMTableSeg *table_seg = module->table_segments; bool func_declared = false; uint32 j; - /* Check whether current function is declared */ + /* Check whether the function is declared in table segs */ for (i = 0; i < module->table_seg_count; i++, table_seg++) { if (table_seg->elem_type == VALUE_TYPE_FUNCREF && wasm_elem_is_declarative(table_seg->mode)) { @@ -5831,10 +6403,17 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, } } if (!func_declared) { - set_error_buf(error_buf, error_buf_size, - "undeclared function reference"); - goto fail; + /* Check whether the function is exported */ + for (i = 0; i < module->export_count; i++) { + if (module->exports[i].kind == EXPORT_KIND_FUNC + && module->exports[i].index == func_idx) { + func_declared = true; + break; + } + } } + bh_assert(func_declared); + (void)func_declared; } #if WASM_ENABLE_FAST_INTERP != 0 @@ -6058,6 +6637,9 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, else if (module->aux_stack_size > 0 && global_idx == module->aux_stack_top_global_index) { *p_org = WASM_OP_SET_GLOBAL_AUX_STACK; +#if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0 + func->has_op_set_global_aux_stack = true; +#endif } #else /* else of WASM_ENABLE_FAST_INTERP */ if (is_64bit_type(global_type)) { @@ -6127,6 +6709,9 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, read_leb_uint32(p, p_end, mem_offset); /* offset */ #if WASM_ENABLE_FAST_INTERP != 0 emit_uint32(loader_ctx, mem_offset); +#endif +#if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0 + func->has_memory_operations = true; #endif switch (opcode) { /* load */ @@ -6188,6 +6773,9 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, PUSH_I32(); module->possible_memory_grow = true; +#if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0 + func->has_memory_operations = true; +#endif break; case WASM_OP_MEMORY_GROW: @@ -6197,8 +6785,14 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, p++; POP_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32); - func->has_op_memory_grow = true; module->possible_memory_grow = true; +#if WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0 \ + || WASM_ENABLE_WAMR_COMPILER != 0 + func->has_op_memory_grow = true; +#endif +#if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0 + func->has_memory_operations = true; +#endif break; case WASM_OP_I32_CONST: @@ -6523,6 +7117,7 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, break; #if WASM_ENABLE_BULK_MEMORY != 0 case WASM_OP_MEMORY_INIT: + { read_leb_uint32(p, p_end, segment_index); #if WASM_ENABLE_FAST_INTERP != 0 emit_uint32(loader_ctx, segment_index); @@ -6540,16 +7135,26 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, POP_I32(); POP_I32(); POP_I32(); +#if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0 + func->has_memory_operations = true; +#endif break; + } case WASM_OP_DATA_DROP: + { read_leb_uint32(p, p_end, segment_index); #if WASM_ENABLE_FAST_INTERP != 0 emit_uint32(loader_ctx, segment_index); #endif bh_assert(segment_index < module->data_seg_count); bh_assert(module->data_seg_count1 > 0); +#if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0 + func->has_memory_operations = true; +#endif break; + } case WASM_OP_MEMORY_COPY: + { /* both src and dst memory index should be 0 */ bh_assert(*(int16 *)p == 0x0000); p += 2; @@ -6561,8 +7166,13 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, POP_I32(); POP_I32(); POP_I32(); +#if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0 + func->has_memory_operations = true; +#endif break; + } case WASM_OP_MEMORY_FILL: + { bh_assert(*p == 0); p++; @@ -6573,7 +7183,11 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, POP_I32(); POP_I32(); POP_I32(); +#if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0 + func->has_memory_operations = true; +#endif break; + } #endif /* WASM_ENABLE_BULK_MEMORY */ #if WASM_ENABLE_REF_TYPES != 0 case WASM_OP_TABLE_INIT: @@ -6735,6 +7349,9 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, emit_uint32(loader_ctx, mem_offset); #endif } +#if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0 + func->has_memory_operations = true; +#endif switch (opcode) { case WASM_OP_ATOMIC_NOTIFY: POP2_AND_PUSH(VALUE_TYPE_I32, VALUE_TYPE_I32); diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/interpreter/wasm_opcode.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm_opcode.h similarity index 98% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/interpreter/wasm_opcode.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm_opcode.h index cd7478a6b9e..ce5e358a2d8 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/interpreter/wasm_opcode.h +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm_opcode.h @@ -675,12 +675,14 @@ typedef enum WASMAtomicEXTOpcode { } WASMAtomicEXTOpcode; #if WASM_ENABLE_DEBUG_INTERP != 0 -#define DEF_DEBUG_BREAK_HANDLE(_name) \ - _name[DEBUG_OP_BREAK] = HANDLE_OPCODE(DEBUG_OP_BREAK); /* 0xd7 */ +#define DEF_DEBUG_BREAK_HANDLE() \ + [DEBUG_OP_BREAK] = HANDLE_OPCODE(DEBUG_OP_BREAK), /* 0xd7 */ #else -#define DEF_DEBUG_BREAK_HANDLE(_name) +#define DEF_DEBUG_BREAK_HANDLE() #endif +#define SET_GOTO_TABLE_ELEM(opcode) [opcode] = HANDLE_OPCODE(opcode) + /* * Macro used to generate computed goto tables for the C interpreter. */ @@ -903,14 +905,10 @@ typedef enum WASMAtomicEXTOpcode { HANDLE_OPCODE(EXT_OP_LOOP), /* 0xd4 */ \ HANDLE_OPCODE(EXT_OP_IF), /* 0xd5 */ \ HANDLE_OPCODE(EXT_OP_BR_TABLE_CACHE), /* 0xd6 */ \ - }; \ - do { \ - _name[WASM_OP_MISC_PREFIX] = \ - HANDLE_OPCODE(WASM_OP_MISC_PREFIX); /* 0xfc */ \ - _name[WASM_OP_ATOMIC_PREFIX] = \ - HANDLE_OPCODE(WASM_OP_ATOMIC_PREFIX); /* 0xfe */ \ - DEF_DEBUG_BREAK_HANDLE(_name) \ - } while (0) + SET_GOTO_TABLE_ELEM(WASM_OP_MISC_PREFIX), /* 0xfc */ \ + SET_GOTO_TABLE_ELEM(WASM_OP_ATOMIC_PREFIX), /* 0xfe */ \ + DEF_DEBUG_BREAK_HANDLE() \ + }; #ifdef __cplusplus } diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/interpreter/wasm_runtime.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm_runtime.c similarity index 62% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/interpreter/wasm_runtime.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm_runtime.c index f085e785845..29365024d9d 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/interpreter/wasm_runtime.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm_runtime.c @@ -19,6 +19,12 @@ #if WASM_ENABLE_DEBUG_INTERP != 0 #include "../libraries/debug-engine/debug_engine.h" #endif +#if WASM_ENABLE_FAST_JIT != 0 +#include "../fast-jit/jit_compiler.h" +#endif +#if WASM_ENABLE_JIT != 0 +#include "../aot/aot_runtime.h" +#endif static void set_error_buf(char *error_buf, uint32 error_buf_size, const char *string) @@ -87,7 +93,7 @@ static WASMModuleInstance * get_sub_module_inst(const WASMModuleInstance *parent_module_inst, const WASMModule *sub_module) { - bh_list *sub_module_inst_list = parent_module_inst->sub_module_inst_list; + bh_list *sub_module_inst_list = parent_module_inst->e->sub_module_inst_list; WASMSubModInstNode *node = bh_list_first_elem(sub_module_inst_list); while (node && sub_module != node->module_inst->module) { @@ -126,7 +132,6 @@ memories_deinstantiate(WASMModuleInstance *module_inst, if (ref_count > 0) continue; } - os_mutex_destroy(&memories[i]->mem_lock); #endif if (memories[i]->heap_handle) { mem_allocator_destroy(memories[i]->heap_handle); @@ -146,7 +151,6 @@ memories_deinstantiate(WASMModuleInstance *module_inst, 8 * (uint64)BH_GB); #endif } - wasm_runtime_free(memories[i]); } } wasm_runtime_free(memories); @@ -155,13 +159,12 @@ memories_deinstantiate(WASMModuleInstance *module_inst, } static WASMMemoryInstance * -memory_instantiate(WASMModuleInstance *module_inst, 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) +memory_instantiate(WASMModuleInstance *module_inst, WASMMemoryInstance *memory, + 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) { WASMModule *module = module_inst->module; - WASMMemoryInstance *memory; uint64 memory_data_size; uint32 heap_offset = num_bytes_per_page * init_page_count; uint32 inc_page_count, aux_heap_base, global_idx; @@ -250,10 +253,10 @@ memory_instantiate(WASMModuleInstance *module_inst, uint32 num_bytes_per_page, /* Adjust __heap_base global value */ global_idx = module->aux_heap_base_global_index; - bh_assert(module_inst->globals - && global_idx < module_inst->global_count); + bh_assert(module_inst->e->globals + && global_idx < module_inst->e->global_count); global_addr = module_inst->global_data - + module_inst->globals[global_idx].data_offset; + + module_inst->e->globals[global_idx].data_offset; *(uint32 *)global_addr = aux_heap_base; LOG_VERBOSE("Reset __heap_base global to %u", aux_heap_base); } @@ -296,12 +299,7 @@ memory_instantiate(WASMModuleInstance *module_inst, uint32 num_bytes_per_page, #endif bh_assert(memory_data_size <= 4 * (uint64)BH_GB); - /* Allocate memory space, addr data and global data */ - if (!(memory = runtime_malloc((uint64)sizeof(WASMMemoryInstance), error_buf, - error_buf_size))) { - return NULL; - } - + bh_assert(memory != NULL); #ifndef OS_ENABLE_HW_BOUND_CHECK if (memory_data_size > 0 && !(memory->memory_data = @@ -370,44 +368,40 @@ memory_instantiate(WASMModuleInstance *module_inst, uint32 num_bytes_per_page, } } -#if WASM_ENABLE_FAST_JIT != 0 +#if WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0 if (memory_data_size > 0) { #if UINTPTR_MAX == UINT64_MAX - memory->mem_bound_check_1byte = memory_data_size - 1; - memory->mem_bound_check_2bytes = memory_data_size - 2; - memory->mem_bound_check_4bytes = memory_data_size - 4; - memory->mem_bound_check_8bytes = memory_data_size - 8; - memory->mem_bound_check_16bytes = memory_data_size - 16; + memory->mem_bound_check_1byte.u64 = memory_data_size - 1; + memory->mem_bound_check_2bytes.u64 = memory_data_size - 2; + memory->mem_bound_check_4bytes.u64 = memory_data_size - 4; + memory->mem_bound_check_8bytes.u64 = memory_data_size - 8; + memory->mem_bound_check_16bytes.u64 = memory_data_size - 16; #else - memory->mem_bound_check_1byte = (uint32)memory_data_size - 1; - memory->mem_bound_check_2bytes = (uint32)memory_data_size - 2; - memory->mem_bound_check_4bytes = (uint32)memory_data_size - 4; - memory->mem_bound_check_8bytes = (uint32)memory_data_size - 8; - memory->mem_bound_check_16bytes = (uint32)memory_data_size - 16; + memory->mem_bound_check_1byte.u32[0] = (uint32)memory_data_size - 1; + memory->mem_bound_check_2bytes.u32[0] = (uint32)memory_data_size - 2; + memory->mem_bound_check_4bytes.u32[0] = (uint32)memory_data_size - 4; + memory->mem_bound_check_8bytes.u32[0] = (uint32)memory_data_size - 8; + memory->mem_bound_check_16bytes.u32[0] = (uint32)memory_data_size - 16; #endif } #endif #if WASM_ENABLE_SHARED_MEMORY != 0 - if (0 != os_mutex_init(&memory->mem_lock)) { - set_error_buf(error_buf, error_buf_size, "init mutex failed"); - goto fail4; - } 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 fail5; + goto fail4; } } #endif + LOG_VERBOSE("Memory instantiate success."); return memory; + #if WASM_ENABLE_SHARED_MEMORY != 0 -fail5: - os_mutex_destroy(&memory->mem_lock); fail4: if (heap_size > 0) mem_allocator_destroy(memory->heap_handle); @@ -426,7 +420,6 @@ memory_instantiate(WASMModuleInstance *module_inst, uint32 num_bytes_per_page, os_munmap(mapped_mem, map_size); #endif fail1: - wasm_runtime_free(memory); return NULL; } @@ -449,9 +442,11 @@ memories_instantiate(const WASMModule *module, WASMModuleInstance *module_inst, return NULL; } + memory = module_inst->global_table_data.memory_instances; + /* instantiate memories from import section */ import = module->import_memories; - for (i = 0; i < module->import_memory_count; i++, import++) { + for (i = 0; i < module->import_memory_count; i++, import++, memory++) { uint32 num_bytes_per_page = import->u.memory.num_bytes_per_page; uint32 init_page_count = import->u.memory.init_page_count; uint32 max_page_count = import->u.memory.max_page_count; @@ -469,7 +464,7 @@ memories_instantiate(const WASMModule *module, WASMModuleInstance *module_inst, return NULL; } - if (!(memory = memories[mem_index++] = wasm_lookup_memory( + if (!(memories[mem_index++] = wasm_lookup_memory( module_inst_linked, import->u.memory.field_name))) { set_error_buf(error_buf, error_buf_size, "unknown memory"); memories_deinstantiate(module_inst, memories, memory_count); @@ -479,8 +474,8 @@ memories_instantiate(const WASMModule *module, WASMModuleInstance *module_inst, else #endif { - if (!(memory = memories[mem_index++] = memory_instantiate( - module_inst, num_bytes_per_page, init_page_count, + 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))) { memories_deinstantiate(module_inst, memories, memory_count); @@ -490,9 +485,9 @@ memories_instantiate(const WASMModule *module, WASMModuleInstance *module_inst, } /* instantiate memories from memory section */ - for (i = 0; i < module->memory_count; i++) { - if (!(memory = memories[mem_index++] = memory_instantiate( - module_inst, module->memories[i].num_bytes_per_page, + 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, module->memories[i].init_page_count, module->memories[i].max_page_count, heap_size, module->memories[i].flags, error_buf, error_buf_size))) { @@ -510,15 +505,16 @@ memories_instantiate(const WASMModule *module, WASMModuleInstance *module_inst, * Destroy table instances. */ static void -tables_deinstantiate(WASMTableInstance **tables, uint32 count) +tables_deinstantiate(WASMModuleInstance *module_inst) { - uint32 i; - if (tables) { - for (i = 0; i < count; i++) - if (tables[i]) - wasm_runtime_free(tables[i]); - wasm_runtime_free(tables); + if (module_inst->tables) { + wasm_runtime_free(module_inst->tables); + } +#if WASM_ENABLE_MULTI_MODULE != 0 + if (module_inst->e->table_insts_linked) { + wasm_runtime_free(module_inst->e->table_insts_linked); } +#endif } /** @@ -526,18 +522,32 @@ tables_deinstantiate(WASMTableInstance **tables, uint32 count) */ static WASMTableInstance ** tables_instantiate(const WASMModule *module, WASMModuleInstance *module_inst, - char *error_buf, uint32 error_buf_size) + WASMTableInstance *first_table, char *error_buf, + uint32 error_buf_size) { WASMImport *import; - uint32 table_index = 0, i, - table_count = module->import_table_count + module->table_count; - uint64 total_size = sizeof(WASMTableInstance *) * (uint64)table_count; - WASMTableInstance **tables, *table; + uint32 table_index = 0, i; + uint32 table_count = module->import_table_count + module->table_count; + uint64 total_size = (uint64)sizeof(WASMTableInstance *) * table_count; + WASMTableInstance **tables, *table = first_table; +#if WASM_ENABLE_MULTI_MODULE != 0 + uint64 total_size_of_tables_linked = + (uint64)sizeof(WASMTableInstance *) * module->import_table_count; + WASMTableInstance **table_linked = NULL; +#endif if (!(tables = runtime_malloc(total_size, error_buf, error_buf_size))) { return NULL; } +#if WASM_ENABLE_MULTI_MODULE != 0 + if (module->import_table_count > 0 + && !(module_inst->e->table_insts_linked = table_linked = runtime_malloc( + total_size_of_tables_linked, error_buf, error_buf_size))) { + goto fail; + } +#endif + /* instantiate tables from import section */ import = module->import_tables; for (i = 0; i < module->import_table_count; i++, import++) { @@ -550,18 +560,16 @@ tables_instantiate(const WASMModule *module, WASMModuleInstance *module_inst, if (!(module_inst_linked = get_sub_module_inst( module_inst, import->u.table.import_module))) { set_error_buf(error_buf, error_buf_size, "unknown table"); - tables_deinstantiate(tables, table_count); - return NULL; + goto fail; } if (!(table_inst_linked = wasm_lookup_table( module_inst_linked, import->u.table.field_name))) { set_error_buf(error_buf, error_buf_size, "unknown table"); - tables_deinstantiate(tables, table_count); - return NULL; + goto fail; } - total_size = offsetof(WASMTableInstance, base_addr); + total_size = offsetof(WASMTableInstance, elems); } else #endif @@ -572,40 +580,39 @@ tables_instantiate(const WASMModule *module, WASMModuleInstance *module_inst, : import->u.table.init_size; /* it is a built-in table, every module has its own */ - total_size = offsetof(WASMTableInstance, base_addr); + total_size = offsetof(WASMTableInstance, elems); total_size += (uint64)max_size_fixed * sizeof(uint32); } - if (!(table = tables[table_index++] = - runtime_malloc(total_size, error_buf, error_buf_size))) { - tables_deinstantiate(tables, table_count); - return NULL; - } + tables[table_index++] = table; /* Set all elements to -1 to mark them as uninitialized elements */ memset(table, -1, (uint32)total_size); #if WASM_ENABLE_MULTI_MODULE != 0 - table->table_inst_linked = table_inst_linked; + *table_linked = table_inst_linked; if (table_inst_linked != NULL) { - table->elem_type = table_inst_linked->elem_type; table->cur_size = table_inst_linked->cur_size; table->max_size = table_inst_linked->max_size; } else #endif { - table->elem_type = import->u.table.elem_type; table->cur_size = import->u.table.init_size; table->max_size = max_size_fixed; } + + table = (WASMTableInstance *)((uint8 *)table + (uint32)total_size); +#if WASM_ENABLE_MULTI_MODULE != 0 + table_linked++; +#endif } /* instantiate tables from table section */ for (i = 0; i < module->table_count; i++) { uint32 max_size_fixed = 0; - total_size = offsetof(WASMTableInstance, base_addr); + total_size = offsetof(WASMTableInstance, elems); #if WASM_ENABLE_MULTI_MODULE != 0 /* in case, a module which imports this table will grow it */ max_size_fixed = module->tables[i].max_size; @@ -616,25 +623,24 @@ tables_instantiate(const WASMModule *module, WASMModuleInstance *module_inst, #endif total_size += sizeof(uint32) * (uint64)max_size_fixed; - if (!(table = tables[table_index++] = - runtime_malloc(total_size, error_buf, error_buf_size))) { - tables_deinstantiate(tables, table_count); - return NULL; - } + tables[table_index++] = table; /* Set all elements to -1 to mark them as uninitialized elements */ memset(table, -1, (uint32)total_size); - table->elem_type = module->tables[i].elem_type; table->cur_size = module->tables[i].init_size; table->max_size = max_size_fixed; -#if WASM_ENABLE_MULTI_MODULE != 0 - table->table_inst_linked = NULL; -#endif + + table = (WASMTableInstance *)((uint8 *)table + (uint32)total_size); } bh_assert(table_index == table_count); (void)module_inst; return tables; +#if WASM_ENABLE_MULTI_MODULE != 0 +fail: + wasm_runtime_free(tables); + return NULL; +#endif } /** @@ -731,13 +737,12 @@ functions_instantiate(const WASMModule *module, WASMModuleInstance *module_inst, function++; } + bh_assert((uint32)(function - functions) == function_count); #if WASM_ENABLE_FAST_JIT != 0 module_inst->fast_jit_func_ptrs = module->fast_jit_func_ptrs; #endif - bh_assert((uint32)(function - functions) == function_count); - (void)module_inst; return functions; } @@ -783,8 +788,7 @@ check_global_init_expr(const WASMModule *module, uint32 global_index, */ static WASMGlobalInstance * globals_instantiate(const WASMModule *module, WASMModuleInstance *module_inst, - uint32 *p_global_data_size, char *error_buf, - uint32 error_buf_size) + char *error_buf, uint32 error_buf_size) { WASMImport *import; uint32 global_data_offset = 0; @@ -831,6 +835,9 @@ globals_instantiate(const WASMModule *module, WASMModuleInstance *module_inst, &(global_import->global_data_linked), sizeof(WASMValue)); } +#if WASM_ENABLE_FAST_JIT != 0 + bh_assert(global_data_offset == global_import->data_offset); +#endif global->data_offset = global_data_offset; global_data_offset += wasm_value_type_size(global->type); @@ -843,8 +850,10 @@ globals_instantiate(const WASMModule *module, WASMModuleInstance *module_inst, global->type = module->globals[i].type; global->is_mutable = module->globals[i].is_mutable; +#if WASM_ENABLE_FAST_JIT != 0 + bh_assert(global_data_offset == module->globals[i].data_offset); +#endif global->data_offset = global_data_offset; - global_data_offset += wasm_value_type_size(global->type); if (init_expr->init_expr_type == INIT_EXPR_TYPE_GET_GLOBAL) { @@ -871,7 +880,7 @@ globals_instantiate(const WASMModule *module, WASMModuleInstance *module_inst, } bh_assert((uint32)(global - globals) == global_count); - *p_global_data_size = global_data_offset; + bh_assert(global_data_offset == module->global_data_size); (void)module_inst; return globals; fail: @@ -928,7 +937,7 @@ export_functions_instantiate(const WASMModule *module, for (i = 0; i < module->export_count; i++, export ++) if (export->kind == EXPORT_KIND_FUNC) { export_func->name = export->name; - export_func->function = &module_inst->functions[export->index]; + export_func->function = &module_inst->e->functions[export->index]; export_func++; } @@ -964,7 +973,7 @@ export_globals_instantiate(const WASMModule *module, for (i = 0; i < module->export_count; i++, export ++) if (export->kind == EXPORT_KIND_GLOBAL) { export_global->name = export->name; - export_global->global = &module_inst->globals[export->index]; + export_global->global = &module_inst->e->globals[export->index]; export_global++; } @@ -973,80 +982,163 @@ export_globals_instantiate(const WASMModule *module, } #endif -static bool -execute_post_inst_function(WASMModuleInstance *module_inst) +static WASMFunctionInstance * +lookup_post_instantiate_func(WASMModuleInstance *module_inst, + const char *func_name) { - WASMFunctionInstance *post_inst_func = NULL; - WASMType *post_inst_func_type; - uint32 i; - - for (i = 0; i < module_inst->export_func_count; i++) - if (!strcmp(module_inst->export_functions[i].name, - "__post_instantiate")) { - post_inst_func = module_inst->export_functions[i].function; - break; - } + WASMFunctionInstance *func; + WASMType *func_type; - if (!post_inst_func) + if (!(func = wasm_lookup_function(module_inst, func_name, NULL))) /* Not found */ - return true; + return NULL; - post_inst_func_type = post_inst_func->u.func->func_type; - if (post_inst_func_type->param_count != 0 - || post_inst_func_type->result_count != 0) + func_type = func->u.func->func_type; + if (!(func_type->param_count == 0 && func_type->result_count == 0)) /* Not a valid function type, ignore it */ - return true; + return NULL; - return wasm_create_exec_env_and_call_function(module_inst, post_inst_func, - 0, NULL); + return func; } -#if WASM_ENABLE_BULK_MEMORY != 0 static bool -execute_memory_init_function(WASMModuleInstance *module_inst) +execute_post_instantiate_functions(WASMModuleInstance *module_inst, + bool is_sub_inst, WASMExecEnv *exec_env_main) { - WASMFunctionInstance *memory_init_func = NULL; - WASMType *memory_init_func_type; - uint32 i; + WASMFunctionInstance *start_func = module_inst->e->start_function; + WASMFunctionInstance *initialize_func = NULL; + WASMFunctionInstance *post_inst_func = NULL; + WASMFunctionInstance *call_ctors_func = NULL; +#if WASM_ENABLE_LIBC_WASI != 0 + WASMModule *module = module_inst->module; +#endif + WASMModuleInstanceCommon *module_inst_main = NULL; +#ifdef OS_ENABLE_HW_BOUND_CHECK + WASMExecEnv *exec_env_tls = wasm_runtime_get_exec_env_tls(); +#endif + WASMExecEnv *exec_env = NULL, *exec_env_created = NULL; + bool ret = false; - for (i = 0; i < module_inst->export_func_count; i++) - if (!strcmp(module_inst->export_functions[i].name, - "__wasm_call_ctors")) { - memory_init_func = module_inst->export_functions[i].function; - break; - } +#if WASM_ENABLE_LIBC_WASI != 0 + /* + * WASI reactor instances may assume that _initialize will be called by + * the environment at most once, and that none of their other exports + * are accessed before that call. + */ + if (!is_sub_inst && module->import_wasi_api) { + initialize_func = + lookup_post_instantiate_func(module_inst, "_initialize"); + } +#endif - if (!memory_init_func) - /* Not found */ - return true; + /* Execute possible "__post_instantiate" function if wasm app is + compiled by emsdk's early version */ + if (!is_sub_inst) { + post_inst_func = + lookup_post_instantiate_func(module_inst, "__post_instantiate"); + } - memory_init_func_type = memory_init_func->u.func->func_type; - if (memory_init_func_type->param_count != 0 - || memory_init_func_type->result_count != 0) - /* Not a valid function type, ignore it */ +#if WASM_ENABLE_BULK_MEMORY != 0 + /* Only execute the memory init function for main instance since + the data segments will be dropped once initialized */ + if (!is_sub_inst +#if WASM_ENABLE_LIBC_WASI != 0 + && !module->import_wasi_api +#endif + ) { + call_ctors_func = + lookup_post_instantiate_func(module_inst, "__wasm_call_ctors"); + } +#endif + + if (!start_func && !initialize_func && !post_inst_func + && !call_ctors_func) { + /* No post instantiation functions to call */ return true; + } - return wasm_create_exec_env_and_call_function(module_inst, memory_init_func, - 0, NULL); -} + if (is_sub_inst) { + bh_assert(exec_env_main); +#ifdef OS_ENABLE_HW_BOUND_CHECK + bh_assert(exec_env_tls == exec_env_main); + (void)exec_env_tls; #endif + exec_env = exec_env_main; -static bool -execute_start_function(WASMModuleInstance *module_inst) -{ - WASMFunctionInstance *func = module_inst->start_function; + /* Temporarily replace parent exec_env's module inst to current + module inst to avoid checking failure when calling the + wasm functions, and ensure that the exec_env's module inst + is the correct one. */ + module_inst_main = exec_env_main->module_inst; + exec_env->module_inst = (WASMModuleInstanceCommon *)module_inst; + } + else { + /* Try using the existing exec_env */ +#ifdef OS_ENABLE_HW_BOUND_CHECK + exec_env = exec_env_tls; +#endif +#if WASM_ENABLE_THREAD_MGR != 0 + if (!exec_env) + exec_env = wasm_clusters_search_exec_env( + (WASMModuleInstanceCommon *)module_inst); +#endif + if (!exec_env) { + if (!(exec_env = exec_env_created = wasm_exec_env_create( + (WASMModuleInstanceCommon *)module_inst, + module_inst->default_wasm_stack_size))) { + wasm_set_exception(module_inst, "allocate memory failed"); + return false; + } + } + else { + /* Temporarily replace exec_env's module inst with current + module inst to ensure that the exec_env's module inst + is the correct one. */ + module_inst_main = exec_env->module_inst; + exec_env->module_inst = (WASMModuleInstanceCommon *)module_inst; + } + } - if (!func) - return true; + /* Execute start function for both main insance and sub instance */ + if (start_func && !wasm_call_function(exec_env, start_func, 0, NULL)) { + goto fail; + } + + if (initialize_func + && !wasm_call_function(exec_env, initialize_func, 0, NULL)) { + goto fail; + } + + if (post_inst_func + && !wasm_call_function(exec_env, post_inst_func, 0, NULL)) { + goto fail; + } + + if (call_ctors_func + && !wasm_call_function(exec_env, call_ctors_func, 0, NULL)) { + goto fail; + } + + ret = true; - bh_assert(!func->is_import_func && func->param_cell_num == 0 - && func->ret_cell_num == 0); +fail: + if (is_sub_inst) { + /* Restore the parent exec_env's module inst */ + exec_env_main->module_inst = module_inst_main; + } + else { + if (module_inst_main) + /* Restore the existing exec_env's module inst */ + exec_env->module_inst = module_inst_main; + if (exec_env_created) + wasm_exec_env_destroy(exec_env_created); + } - return wasm_create_exec_env_and_call_function(module_inst, func, 0, NULL); + return ret; } static bool -execute_malloc_function(WASMModuleInstance *module_inst, +execute_malloc_function(WASMModuleInstance *module_inst, WASMExecEnv *exec_env, WASMFunctionInstance *malloc_func, WASMFunctionInstance *retain_func, uint32 size, uint32 *p_result) @@ -1054,6 +1146,8 @@ execute_malloc_function(WASMModuleInstance *module_inst, #ifdef OS_ENABLE_HW_BOUND_CHECK WASMExecEnv *exec_env_tls = wasm_runtime_get_exec_env_tls(); #endif + WASMExecEnv *exec_env_created = NULL; + WASMModuleInstanceCommon *module_inst_old = NULL; uint32 argv[2], argc; bool ret; @@ -1072,55 +1166,119 @@ execute_malloc_function(WASMModuleInstance *module_inst, argc = 2; } + if (exec_env) { #ifdef OS_ENABLE_HW_BOUND_CHECK - if (exec_env_tls != NULL) { - bh_assert(exec_env_tls->module_inst - == (WASMModuleInstanceCommon *)module_inst); - ret = wasm_call_function(exec_env_tls, malloc_func, argc, argv); - - if (retain_func && ret) { - ret = wasm_call_function(exec_env_tls, retain_func, 1, argv); + if (exec_env_tls) { + bh_assert(exec_env_tls == exec_env); } +#endif + bh_assert(exec_env->module_inst + == (WASMModuleInstanceCommon *)module_inst); } - else + else { + /* Try using the existing exec_env */ +#ifdef OS_ENABLE_HW_BOUND_CHECK + exec_env = exec_env_tls; #endif - { - ret = wasm_create_exec_env_and_call_function(module_inst, malloc_func, - argc, argv); - - if (retain_func && ret) { - ret = wasm_create_exec_env_and_call_function(module_inst, - retain_func, 1, argv); +#if WASM_ENABLE_THREAD_MGR != 0 + if (!exec_env) + exec_env = wasm_clusters_search_exec_env( + (WASMModuleInstanceCommon *)module_inst); +#endif + if (!exec_env) { + if (!(exec_env = exec_env_created = wasm_exec_env_create( + (WASMModuleInstanceCommon *)module_inst, + module_inst->default_wasm_stack_size))) { + wasm_set_exception(module_inst, "allocate memory failed"); + return false; + } + } + else { + /* Temporarily replace exec_env's module inst with current + module inst to ensure that the exec_env's module inst + is the correct one. */ + module_inst_old = exec_env->module_inst; + exec_env->module_inst = (WASMModuleInstanceCommon *)module_inst; } } + ret = wasm_call_function(exec_env, malloc_func, argc, argv); + + if (retain_func && ret) + ret = wasm_call_function(exec_env, retain_func, 1, argv); + + if (module_inst_old) + /* Restore the existing exec_env's module inst */ + exec_env->module_inst = module_inst_old; + + if (exec_env_created) + wasm_exec_env_destroy(exec_env_created); + if (ret) *p_result = argv[0]; return ret; } static bool -execute_free_function(WASMModuleInstance *module_inst, +execute_free_function(WASMModuleInstance *module_inst, WASMExecEnv *exec_env, WASMFunctionInstance *free_func, uint32 offset) { #ifdef OS_ENABLE_HW_BOUND_CHECK WASMExecEnv *exec_env_tls = wasm_runtime_get_exec_env_tls(); #endif + WASMExecEnv *exec_env_created = NULL; + WASMModuleInstanceCommon *module_inst_old = NULL; uint32 argv[2]; + bool ret; argv[0] = offset; + + if (exec_env) { #ifdef OS_ENABLE_HW_BOUND_CHECK - if (exec_env_tls != NULL) { - bh_assert(exec_env_tls->module_inst + if (exec_env_tls) { + bh_assert(exec_env_tls == exec_env); + } +#endif + bh_assert(exec_env->module_inst == (WASMModuleInstanceCommon *)module_inst); - return wasm_call_function(exec_env_tls, free_func, 1, argv); } - else + else { + /* Try using the existing exec_env */ +#ifdef OS_ENABLE_HW_BOUND_CHECK + exec_env = exec_env_tls; #endif - { - return wasm_create_exec_env_and_call_function(module_inst, free_func, 1, - argv); +#if WASM_ENABLE_THREAD_MGR != 0 + if (!exec_env) + exec_env = wasm_clusters_search_exec_env( + (WASMModuleInstanceCommon *)module_inst); +#endif + if (!exec_env) { + if (!(exec_env = exec_env_created = wasm_exec_env_create( + (WASMModuleInstanceCommon *)module_inst, + module_inst->default_wasm_stack_size))) { + wasm_set_exception(module_inst, "allocate memory failed"); + return false; + } + } + else { + /* Temporarily replace exec_env's module inst with current + module inst to ensure that the exec_env's module inst + is the correct one. */ + module_inst_old = exec_env->module_inst; + exec_env->module_inst = (WASMModuleInstanceCommon *)module_inst; + } } + + ret = wasm_call_function(exec_env, free_func, 1, argv); + + if (module_inst_old) + /* Restore the existing exec_env's module inst */ + exec_env->module_inst = module_inst_old; + + if (exec_env_created) + wasm_exec_env_destroy(exec_env_created); + + return ret; } #if WASM_ENABLE_MULTI_MODULE != 0 @@ -1129,7 +1287,7 @@ sub_module_instantiate(WASMModule *module, WASMModuleInstance *module_inst, uint32 stack_size, uint32 heap_size, char *error_buf, uint32 error_buf_size) { - bh_list *sub_module_inst_list = module_inst->sub_module_inst_list; + bh_list *sub_module_inst_list = module_inst->e->sub_module_inst_list; WASMRegisteredModule *sub_module_list_node = bh_list_first_elem(module->import_module_list); @@ -1139,7 +1297,7 @@ sub_module_instantiate(WASMModule *module, WASMModuleInstance *module_inst, WASMModuleInstance *sub_module_inst = NULL; sub_module_inst = - wasm_instantiate(sub_module, false, stack_size, heap_size, + wasm_instantiate(sub_module, false, NULL, stack_size, heap_size, error_buf, error_buf_size); if (!sub_module_inst) { LOG_DEBUG("instantiate %s failed", @@ -1165,28 +1323,6 @@ sub_module_instantiate(WASMModule *module, WASMModuleInstance *module_inst, sub_module_list_node = bh_list_elem_next(sub_module_list_node); -#if WASM_ENABLE_LIBC_WASI != 0 - { - /* - * reactor instances may assume that _initialize will be called by - * the environment at most once, and that none of their other - * exports are accessed before that call. - * - * let the loader decide how to act if there is no _initialize - * in a reactor - */ - WASMFunctionInstance *initialize = - wasm_lookup_function(sub_module_inst, "_initialize", NULL); - if (initialize - && !wasm_create_exec_env_and_call_function( - sub_module_inst, initialize, 0, NULL)) { - set_error_buf(error_buf, error_buf_size, - "Call _initialize failed "); - goto failed; - } - } -#endif - continue; failed: if (sub_module_inst_list_node) { @@ -1205,7 +1341,7 @@ sub_module_instantiate(WASMModule *module, WASMModuleInstance *module_inst, static void sub_module_deinstantiate(WASMModuleInstance *module_inst) { - bh_list *list = module_inst->sub_module_inst_list; + bh_list *list = module_inst->e->sub_module_inst_list; WASMSubModInstNode *node = bh_list_first_elem(list); while (node) { WASMSubModInstNode *next_node = bh_list_elem_next(node); @@ -1235,6 +1371,7 @@ check_linked_symbol(WASMModuleInstance *module_inst, char *error_buf, #if WASM_ENABLE_WAMR_COMPILER == 0 LOG_WARNING("warning: failed to link import function (%s, %s)", func->module_name, func->field_name); + /* will throw exception only if calling */ #else /* do nothing to avoid confused message */ #endif /* WASM_ENABLE_WAMR_COMPILER == 0 */ @@ -1250,8 +1387,10 @@ check_linked_symbol(WASMModuleInstance *module_inst, char *error_buf, return false; #else #if WASM_ENABLE_WAMR_COMPILER == 0 - LOG_DEBUG("warning: failed to link import global (%s, %s)", - global->module_name, global->field_name); + set_error_buf_v(error_buf, error_buf_size, + "failed to link import global (%s, %s)", + global->module_name, global->field_name); + return false; #else /* do nothing to avoid confused message */ #endif /* WASM_ENABLE_WAMR_COMPILER == 0 */ @@ -1262,7 +1401,36 @@ check_linked_symbol(WASMModuleInstance *module_inst, char *error_buf, return true; } -#if WASM_ENABLE_FAST_JIT != 0 +#if WASM_ENABLE_JIT != 0 +static bool +init_func_ptrs(WASMModuleInstance *module_inst, WASMModule *module, + char *error_buf, uint32 error_buf_size) +{ + uint32 i; + void **func_ptrs; + uint64 total_size = (uint64)sizeof(void *) * module_inst->e->function_count; + + /* Allocate memory */ + if (!(func_ptrs = module_inst->func_ptrs = + runtime_malloc(total_size, error_buf, error_buf_size))) { + return false; + } + + /* Set import function pointers */ + for (i = 0; i < module->import_function_count; i++, func_ptrs++) { + WASMFunctionImport *import_func = + &module->import_functions[i].u.function; + /* TODO: handle multi module */ + *func_ptrs = import_func->func_ptr_linked; + } + + /* The defined function pointers will be set in + wasm_runtime_set_running_mode, no need to set them here */ + return true; +} +#endif /* end of WASM_ENABLE_JIT != 0 */ + +#if WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0 static uint32 get_smallest_type_idx(WASMModule *module, WASMType *func_type) { @@ -1282,7 +1450,7 @@ init_func_type_indexes(WASMModuleInstance *module_inst, char *error_buf, uint32 error_buf_size) { uint32 i; - uint64 total_size = (uint64)sizeof(uint32) * module_inst->function_count; + uint64 total_size = (uint64)sizeof(uint32) * module_inst->e->function_count; /* Allocate memory */ if (!(module_inst->func_type_indexes = @@ -1290,8 +1458,8 @@ init_func_type_indexes(WASMModuleInstance *module_inst, char *error_buf, return false; } - for (i = 0; i < module_inst->function_count; i++) { - WASMFunctionInstance *func_inst = module_inst->functions + i; + for (i = 0; i < module_inst->e->function_count; i++) { + WASMFunctionInstance *func_inst = module_inst->e->functions + i; WASMType *func_type = func_inst->is_import_func ? func_inst->u.func_import->func_type : func_inst->u.func->func_type; @@ -1301,19 +1469,192 @@ init_func_type_indexes(WASMModuleInstance *module_inst, char *error_buf, return true; } +#endif /* end of WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0 */ + +static bool +set_running_mode(WASMModuleInstance *module_inst, RunningMode running_mode, + bool first_time_set) +{ + WASMModule *module = module_inst->module; + + if (running_mode == Mode_Default) { +#if WASM_ENABLE_FAST_JIT == 0 && WASM_ENABLE_JIT == 0 + running_mode = Mode_Interp; +#elif WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT == 0 + running_mode = Mode_Fast_JIT; +#elif WASM_ENABLE_FAST_JIT == 0 && WASM_ENABLE_JIT != 0 + running_mode = Mode_LLVM_JIT; +#else /* WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 */ +#if WASM_ENABLE_LAZY_JIT == 0 + running_mode = Mode_LLVM_JIT; +#else + running_mode = Mode_Multi_Tier_JIT; +#endif +#endif + } + + if (!wasm_runtime_is_running_mode_supported(running_mode)) + return false; + +#if !(WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \ + && WASM_ENABLE_LAZY_JIT != 0) /* No possible multi-tier JIT */ + module_inst->e->running_mode = running_mode; + + if (running_mode == Mode_Interp) { + /* Do nothing for Mode_Interp */ + } + else if (running_mode == Mode_Fast_JIT) { + /* Do nothing for Mode_Fast_JIT since + module_inst->fast_jit_func_ptrs is same as + module->fast_jit_func_ptrs */ + } +#if WASM_ENABLE_JIT != 0 + else if (running_mode == Mode_LLVM_JIT) { + /* Set defined function pointers */ + bh_memcpy_s(module_inst->func_ptrs + module->import_function_count, + sizeof(void *) * module->function_count, module->func_ptrs, + sizeof(void *) * module->function_count); + } +#endif + else { + bh_assert(0); + } +#else /* Possible multi-tier JIT */ + os_mutex_lock(&module->instance_list_lock); + + module_inst->e->running_mode = running_mode; + + if (running_mode == Mode_Interp) { + /* Do nothing for Mode_Interp */ + } +#if WASM_ENABLE_FAST_JIT != 0 + else if (running_mode == Mode_Fast_JIT) { + JitGlobals *jit_globals = jit_compiler_get_jit_globals(); + uint32 i; + + /* Allocate memory for fast_jit_func_ptrs if needed */ + if (!module_inst->fast_jit_func_ptrs + || module_inst->fast_jit_func_ptrs == module->fast_jit_func_ptrs) { + uint64 total_size = (uint64)sizeof(void *) * module->function_count; + if (!(module_inst->fast_jit_func_ptrs = + runtime_malloc(total_size, NULL, 0))) { + os_mutex_unlock(&module->instance_list_lock); + return false; + } + } + + for (i = 0; i < module->function_count; i++) { + if (module->functions[i]->fast_jit_jitted_code) { + /* current fast jit function has been compiled */ + module_inst->fast_jit_func_ptrs[i] = + module->functions[i]->fast_jit_jitted_code; + } + else { + module_inst->fast_jit_func_ptrs[i] = + jit_globals->compile_fast_jit_and_then_call; + } + } + } +#endif +#if WASM_ENABLE_JIT != 0 + else if (running_mode == Mode_LLVM_JIT) { + void **llvm_jit_func_ptrs; + uint32 i; + + /* Notify backend threads to start llvm jit compilation */ + module->enable_llvm_jit_compilation = true; + + /* Wait until llvm jit finishes initialization */ + os_mutex_lock(&module->tierup_wait_lock); + while (!module->llvm_jit_inited) { + os_cond_reltimedwait(&module->tierup_wait_cond, + &module->tierup_wait_lock, 10000); + if (module->orcjit_stop_compiling) { + /* init_llvm_jit_functions_stage2 failed */ + os_mutex_unlock(&module->tierup_wait_lock); + os_mutex_unlock(&module->instance_list_lock); + return false; + } + } + os_mutex_unlock(&module->tierup_wait_lock); + + llvm_jit_func_ptrs = + module_inst->func_ptrs + module->import_function_count; + for (i = 0; i < module->function_count; i++) { + llvm_jit_func_ptrs[i] = module->functions[i]->llvm_jit_func_ptr; + } + } #endif + else if (running_mode == Mode_Multi_Tier_JIT) { + /* Notify backend threads to start llvm jit compilation */ + module->enable_llvm_jit_compilation = true; + + /* Free fast_jit_func_ptrs if it is allocated before */ + if (module_inst->fast_jit_func_ptrs + && module_inst->fast_jit_func_ptrs != module->fast_jit_func_ptrs) { + wasm_runtime_free(module_inst->fast_jit_func_ptrs); + } + module_inst->fast_jit_func_ptrs = module->fast_jit_func_ptrs; + + /* Copy all llvm jit func ptrs from the module */ + bh_memcpy_s(module_inst->func_ptrs + module->import_function_count, + sizeof(void *) * module->function_count, module->func_ptrs, + sizeof(void *) * module->function_count); + } + else { + bh_assert(0); + } + + /* Add module instance into module's instance list if not added */ + if (first_time_set) { + bool found = false; + WASMModuleInstance *node = module->instance_list; + + while (node) { + if (node == module_inst) { + found = true; + break; + } + node = node->e->next; + } + + if (!found) { + module_inst->e->next = module->instance_list; + module->instance_list = module_inst; + } + } + + os_mutex_unlock(&module->instance_list_lock); +#endif /* end of !(WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \ + && WASM_ENABLE_LAZY_JIT != 0) */ + + (void)module; + return true; +} + +bool +wasm_set_running_mode(WASMModuleInstance *module_inst, RunningMode running_mode) +{ + return set_running_mode(module_inst, running_mode, false); +} /** * Instantiate module */ WASMModuleInstance * -wasm_instantiate(WASMModule *module, bool is_sub_inst, uint32 stack_size, +wasm_instantiate(WASMModule *module, bool is_sub_inst, + WASMExecEnv *exec_env_main, uint32 stack_size, uint32 heap_size, char *error_buf, uint32 error_buf_size) { WASMModuleInstance *module_inst; WASMGlobalInstance *globals = NULL, *global; - uint32 global_count, global_data_size = 0, i; - uint32 base_offset, length; + WASMTableInstance *first_table; + uint32 global_count, i; + uint32 base_offset, length, extra_info_offset; + uint32 module_inst_struct_size = + offsetof(WASMModuleInstance, global_table_data.bytes); + uint64 module_inst_mem_inst_size; + uint64 total_size, table_size = 0; uint8 *global_data, *global_data_end; #if WASM_ENABLE_MULTI_MODULE != 0 bool ret = false; @@ -1322,43 +1663,73 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, uint32 stack_size, if (!module) return NULL; -#if WASM_ENABLE_DEBUG_INTERP != 0 - if (!is_sub_inst) { - os_mutex_lock(&module->ref_count_lock); - if (module->ref_count != 0) { - LOG_WARNING( - "warning: multiple instances referencing the same module may " - "cause unexpected behaviour during debugging"); - } - module->ref_count++; - os_mutex_unlock(&module->ref_count_lock); - } -#endif - - /* Check heap size */ + /* Check the heap size */ heap_size = align_uint(heap_size, 8); if (heap_size > APP_HEAP_SIZE_MAX) heap_size = APP_HEAP_SIZE_MAX; - /* Allocate the memory */ - if (!(module_inst = runtime_malloc(sizeof(WASMModuleInstance), error_buf, - error_buf_size))) { -#if WASM_ENABLE_DEBUG_INTERP != 0 - if (!is_sub_inst) { - os_mutex_lock(&module->ref_count_lock); - module->ref_count--; - os_mutex_unlock(&module->ref_count_lock); - } + module_inst_mem_inst_size = + (uint64)sizeof(WASMMemoryInstance) + * (module->import_memory_count + module->memory_count); + +#if WASM_ENABLE_JIT != 0 + /* If the module dosen't have memory, reserve one mem_info space + with empty content to align with llvm jit compiler */ + if (module_inst_mem_inst_size == 0) + module_inst_mem_inst_size = (uint64)sizeof(WASMMemoryInstance); #endif - return NULL; - } - module_inst->module = module; + /* Size of module inst, memory instances and global data */ + total_size = (uint64)module_inst_struct_size + module_inst_mem_inst_size + + module->global_data_size; + /* Calculate the size of table data */ + for (i = 0; i < module->import_table_count; i++) { + WASMTableImport *import_table = &module->import_tables[i].u.table; + table_size += offsetof(WASMTableInstance, elems); #if WASM_ENABLE_MULTI_MODULE != 0 - module_inst->sub_module_inst_list = &module_inst->sub_module_inst_list_head; - ret = sub_module_instantiate(module, module_inst, stack_size, heap_size, - error_buf, error_buf_size); + table_size += (uint64)sizeof(uint32) * import_table->max_size; +#else + table_size += (uint64)sizeof(uint32) + * (import_table->possible_grow ? import_table->max_size + : import_table->init_size); +#endif + } + for (i = 0; i < module->table_count; i++) { + WASMTable *table = module->tables + i; + table_size += offsetof(WASMTableInstance, elems); +#if WASM_ENABLE_MULTI_MODULE != 0 + table_size += (uint64)sizeof(uint32) * table->max_size; +#else + table_size += + (uint64)sizeof(uint32) + * (table->possible_grow ? table->max_size : table->init_size); +#endif + } + total_size += table_size; + + /* The offset of WASMModuleInstanceExtra, make it 8-byte aligned */ + total_size = (total_size + 7LL) & ~7LL; + extra_info_offset = (uint32)total_size; + total_size += sizeof(WASMModuleInstanceExtra); + + /* Allocate the memory for module instance with memory instances, + global data, table data appended at the end */ + if (!(module_inst = + runtime_malloc(total_size, error_buf, error_buf_size))) { + return NULL; + } + + module_inst->module_type = Wasm_Module_Bytecode; + module_inst->module = module; + module_inst->e = + (WASMModuleInstanceExtra *)((uint8 *)module_inst + extra_info_offset); + +#if WASM_ENABLE_MULTI_MODULE != 0 + module_inst->e->sub_module_inst_list = + &module_inst->e->sub_module_inst_list_head; + ret = sub_module_instantiate(module, module_inst, stack_size, heap_size, + error_buf, error_buf_size); if (!ret) { LOG_DEBUG("build a sub module list failed"); goto fail; @@ -1375,59 +1746,62 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, uint32 stack_size, /* Instantiate global firstly to get the mutable data size */ global_count = module->import_global_count + module->global_count; if (global_count - && !(globals = - globals_instantiate(module, module_inst, &global_data_size, - error_buf, error_buf_size))) { + && !(globals = globals_instantiate(module, module_inst, error_buf, + error_buf_size))) { goto fail; } - module_inst->global_count = global_count; - module_inst->globals = globals; + module_inst->e->global_count = global_count; + module_inst->e->globals = globals; + module_inst->global_data = (uint8 *)module_inst + module_inst_struct_size + + module_inst_mem_inst_size; + module_inst->global_data_size = module->global_data_size; + first_table = (WASMTableInstance *)(module_inst->global_data + + module->global_data_size); module_inst->memory_count = module->import_memory_count + module->memory_count; module_inst->table_count = module->import_table_count + module->table_count; - module_inst->function_count = + module_inst->e->function_count = module->import_function_count + module->function_count; /* export */ module_inst->export_func_count = get_export_count(module, EXPORT_KIND_FUNC); #if WASM_ENABLE_MULTI_MODULE != 0 - module_inst->export_tab_count = get_export_count(module, EXPORT_KIND_TABLE); - module_inst->export_mem_count = + module_inst->export_table_count = + get_export_count(module, EXPORT_KIND_TABLE); + module_inst->export_memory_count = get_export_count(module, EXPORT_KIND_MEMORY); - module_inst->export_glob_count = + module_inst->export_global_count = get_export_count(module, EXPORT_KIND_GLOBAL); #endif - if (global_count > 0) { - if (!(module_inst->global_data = runtime_malloc( - global_data_size, error_buf, error_buf_size))) { - goto fail; - } - } - /* 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->table_count > 0 - && !(module_inst->tables = tables_instantiate( - module, module_inst, error_buf, error_buf_size))) - || (module_inst->function_count > 0 - && !(module_inst->functions = functions_instantiate( + && !(module_inst->tables = + tables_instantiate(module, module_inst, first_table, + error_buf, error_buf_size))) + || (module_inst->e->function_count > 0 + && !(module_inst->e->functions = functions_instantiate( module, module_inst, error_buf, error_buf_size))) || (module_inst->export_func_count > 0 && !(module_inst->export_functions = export_functions_instantiate( module, module_inst, module_inst->export_func_count, error_buf, error_buf_size))) #if WASM_ENABLE_MULTI_MODULE != 0 - || (module_inst->export_glob_count > 0 + || (module_inst->export_global_count > 0 && !(module_inst->export_globals = export_globals_instantiate( - module, module_inst, module_inst->export_glob_count, + module, module_inst, module_inst->export_global_count, error_buf, error_buf_size))) #endif -#if WASM_ENABLE_FAST_JIT != 0 - || (module_inst->function_count > 0 +#if WASM_ENABLE_JIT != 0 + || (module_inst->e->function_count > 0 + && !init_func_ptrs(module_inst, module, error_buf, error_buf_size)) +#endif +#if WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0 + || (module_inst->e->function_count > 0 && !init_func_type_indexes(module_inst, error_buf, error_buf_size)) #endif ) { @@ -1437,7 +1811,7 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, uint32 stack_size, if (global_count > 0) { /* Initialize the global data */ global_data = module_inst->global_data; - global_data_end = global_data + global_data_size; + global_data_end = global_data + module->global_data_size; global = globals; for (i = 0; i < global_count; i++, global++) { switch (global->type) { @@ -1457,6 +1831,13 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, uint32 stack_size, &global->initial_value.i64, sizeof(int64)); global_data += sizeof(int64); break; +#if WASM_ENABLE_SIMD != 0 + case VALUE_TYPE_V128: + bh_memcpy_s(global_data, (uint32)sizeof(V128), + &global->initial_value.v128, sizeof(V128)); + global_data += sizeof(V128); + break; +#endif default: bh_assert(0); } @@ -1469,9 +1850,6 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, uint32 stack_size, } /* Initialize the memory data with data segment section */ - module_inst->default_memory = - module_inst->memory_count ? module_inst->memories[0] : NULL; - for (i = 0; i < module->data_seg_count; i++) { WASMMemoryInstance *memory = NULL; uint8 *memory_data = NULL; @@ -1554,30 +1932,41 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, uint32 stack_size, } /* Initialize the table data with table segment section */ - module_inst->default_table = - module_inst->table_count ? module_inst->tables[0] : NULL; - /* in case there is no table */ for (i = 0; module_inst->table_count > 0 && i < module->table_seg_count; i++) { WASMTableSeg *table_seg = module->table_segments + i; /* has check it in loader */ WASMTableInstance *table = module_inst->tables[table_seg->table_index]; + uint32 *table_data; +#if WASM_ENABLE_REF_TYPES != 0 + uint8 tbl_elem_type; + uint32 tbl_init_size, tbl_max_size; +#endif + bh_assert(table); #if WASM_ENABLE_REF_TYPES != 0 - if (table->elem_type != VALUE_TYPE_FUNCREF - && table->elem_type != VALUE_TYPE_EXTERNREF) { + (void)wasm_runtime_get_table_inst_elem_type( + (WASMModuleInstanceCommon *)module_inst, table_seg->table_index, + &tbl_elem_type, &tbl_init_size, &tbl_max_size); + if (tbl_elem_type != VALUE_TYPE_FUNCREF + && tbl_elem_type != VALUE_TYPE_EXTERNREF) { set_error_buf(error_buf, error_buf_size, "elements segment does not fit"); goto fail; } + (void)tbl_init_size; + (void)tbl_max_size; #endif - uint32 *table_data = (uint32 *)table->base_addr; + table_data = table->elems; #if WASM_ENABLE_MULTI_MODULE != 0 - table_data = table->table_inst_linked - ? (uint32 *)table->table_inst_linked->base_addr - : table_data; + if (table_seg->table_index < module->import_table_count + && module_inst->e->table_insts_linked[table_seg->table_index]) { + table_data = + module_inst->e->table_insts_linked[table_seg->table_index] + ->elems; + } #endif bh_assert(table_data); @@ -1586,7 +1975,6 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, uint32 stack_size, continue; #endif - /* init vec(funcidx) or vec(expr) */ #if WASM_ENABLE_REF_TYPES != 0 bh_assert(table_seg->base_offset.init_expr_type == INIT_EXPR_TYPE_I32_CONST @@ -1603,6 +1991,7 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, uint32 stack_size, == INIT_EXPR_TYPE_GET_GLOBAL); #endif + /* init vec(funcidx) or vec(expr) */ if (table_seg->base_offset.init_expr_type == INIT_EXPR_TYPE_GET_GLOBAL) { if (!check_global_init_expr(module, @@ -1665,9 +2054,6 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, uint32 stack_size, table_seg->func_indexes, (uint32)(length * sizeof(uint32))); } - /* module instance type */ - module_inst->module_type = Wasm_Module_Bytecode; - /* Initialize the thread related data */ if (stack_size == 0) stack_size = DEFAULT_WASM_STACK_SIZE; @@ -1678,18 +2064,18 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, uint32 stack_size, module_inst->default_wasm_stack_size = stack_size; if (module->malloc_function != (uint32)-1) { - module_inst->malloc_function = - &module_inst->functions[module->malloc_function]; + module_inst->e->malloc_function = + &module_inst->e->functions[module->malloc_function]; } if (module->free_function != (uint32)-1) { - module_inst->free_function = - &module_inst->functions[module->free_function]; + module_inst->e->free_function = + &module_inst->e->functions[module->free_function]; } if (module->retain_function != (uint32)-1) { - module_inst->retain_function = - &module_inst->functions[module->retain_function]; + module_inst->e->retain_function = + &module_inst->e->functions[module->retain_function]; } #if WASM_ENABLE_LIBC_WASI != 0 @@ -1711,45 +2097,58 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst, uint32 stack_size, } #endif +#if WASM_ENABLE_WASI_NN != 0 + if (!is_sub_inst) { + if (!(module_inst->e->wasi_nn_ctx = wasi_nn_initialize())) { + set_error_buf(error_buf, error_buf_size, + "wasi nn initialization failed"); + goto fail; + } + } +#endif + +#if WASM_ENABLE_DEBUG_INTERP != 0 + if (!is_sub_inst) { + /* Add module instance into module's instance list */ + os_mutex_lock(&module->instance_list_lock); + if (module->instance_list) { + LOG_WARNING( + "warning: multiple instances referencing to the same module " + "may cause unexpected behaviour during debugging"); + } + module_inst->e->next = module->instance_list; + module->instance_list = module_inst; + os_mutex_unlock(&module->instance_list_lock); + } +#endif + + /* Set running mode before executing wasm functions */ + if (!set_running_mode(module_inst, wasm_runtime_get_default_running_mode(), + true)) { + set_error_buf(error_buf, error_buf_size, + "set instance running mode failed"); + goto fail; + } + if (module->start_function != (uint32)-1) { /* TODO: fix start function can be import function issue */ if (module->start_function >= module->import_function_count) - module_inst->start_function = - &module_inst->functions[module->start_function]; + module_inst->e->start_function = + &module_inst->e->functions[module->start_function]; } - /* Execute __post_instantiate function */ - if (!execute_post_inst_function(module_inst) - || !execute_start_function(module_inst)) { + if (!execute_post_instantiate_functions(module_inst, is_sub_inst, + exec_env_main)) { set_error_buf(error_buf, error_buf_size, module_inst->cur_exception); goto fail; } -#if WASM_ENABLE_BULK_MEMORY != 0 -#if WASM_ENABLE_LIBC_WASI != 0 - if (!module->import_wasi_api) { -#endif - /* Only execute the memory init function for main instance because - the data segments will be dropped once initialized. - */ - if (!is_sub_inst) { - if (!execute_memory_init_function(module_inst)) { - set_error_buf(error_buf, error_buf_size, - module_inst->cur_exception); - goto fail; - } - } -#if WASM_ENABLE_LIBC_WASI != 0 - } -#endif -#endif - #if WASM_ENABLE_MEMORY_TRACING != 0 wasm_runtime_dump_module_inst_mem_consumption( (WASMModuleInstanceCommon *)module_inst); #endif - (void)global_data_end; + (void)global_data_end; return module_inst; fail: @@ -1763,7 +2162,58 @@ wasm_deinstantiate(WASMModuleInstance *module_inst, bool is_sub_inst) if (!module_inst) return; -#if WASM_ENABLE_FAST_JIT != 0 + if (module_inst->exec_env_singleton) { + /* wasm_exec_env_destroy will call + wasm_cluster_wait_for_all_except_self to wait for other + threads, so as to destroy their exec_envs and module + instances first, and avoid accessing the shared resources + of current module instance after it is deinstantiated. */ + wasm_exec_env_destroy(module_inst->exec_env_singleton); + } + +#if WASM_ENABLE_DEBUG_INTERP != 0 \ + || (WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \ + && WASM_ENABLE_LAZY_JIT != 0) + /* Remove instance from module's instance list before freeing + func_ptrs and fast_jit_func_ptrs of the instance, to avoid + accessing the freed memory in the jit backend compilation + threads */ + { + WASMModule *module = module_inst->module; + WASMModuleInstance *instance_prev = NULL, *instance; + os_mutex_lock(&module->instance_list_lock); + + instance = module->instance_list; + while (instance) { + if (instance == module_inst) { + if (!instance_prev) + module->instance_list = instance->e->next; + else + instance_prev->e->next = instance->e->next; + break; + } + instance_prev = instance; + instance = instance->e->next; + } + + os_mutex_unlock(&module->instance_list_lock); + } +#endif + +#if WASM_ENABLE_JIT != 0 + if (module_inst->func_ptrs) + wasm_runtime_free(module_inst->func_ptrs); +#endif + +#if WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \ + && WASM_ENABLE_LAZY_JIT != 0 + if (module_inst->fast_jit_func_ptrs + && module_inst->fast_jit_func_ptrs + != module_inst->module->fast_jit_func_ptrs) + wasm_runtime_free(module_inst->fast_jit_func_ptrs); +#endif + +#if WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0 if (module_inst->func_type_indexes) wasm_runtime_free(module_inst->func_type_indexes); #endif @@ -1790,25 +2240,19 @@ wasm_deinstantiate(WASMModuleInstance *module_inst, bool is_sub_inst) wasm_runtime_free(module_inst->import_func_ptrs); } - tables_deinstantiate(module_inst->tables, module_inst->table_count); - functions_deinstantiate(module_inst->functions, - module_inst->function_count); - globals_deinstantiate(module_inst->globals); + tables_deinstantiate(module_inst); + functions_deinstantiate(module_inst->e->functions, + module_inst->e->function_count); + globals_deinstantiate(module_inst->e->globals); export_functions_deinstantiate(module_inst->export_functions); #if WASM_ENABLE_MULTI_MODULE != 0 export_globals_deinstantiate(module_inst->export_globals); #endif - if (module_inst->global_data) - wasm_runtime_free(module_inst->global_data); - #if WASM_ENABLE_REF_TYPES != 0 wasm_externref_cleanup((WASMModuleInstanceCommon *)module_inst); #endif - if (module_inst->exec_env_singleton) - wasm_exec_env_destroy(module_inst->exec_env_singleton); - #if WASM_ENABLE_DUMP_CALL_STACK != 0 if (module_inst->frames) { bh_vector_destroy(module_inst->frames); @@ -1817,11 +2261,14 @@ wasm_deinstantiate(WASMModuleInstance *module_inst, bool is_sub_inst) } #endif -#if WASM_ENABLE_DEBUG_INTERP != 0 + if (module_inst->e->c_api_func_imports) + wasm_runtime_free(module_inst->e->c_api_func_imports); + +#if WASM_ENABLE_WASI_NN != 0 if (!is_sub_inst) { - os_mutex_lock(&module_inst->module->ref_count_lock); - module_inst->module->ref_count--; - os_mutex_unlock(&module_inst->module->ref_count_lock); + WASINNContext *wasi_nn_ctx = module_inst->e->wasi_nn_ctx; + if (wasi_nn_ctx) + wasi_nn_destroy(wasi_nn_ctx); } #endif @@ -1845,7 +2292,7 @@ WASMGlobalInstance * wasm_lookup_global(const WASMModuleInstance *module_inst, const char *name) { uint32 i; - for (i = 0; i < module_inst->export_glob_count; i++) + for (i = 0; i < module_inst->export_global_count; i++) if (!strcmp(module_inst->export_globals[i].name, name)) return module_inst->export_globals[i].global; return NULL; @@ -1874,133 +2321,8 @@ wasm_lookup_table(const WASMModuleInstance *module_inst, const char *name) } #endif -static bool -clear_wasi_proc_exit_exception(WASMModuleInstance *module_inst) -{ -#if WASM_ENABLE_LIBC_WASI != 0 - const char *exception = wasm_get_exception(module_inst); - if (exception && !strcmp(exception, "Exception: wasi proc exit")) { - /* The "wasi proc exit" exception is thrown by native lib to - let wasm app exit, which is a normal behavior, we clear - the exception here. */ - wasm_set_exception(module_inst, NULL); - return true; - } - return false; -#else - return false; -#endif -} - #ifdef OS_ENABLE_HW_BOUND_CHECK -#ifndef BH_PLATFORM_WINDOWS -void -wasm_signal_handler(WASMSignalInfo *sig_info) -{ - WASMExecEnv *exec_env_tls = sig_info->exec_env_tls; - void *sig_addr = sig_info->sig_addr; - WASMModuleInstance *module_inst; - WASMMemoryInstance *memory_inst; - WASMJmpBuf *jmpbuf_node; - uint8 *mapped_mem_start_addr = NULL; - uint8 *mapped_mem_end_addr = NULL; - uint8 *stack_min_addr; - uint32 page_size; - uint32 guard_page_count = STACK_OVERFLOW_CHECK_GUARD_PAGE_COUNT; - - /* Check whether current thread is running wasm function */ - if (exec_env_tls && exec_env_tls->handle == os_self_thread() - && (jmpbuf_node = exec_env_tls->jmpbuf_stack_top)) { - /* Get mapped mem info of current instance */ - module_inst = (WASMModuleInstance *)exec_env_tls->module_inst; - /* Get the default memory instance */ - memory_inst = module_inst->default_memory; - if (memory_inst) { - mapped_mem_start_addr = (uint8 *)memory_inst->memory_data; - mapped_mem_end_addr = - (uint8 *)memory_inst->memory_data + 8 * (uint64)BH_GB; - } - - /* Get stack info of current thread */ - page_size = os_getpagesize(); - stack_min_addr = os_thread_get_stack_boundary(); - - if (memory_inst - && (mapped_mem_start_addr <= (uint8 *)sig_addr - && (uint8 *)sig_addr < mapped_mem_end_addr)) { - /* The address which causes segmentation fault is inside - the memory instance's guard regions */ - wasm_set_exception(module_inst, "out of bounds memory access"); - os_longjmp(jmpbuf_node->jmpbuf, 1); - } - else if (stack_min_addr - page_size <= (uint8 *)sig_addr - && (uint8 *)sig_addr - < stack_min_addr + page_size * guard_page_count) { - /* The address which causes segmentation fault is inside - native thread's guard page */ - wasm_set_exception(module_inst, "native stack overflow"); - os_longjmp(jmpbuf_node->jmpbuf, 1); - } - } -} -#else /* else of BH_PLATFORM_WINDOWS */ -LONG -wasm_exception_handler(WASMSignalInfo *sig_info) -{ - WASMExecEnv *exec_env_tls = sig_info->exec_env_tls; - EXCEPTION_POINTERS *exce_info = sig_info->exce_info; - PEXCEPTION_RECORD ExceptionRecord = exce_info->ExceptionRecord; - uint8 *sig_addr = (uint8 *)ExceptionRecord->ExceptionInformation[1]; - WASMModuleInstance *module_inst; - WASMMemoryInstance *memory_inst; - WASMJmpBuf *jmpbuf_node; - uint8 *mapped_mem_start_addr = NULL; - uint8 *mapped_mem_end_addr = NULL; - uint32 page_size = os_getpagesize(); - - if (exec_env_tls && exec_env_tls->handle == os_self_thread() - && (jmpbuf_node = exec_env_tls->jmpbuf_stack_top)) { - module_inst = (WASMModuleInstance *)exec_env_tls->module_inst; - if (ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) { - /* Get the default memory instance */ - memory_inst = module_inst->default_memory; - if (memory_inst) { - mapped_mem_start_addr = (uint8 *)memory_inst->memory_data; - mapped_mem_end_addr = - (uint8 *)memory_inst->memory_data + 8 * (uint64)BH_GB; - if (mapped_mem_start_addr <= (uint8 *)sig_addr - && (uint8 *)sig_addr < mapped_mem_end_addr) { - /* The address which causes segmentation fault is inside - the memory instance's guard regions. - Set exception and let the wasm func continue to run, when - the wasm func returns, the caller will check whether the - exception is thrown and return to runtime. */ - wasm_set_exception(module_inst, - "out of bounds memory access"); - /* Skip current instruction */ - return EXCEPTION_CONTINUE_SEARCH; - } - } - } - else if (ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW) { - /* Set stack overflow exception and let the wasm func continue - to run, when the wasm func returns, the caller will check - whether the exception is thrown and return to runtime, and - the damaged stack will be recovered by _resetstkoflw(). */ - wasm_set_exception(module_inst, "native stack overflow"); - return EXCEPTION_CONTINUE_SEARCH; - } - } - - os_printf("Unhandled exception thrown: exception code: 0x%lx, " - "exception address: %p, exception information: %p\n", - ExceptionRecord->ExceptionCode, ExceptionRecord->ExceptionAddress, - sig_addr); - return EXCEPTION_CONTINUE_SEARCH; -} -#endif /* end of BH_PLATFORM_WINDOWS */ - static void call_wasm_with_hw_bound_check(WASMModuleInstance *module_inst, WASMExecEnv *exec_env, @@ -2011,15 +2333,19 @@ call_wasm_with_hw_bound_check(WASMModuleInstance *module_inst, WASMJmpBuf jmpbuf_node = { 0 }, *jmpbuf_node_pop; uint32 page_size = os_getpagesize(); uint32 guard_page_count = STACK_OVERFLOW_CHECK_GUARD_PAGE_COUNT; + WASMRuntimeFrame *prev_frame = wasm_exec_env_get_cur_frame(exec_env); + uint8 *prev_top = exec_env->wasm_stack.s.top; #ifdef BH_PLATFORM_WINDOWS - const char *exce; int result; + bool has_exception; + char exception[EXCEPTION_BUF_LEN]; #endif bool ret = true; /* Check native stack overflow firstly to ensure we have enough native stack to run the following codes before actually calling the aot function in invokeNative function. */ + RECORD_STACK_USAGE(exec_env, (uint8 *)&exec_env_tls); if ((uint8 *)&exec_env_tls < exec_env->native_stack_boundary + page_size * (guard_page_count + 1)) { wasm_set_exception(module_inst, "native stack overflow"); @@ -2045,14 +2371,14 @@ call_wasm_with_hw_bound_check(WASMModuleInstance *module_inst, #else __try { wasm_interp_call_wasm(module_inst, exec_env, function, argc, argv); - } __except (wasm_get_exception(module_inst) + } __except (wasm_copy_exception(module_inst, NULL) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { /* exception was thrown in wasm_exception_handler */ ret = false; } - if ((exce = wasm_get_exception(module_inst)) - && strstr(exce, "native stack overflow")) { + has_exception = wasm_copy_exception(module_inst, exception); + if (has_exception && strstr(exception, "native stack overflow")) { /* After a stack overflow, the stack was left in a damaged state, let the CRT repair it */ result = _resetstkoflw(); @@ -2065,13 +2391,18 @@ call_wasm_with_hw_bound_check(WASMModuleInstance *module_inst, ret = false; } - if (wasm_get_exception(module_inst)) { + /* Note: can't check wasm_get_exception(module_inst) here, there may be + * exception which is not caught by hardware (e.g. uninitialized elements), + * then the stack-frame is already freed inside wasm_interp_call_wasm */ + if (!ret) { #if WASM_ENABLE_DUMP_CALL_STACK != 0 if (wasm_interp_create_call_stack(exec_env)) { wasm_interp_dump_call_stack(exec_env, true, NULL, 0); } #endif - wasm_interp_restore_wasm_frame(exec_env); + /* Restore operand frames */ + wasm_exec_env_set_cur_frame(exec_env, prev_frame); + exec_env->wasm_stack.s.top = prev_top; } jmpbuf_node_pop = wasm_exec_env_pop_jmpbuf(exec_env); @@ -2101,77 +2432,7 @@ wasm_call_function(WASMExecEnv *exec_env, WASMFunctionInstance *function, wasm_exec_env_set_thread_info(exec_env); interp_call_wasm(module_inst, exec_env, function, argc, argv); - (void)clear_wasi_proc_exit_exception(module_inst); - return !wasm_get_exception(module_inst) ? true : false; -} - -bool -wasm_create_exec_env_and_call_function(WASMModuleInstance *module_inst, - WASMFunctionInstance *func, - unsigned argc, uint32 argv[]) -{ - WASMExecEnv *exec_env = NULL, *existing_exec_env = NULL; - bool ret; - -#if defined(OS_ENABLE_HW_BOUND_CHECK) - existing_exec_env = exec_env = wasm_runtime_get_exec_env_tls(); -#elif WASM_ENABLE_THREAD_MGR != 0 - existing_exec_env = exec_env = - wasm_clusters_search_exec_env((WASMModuleInstanceCommon *)module_inst); -#endif - - if (!existing_exec_env) { - if (!(exec_env = - wasm_exec_env_create((WASMModuleInstanceCommon *)module_inst, - module_inst->default_wasm_stack_size))) { - wasm_set_exception(module_inst, "allocate memory failed"); - return false; - } - } - - ret = wasm_call_function(exec_env, func, argc, argv); - - /* don't destroy the exec_env if it isn't created in this function */ - if (!existing_exec_env) - wasm_exec_env_destroy(exec_env); - - return ret; -} - -bool -wasm_create_exec_env_singleton(WASMModuleInstance *module_inst) -{ - WASMExecEnv *exec_env = NULL; - - if (module_inst->exec_env_singleton) { - return true; - } - - exec_env = wasm_exec_env_create((WASMModuleInstanceCommon *)module_inst, - module_inst->default_wasm_stack_size); - if (exec_env) - module_inst->exec_env_singleton = exec_env; - - return exec_env ? true : false; -} - -void -wasm_set_exception(WASMModuleInstance *module_inst, const char *exception) -{ - if (exception) - snprintf(module_inst->cur_exception, sizeof(module_inst->cur_exception), - "Exception: %s", exception); - else - module_inst->cur_exception[0] = '\0'; -} - -const char * -wasm_get_exception(WASMModuleInstance *module_inst) -{ - if (module_inst->cur_exception[0] == '\0') - return NULL; - else - return module_inst->cur_exception; + return !wasm_copy_exception(module_inst, NULL); } #if WASM_ENABLE_PERF_PROFILING != 0 @@ -2184,8 +2445,8 @@ wasm_dump_perf_profiling(const WASMModuleInstance *module_inst) uint32 i, j; os_printf("Performance profiler data:\n"); - for (i = 0; i < module_inst->function_count; i++) { - func_inst = module_inst->functions + i; + for (i = 0; i < module_inst->e->function_count; i++) { + func_inst = module_inst->e->functions + i; if (func_inst->is_import_func) { func_name = func_inst->u.func_import->field_name; } @@ -2209,22 +2470,23 @@ wasm_dump_perf_profiling(const WASMModuleInstance *module_inst) os_printf(" func %s, execution time: %.3f ms, execution count: %d " "times\n", func_name, - module_inst->functions[i].total_exec_time / 1000.0f, - module_inst->functions[i].total_exec_cnt); + module_inst->e->functions[i].total_exec_time / 1000.0f, + module_inst->e->functions[i].total_exec_cnt); else os_printf(" func %d, execution time: %.3f ms, execution count: %d " "times\n", - i, module_inst->functions[i].total_exec_time / 1000.0f, - module_inst->functions[i].total_exec_cnt); + i, module_inst->e->functions[i].total_exec_time / 1000.0f, + module_inst->e->functions[i].total_exec_cnt); } } #endif uint32 -wasm_module_malloc(WASMModuleInstance *module_inst, uint32 size, - void **p_native_addr) +wasm_module_malloc_internal(WASMModuleInstance *module_inst, + WASMExecEnv *exec_env, uint32 size, + void **p_native_addr) { - WASMMemoryInstance *memory = module_inst->default_memory; + WASMMemoryInstance *memory = wasm_get_default_memory(module_inst); uint8 *addr = NULL; uint32 offset = 0; @@ -2236,15 +2498,15 @@ wasm_module_malloc(WASMModuleInstance *module_inst, uint32 size, if (memory->heap_handle) { addr = mem_allocator_malloc(memory->heap_handle, size); } - else if (module_inst->malloc_function && module_inst->free_function) { - if (!execute_malloc_function(module_inst, module_inst->malloc_function, - module_inst->retain_function, size, - &offset)) { + else if (module_inst->e->malloc_function && module_inst->e->free_function) { + if (!execute_malloc_function( + module_inst, exec_env, module_inst->e->malloc_function, + module_inst->e->retain_function, size, &offset)) { return 0; } /* If we use app's malloc function, the default memory may be changed while memory growing */ - memory = module_inst->default_memory; + memory = wasm_get_default_memory(module_inst); addr = offset ? memory->memory_data + offset : NULL; } @@ -2266,10 +2528,11 @@ wasm_module_malloc(WASMModuleInstance *module_inst, uint32 size, } uint32 -wasm_module_realloc(WASMModuleInstance *module_inst, uint32 ptr, uint32 size, - void **p_native_addr) +wasm_module_realloc_internal(WASMModuleInstance *module_inst, + WASMExecEnv *exec_env, uint32 ptr, uint32 size, + void **p_native_addr) { - WASMMemoryInstance *memory = module_inst->default_memory; + WASMMemoryInstance *memory = wasm_get_default_memory(module_inst); uint8 *addr = NULL; if (!memory) { @@ -2283,6 +2546,7 @@ wasm_module_realloc(WASMModuleInstance *module_inst, uint32 ptr, uint32 size, } /* Only support realloc in WAMR's app heap */ + (void)exec_env; if (!addr) { if (memory->heap_handle @@ -2301,10 +2565,11 @@ wasm_module_realloc(WASMModuleInstance *module_inst, uint32 ptr, uint32 size, } void -wasm_module_free(WASMModuleInstance *module_inst, uint32 ptr) +wasm_module_free_internal(WASMModuleInstance *module_inst, + WASMExecEnv *exec_env, uint32 ptr) { if (ptr) { - WASMMemoryInstance *memory = module_inst->default_memory; + WASMMemoryInstance *memory = wasm_get_default_memory(module_inst); uint8 *addr; if (!memory) { @@ -2317,14 +2582,36 @@ wasm_module_free(WASMModuleInstance *module_inst, uint32 ptr) && addr < memory->heap_data_end) { mem_allocator_free(memory->heap_handle, addr); } - else if (module_inst->malloc_function && module_inst->free_function - && memory->memory_data <= addr + else if (module_inst->e->malloc_function + && module_inst->e->free_function && memory->memory_data <= addr && addr < memory->memory_data_end) { - execute_free_function(module_inst, module_inst->free_function, ptr); + execute_free_function(module_inst, exec_env, + module_inst->e->free_function, ptr); } } } +uint32 +wasm_module_malloc(WASMModuleInstance *module_inst, uint32 size, + void **p_native_addr) +{ + return wasm_module_malloc_internal(module_inst, NULL, size, p_native_addr); +} + +uint32 +wasm_module_realloc(WASMModuleInstance *module_inst, uint32 ptr, uint32 size, + void **p_native_addr) +{ + return wasm_module_realloc_internal(module_inst, NULL, ptr, size, + p_native_addr); +} + +void +wasm_module_free(WASMModuleInstance *module_inst, uint32 ptr) +{ + wasm_module_free_internal(module_inst, NULL, ptr); +} + uint32 wasm_module_dup_data(WASMModuleInstance *module_inst, const char *src, uint32 size) @@ -2333,420 +2620,98 @@ wasm_module_dup_data(WASMModuleInstance *module_inst, const char *src, uint32 buffer_offset = wasm_module_malloc(module_inst, size, (void **)&buffer); if (buffer_offset != 0) { - buffer = wasm_addr_app_to_native(module_inst, buffer_offset); + buffer = wasm_runtime_addr_app_to_native( + (WASMModuleInstanceCommon *)module_inst, buffer_offset); bh_memcpy_s(buffer, size, src, size); } return buffer_offset; } +#if WASM_ENABLE_REF_TYPES != 0 bool -wasm_validate_app_addr(WASMModuleInstance *module_inst, uint32 app_offset, - uint32 size) +wasm_enlarge_table(WASMModuleInstance *module_inst, uint32 table_idx, + uint32 inc_size, uint32 init_val) { - WASMMemoryInstance *memory = module_inst->default_memory; - uint32 memory_data_size; + uint32 total_size, *new_table_data_start, i; + WASMTableInstance *table_inst; - if (!memory) { - goto fail; + if (!inc_size) { + return true; } - memory_data_size = memory->num_bytes_per_page * memory->cur_page_count; - - /* integer overflow check */ - if (app_offset > UINT32_MAX - size) { - goto fail; + bh_assert(table_idx < module_inst->table_count); + table_inst = wasm_get_table_inst(module_inst, table_idx); + if (!table_inst) { + return false; } - if (app_offset + size <= memory_data_size) { - return true; + if (inc_size > UINT32_MAX - table_inst->cur_size) { + return false; } -fail: - wasm_set_exception(module_inst, "out of bounds memory access"); - return false; -} - -bool -wasm_validate_native_addr(WASMModuleInstance *module_inst, void *native_ptr, - uint32 size) -{ - WASMMemoryInstance *memory = module_inst->default_memory; - uint8 *addr = (uint8 *)native_ptr; - if (!memory) { - goto fail; + total_size = table_inst->cur_size + inc_size; + if (total_size > table_inst->max_size) { + return false; } - /* integer overflow check */ - if ((uintptr_t)addr > UINTPTR_MAX - size) { - goto fail; + /* fill in */ + new_table_data_start = table_inst->elems + table_inst->cur_size; + for (i = 0; i < inc_size; ++i) { + new_table_data_start[i] = init_val; } - if (memory->memory_data <= addr && addr + size <= memory->memory_data_end) { - return true; - } -fail: - wasm_set_exception(module_inst, "out of bounds memory access"); - return false; + table_inst->cur_size = total_size; + return true; } +#endif /* WASM_ENABLE_REF_TYPES != 0 */ -void * -wasm_addr_app_to_native(WASMModuleInstance *module_inst, uint32 app_offset) +static bool +call_indirect(WASMExecEnv *exec_env, uint32 tbl_idx, uint32 elem_idx, + uint32 argc, uint32 argv[], bool check_type_idx, uint32 type_idx) { - WASMMemoryInstance *memory = module_inst->default_memory; - uint8 *addr; - - if (!memory) - return NULL; + WASMModuleInstance *module_inst = NULL; + WASMTableInstance *table_inst = NULL; + uint32 func_idx = 0; + WASMFunctionInstance *func_inst = NULL; - addr = memory->memory_data + app_offset; + module_inst = (WASMModuleInstance *)exec_env->module_inst; + bh_assert(module_inst); - if (memory->memory_data <= addr && addr < memory->memory_data_end) - return addr; - return NULL; -} + table_inst = module_inst->tables[tbl_idx]; + if (!table_inst) { + wasm_set_exception(module_inst, "unknown table"); + goto got_exception; + } -uint32 -wasm_addr_native_to_app(WASMModuleInstance *module_inst, void *native_ptr) -{ - WASMMemoryInstance *memory = module_inst->default_memory; - uint8 *addr = (uint8 *)native_ptr; + if (elem_idx >= table_inst->cur_size) { + wasm_set_exception(module_inst, "undefined element"); + goto got_exception; + } - if (!memory) - return 0; + func_idx = table_inst->elems[elem_idx]; + if (func_idx == NULL_REF) { + wasm_set_exception(module_inst, "uninitialized element"); + goto got_exception; + } - if (memory->memory_data <= addr && addr < memory->memory_data_end) - return (uint32)(addr - memory->memory_data); - return 0; -} + /** + * we insist to call functions owned by the module itself + **/ + if (func_idx >= module_inst->e->function_count) { + wasm_set_exception(module_inst, "unknown function"); + goto got_exception; + } -bool -wasm_get_app_addr_range(WASMModuleInstance *module_inst, uint32 app_offset, - uint32 *p_app_start_offset, uint32 *p_app_end_offset) -{ - WASMMemoryInstance *memory = module_inst->default_memory; - uint32 memory_data_size; + func_inst = module_inst->e->functions + func_idx; - if (!memory) - return false; + if (check_type_idx) { + WASMType *cur_type = module_inst->module->types[type_idx]; + WASMType *cur_func_type; - memory_data_size = memory->num_bytes_per_page * memory->cur_page_count; - - if (app_offset < memory_data_size) { - if (p_app_start_offset) - *p_app_start_offset = 0; - if (p_app_end_offset) - *p_app_end_offset = memory_data_size; - return true; - } - return false; -} - -bool -wasm_get_native_addr_range(WASMModuleInstance *module_inst, uint8 *native_ptr, - uint8 **p_native_start_addr, - uint8 **p_native_end_addr) -{ - WASMMemoryInstance *memory = module_inst->default_memory; - uint8 *addr = (uint8 *)native_ptr; - - if (!memory) - return false; - - if (memory->memory_data <= addr && addr < memory->memory_data_end) { - if (p_native_start_addr) - *p_native_start_addr = memory->memory_data; - if (p_native_end_addr) - *p_native_end_addr = memory->memory_data_end; - return true; - } - return false; -} - -#ifndef OS_ENABLE_HW_BOUND_CHECK -bool -wasm_enlarge_memory(WASMModuleInstance *module, uint32 inc_page_count) -{ - WASMMemoryInstance *memory = module->default_memory; - uint8 *memory_data_old, *memory_data_new, *heap_data_old; - uint32 num_bytes_per_page, heap_size, total_size_old; - uint32 cur_page_count, max_page_count, total_page_count; - uint64 total_size_new; - bool ret = true; - - if (!memory) - return false; - - heap_data_old = memory->heap_data; - heap_size = (uint32)(memory->heap_data_end - memory->heap_data); - - memory_data_old = memory->memory_data; - total_size_old = memory->memory_data_size; - - num_bytes_per_page = memory->num_bytes_per_page; - cur_page_count = memory->cur_page_count; - max_page_count = memory->max_page_count; - total_page_count = inc_page_count + cur_page_count; - total_size_new = num_bytes_per_page * (uint64)total_page_count; - - if (inc_page_count <= 0) - /* No need to enlarge memory */ - return true; - - if (total_page_count < cur_page_count /* integer overflow */ - || total_page_count > max_page_count) { - return false; - } - - bh_assert(total_size_new <= 4 * (uint64)BH_GB); - if (total_size_new > UINT32_MAX) { - /* Resize to 1 page with size 4G-1 */ - num_bytes_per_page = UINT32_MAX; - total_page_count = max_page_count = 1; - total_size_new = UINT32_MAX; - } - -#if WASM_ENABLE_SHARED_MEMORY != 0 - if (memory->is_shared) { - memory->num_bytes_per_page = num_bytes_per_page; - memory->cur_page_count = total_page_count; - memory->max_page_count = max_page_count; - /* No need to update memory->memory_data_size as it is - initialized with the maximum memory data size for - shared memory */ - return true; - } -#endif - - if (heap_size > 0) { - if (mem_allocator_is_heap_corrupted(memory->heap_handle)) { - wasm_runtime_show_app_heap_corrupted_prompt(); - return false; - } - } - - if (!(memory_data_new = - wasm_runtime_realloc(memory_data_old, (uint32)total_size_new))) { - if (!(memory_data_new = wasm_runtime_malloc((uint32)total_size_new))) { - return false; - } - if (memory_data_old) { - bh_memcpy_s(memory_data_new, (uint32)total_size_new, - memory_data_old, total_size_old); - wasm_runtime_free(memory_data_old); - } - } - - memset(memory_data_new + total_size_old, 0, - (uint32)total_size_new - total_size_old); - - if (heap_size > 0) { - if (mem_allocator_migrate(memory->heap_handle, - (char *)heap_data_old - + (memory_data_new - memory_data_old), - heap_size) - != 0) { - /* Don't return here as memory->memory_data is obsolete and - must be updated to be correctly used later. */ - ret = false; - } - } - - memory->heap_data = memory_data_new + (heap_data_old - memory_data_old); - memory->heap_data_end = memory->heap_data + heap_size; - - memory->num_bytes_per_page = num_bytes_per_page; - memory->cur_page_count = total_page_count; - memory->max_page_count = max_page_count; - memory->memory_data_size = (uint32)total_size_new; - - memory->memory_data = memory_data_new; - memory->memory_data_end = memory_data_new + (uint32)total_size_new; - -#if WASM_ENABLE_FAST_JIT != 0 -#if UINTPTR_MAX == UINT64_MAX - memory->mem_bound_check_1byte = total_size_new - 1; - memory->mem_bound_check_2bytes = total_size_new - 2; - memory->mem_bound_check_4bytes = total_size_new - 4; - memory->mem_bound_check_8bytes = total_size_new - 8; - memory->mem_bound_check_16bytes = total_size_new - 16; -#else - memory->mem_bound_check_1byte = (uint32)total_size_new - 1; - memory->mem_bound_check_2bytes = (uint32)total_size_new - 2; - memory->mem_bound_check_4bytes = (uint32)total_size_new - 4; - memory->mem_bound_check_8bytes = (uint32)total_size_new - 8; - memory->mem_bound_check_16bytes = (uint32)total_size_new - 16; -#endif -#endif - - return ret; -} -#else -bool -wasm_enlarge_memory(WASMModuleInstance *module, uint32 inc_page_count) -{ - WASMMemoryInstance *memory = module->default_memory; - uint32 num_bytes_per_page, total_size_old; - uint32 cur_page_count, max_page_count, total_page_count; - uint64 total_size_new; - - if (!memory) - return false; - - num_bytes_per_page = memory->num_bytes_per_page; - cur_page_count = memory->cur_page_count; - max_page_count = memory->max_page_count; - total_size_old = num_bytes_per_page * cur_page_count; - total_page_count = inc_page_count + cur_page_count; - total_size_new = num_bytes_per_page * (uint64)total_page_count; - - if (inc_page_count <= 0) - /* No need to enlarge memory */ - return true; - - if (total_page_count < cur_page_count /* integer overflow */ - || total_page_count > max_page_count) { - return false; - } - - bh_assert(total_size_new <= 4 * (uint64)BH_GB); - if (total_size_new > UINT32_MAX) { - /* Resize to 1 page with size 4G-1 */ - num_bytes_per_page = UINT32_MAX; - total_page_count = max_page_count = 1; - total_size_new = UINT32_MAX; - } - -#ifdef BH_PLATFORM_WINDOWS - if (!os_mem_commit(memory->memory_data_end, - (uint32)total_size_new - total_size_old, - MMAP_PROT_READ | MMAP_PROT_WRITE)) { - return false; - } -#endif - - if (os_mprotect(memory->memory_data_end, - (uint32)total_size_new - total_size_old, - MMAP_PROT_READ | MMAP_PROT_WRITE) - != 0) { -#ifdef BH_PLATFORM_WINDOWS - os_mem_decommit(memory->memory_data_end, - (uint32)total_size_new - total_size_old); -#endif - return false; - } - - /* The increased pages are filled with zero by the OS when os_mmap, - no need to memset it again here */ - - memory->num_bytes_per_page = num_bytes_per_page; - memory->cur_page_count = total_page_count; - memory->max_page_count = max_page_count; - memory->memory_data_size = (uint32)total_size_new; - memory->memory_data_end = memory->memory_data + (uint32)total_size_new; - -#if WASM_ENABLE_FAST_JIT != 0 - memory->mem_bound_check_1byte = total_size_new - 1; - memory->mem_bound_check_2bytes = total_size_new - 2; - memory->mem_bound_check_4bytes = total_size_new - 4; - memory->mem_bound_check_8bytes = total_size_new - 8; - memory->mem_bound_check_16bytes = total_size_new - 16; -#endif - - return true; -} -#endif /* end of OS_ENABLE_HW_BOUND_CHECK */ - -#if WASM_ENABLE_REF_TYPES != 0 -bool -wasm_enlarge_table(WASMModuleInstance *module_inst, uint32 table_idx, - uint32 inc_entries, uint32 init_val) -{ - uint32 entry_count, *new_table_data_start, i; - WASMTableInstance *table_inst; - - if (!inc_entries) { - return true; - } - - bh_assert(table_idx < module_inst->table_count); - table_inst = wasm_get_table_inst(module_inst, table_idx); - if (!table_inst) { - return false; - } - - if (inc_entries > UINT32_MAX - table_inst->cur_size) { - return false; - } - - entry_count = table_inst->cur_size + inc_entries; - if (entry_count > table_inst->max_size) { - return false; - } - - /* fill in */ - new_table_data_start = - (uint32 *)((uint8 *)table_inst + offsetof(WASMTableInstance, base_addr)) - + table_inst->cur_size; - for (i = 0; i < inc_entries; ++i) { - new_table_data_start[i] = init_val; - } - - table_inst->cur_size = entry_count; - return true; -} -#endif /* WASM_ENABLE_REF_TYPES != 0 */ - -static bool -call_indirect(WASMExecEnv *exec_env, uint32 tbl_idx, uint32 elem_idx, - uint32 argc, uint32 argv[], bool check_type_idx, uint32 type_idx) -{ - WASMModuleInstance *module_inst = NULL; - WASMTableInstance *table_inst = NULL; - uint32 func_idx = 0; - WASMFunctionInstance *func_inst = NULL; - - module_inst = (WASMModuleInstance *)exec_env->module_inst; - bh_assert(module_inst); - - table_inst = module_inst->tables[tbl_idx]; - if (!table_inst) { - wasm_set_exception(module_inst, "unknown table"); - goto got_exception; - } - - if (elem_idx >= table_inst->cur_size) { - wasm_set_exception(module_inst, "undefined element"); - goto got_exception; - } - - /** - * please be aware that table_inst->base_addr may point - * to another module's table - **/ - func_idx = ((uint32 *)table_inst->base_addr)[elem_idx]; - if (func_idx == NULL_REF) { - wasm_set_exception(module_inst, "uninitialized element"); - goto got_exception; - } - - /** - * we insist to call functions owned by the module itself - **/ - if (func_idx >= module_inst->function_count) { - wasm_set_exception(module_inst, "unknown function"); - goto got_exception; - } - - func_inst = module_inst->functions + func_idx; - - if (check_type_idx) { - WASMType *cur_type = module_inst->module->types[type_idx]; - WASMType *cur_func_type; - - if (func_inst->is_import_func) - cur_func_type = func_inst->u.func_import->func_type; - else - cur_func_type = func_inst->u.func->func_type; + if (func_inst->is_import_func) + cur_func_type = func_inst->u.func_import->func_type; + else + cur_func_type = func_inst->u.func->func_type; if (cur_type != cur_func_type) { wasm_set_exception(module_inst, "indirect call type mismatch"); @@ -2756,8 +2721,7 @@ call_indirect(WASMExecEnv *exec_env, uint32 tbl_idx, uint32 elem_idx, interp_call_wasm(module_inst, exec_env, func_inst, argc, argv); - (void)clear_wasi_proc_exit_exception(module_inst); - return !wasm_get_exception(module_inst) ? true : false; + return !wasm_copy_exception(module_inst, NULL); got_exception: return false; @@ -2770,16 +2734,6 @@ wasm_call_indirect(WASMExecEnv *exec_env, uint32 tbl_idx, uint32 elem_idx, return call_indirect(exec_env, tbl_idx, elem_idx, argc, argv, false, 0); } -#if WASM_ENABLE_FAST_JIT != 0 -bool -jit_call_indirect(WASMExecEnv *exec_env, uint32 tbl_idx, uint32 elem_idx, - uint32 type_idx, uint32 argc, uint32 argv[]) -{ - return call_indirect(exec_env, tbl_idx, elem_idx, argc, argv, true, - type_idx); -} -#endif - #if WASM_ENABLE_THREAD_MGR != 0 bool wasm_set_aux_stack(WASMExecEnv *exec_env, uint32 start_offset, uint32 size) @@ -2787,20 +2741,23 @@ wasm_set_aux_stack(WASMExecEnv *exec_env, uint32 start_offset, uint32 size) WASMModuleInstance *module_inst = (WASMModuleInstance *)exec_env->module_inst; uint32 stack_top_idx = module_inst->module->aux_stack_top_global_index; + +#if WASM_ENABLE_HEAP_AUX_STACK_ALLOCATION == 0 + /* Check the aux stack space */ uint32 data_end = module_inst->module->aux_data_end; uint32 stack_bottom = module_inst->module->aux_stack_bottom; bool is_stack_before_data = stack_bottom < data_end ? true : false; - - /* Check the aux stack space, currently we don't allocate space in heap */ if ((is_stack_before_data && (size > start_offset)) || ((!is_stack_before_data) && (start_offset - data_end < size))) return false; +#endif if (stack_top_idx != (uint32)-1) { /* The aux stack top is a wasm global, set the initial value for the global */ - uint8 *global_addr = module_inst->global_data - + module_inst->globals[stack_top_idx].data_offset; + uint8 *global_addr = + module_inst->global_data + + module_inst->e->globals[stack_top_idx].data_offset; *(int32 *)global_addr = start_offset; /* The aux stack boundary is a constant value, set the value to exec_env */ @@ -2917,48 +2874,34 @@ wasm_get_module_inst_mem_consumption(const WASMModuleInstance *module_inst, memset(mem_conspn, 0, sizeof(*mem_conspn)); - mem_conspn->module_inst_struct_size = sizeof(WASMModuleInstance); + mem_conspn->module_inst_struct_size = (uint8 *)module_inst->e + - (uint8 *)module_inst + + sizeof(WASMModuleInstanceExtra); mem_conspn->memories_size = sizeof(WASMMemoryInstance *) * module_inst->memory_count; for (i = 0; i < module_inst->memory_count; i++) { WASMMemoryInstance *memory = module_inst->memories[i]; - size = sizeof(WASMMemoryInstance) - + memory->num_bytes_per_page * memory->cur_page_count; + size = memory->num_bytes_per_page * memory->cur_page_count; mem_conspn->memories_size += size; mem_conspn->app_heap_size += memory->heap_data_end - memory->heap_data; /* size of app heap structure */ mem_conspn->memories_size += mem_allocator_get_heap_struct_size(); + /* Module instance structures have been appened into the end of + module instance */ } mem_conspn->tables_size = sizeof(WASMTableInstance *) * module_inst->table_count; - for (i = 0; i < module_inst->table_count; i++) { - WASMTableInstance *table = module_inst->tables[i]; -#if WASM_ENABLE_MULTI_MODULE != 0 - if (table->table_inst_linked) { - size = offsetof(WASMTableInstance, base_addr); - } - else -#endif - { - size = offsetof(WASMTableInstance, base_addr) - + sizeof(uint32) * table->cur_size; - } - mem_conspn->tables_size += size; - } + /* Table instance structures and table elements have been appened into + the end of module instance */ mem_conspn->functions_size = - sizeof(WASMFunctionInstance) * module_inst->function_count; + sizeof(WASMFunctionInstance) * module_inst->e->function_count; mem_conspn->globals_size = - sizeof(WASMGlobalInstance) * module_inst->global_count; - if (module_inst->global_count > 0) { - WASMGlobalInstance *global = - &module_inst->globals[module_inst->global_count - 1]; - mem_conspn->globals_size += - global->data_offset + wasm_value_type_size(global->type); - } + sizeof(WASMGlobalInstance) * module_inst->e->global_count; + /* Global data has been appened into the end of module instance */ mem_conspn->exports_size = sizeof(WASMExportFuncInstance) * module_inst->export_func_count; @@ -3016,7 +2959,7 @@ wasm_interp_create_call_stack(struct WASMExecEnv *exec_env) /* place holder, will overwrite it in wasm_c_api */ frame.instance = module_inst; frame.module_offset = 0; - frame.func_index = (uint32)(func_inst - module_inst->functions); + frame.func_index = (uint32)(func_inst - module_inst->e->functions); func_code_base = wasm_get_func_code(func_inst); if (!cur_frame->ip || !func_code_base) { @@ -3132,3 +3075,458 @@ wasm_interp_dump_call_stack(struct WASMExecEnv *exec_env, bool print, char *buf, return total_len + 1; } #endif /* end of WASM_ENABLE_DUMP_CALL_STACK */ + +#if WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0 \ + || WASM_ENABLE_WAMR_COMPILER != 0 +void +jit_set_exception_with_id(WASMModuleInstance *module_inst, uint32 id) +{ + if (id != EXCE_ALREADY_THROWN) + wasm_set_exception_with_id(module_inst, id); +#ifdef OS_ENABLE_HW_BOUND_CHECK + wasm_runtime_access_exce_check_guard_page(); +#endif +} + +bool +jit_check_app_addr_and_convert(WASMModuleInstance *module_inst, bool is_str, + uint32 app_buf_addr, uint32 app_buf_size, + void **p_native_addr) +{ + bool ret = wasm_check_app_addr_and_convert( + module_inst, is_str, app_buf_addr, app_buf_size, p_native_addr); + +#ifdef OS_ENABLE_HW_BOUND_CHECK + if (!ret) + wasm_runtime_access_exce_check_guard_page(); +#endif + + return ret; +} +#endif /* end of WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0 \ + || WASM_ENABLE_WAMR_COMPILER != 0 */ + +#if WASM_ENABLE_FAST_JIT != 0 +bool +fast_jit_call_indirect(WASMExecEnv *exec_env, uint32 tbl_idx, uint32 elem_idx, + uint32 type_idx, uint32 argc, uint32 *argv) +{ + return call_indirect(exec_env, tbl_idx, elem_idx, argc, argv, true, + type_idx); +} +#endif /* end of WASM_ENABLE_FAST_JIT != 0 */ + +#if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0 + +bool +llvm_jit_call_indirect(WASMExecEnv *exec_env, uint32 tbl_idx, uint32 elem_idx, + uint32 argc, uint32 *argv) +{ + bool ret; + +#if WASM_ENABLE_JIT != 0 + if (Wasm_Module_AoT == exec_env->module_inst->module_type) { + return aot_call_indirect(exec_env, tbl_idx, elem_idx, argc, argv); + } +#endif + + ret = call_indirect(exec_env, tbl_idx, elem_idx, argc, argv, false, 0); +#ifdef OS_ENABLE_HW_BOUND_CHECK + if (!ret) + wasm_runtime_access_exce_check_guard_page(); +#endif + return ret; +} + +bool +llvm_jit_invoke_native(WASMExecEnv *exec_env, uint32 func_idx, uint32 argc, + uint32 *argv) +{ + WASMModuleInstance *module_inst; + WASMModule *module; + uint32 *func_type_indexes; + uint32 func_type_idx; + WASMType *func_type; + void *func_ptr; + WASMFunctionImport *import_func; + CApiFuncImport *c_api_func_import = NULL; + const char *signature; + void *attachment; + char buf[96]; + bool ret = false; + +#if WASM_ENABLE_JIT != 0 + if (Wasm_Module_AoT == exec_env->module_inst->module_type) { + return aot_invoke_native(exec_env, func_idx, argc, argv); + } +#endif + + module_inst = (WASMModuleInstance *)wasm_runtime_get_module_inst(exec_env); + module = module_inst->module; + func_type_indexes = module_inst->func_type_indexes; + func_type_idx = func_type_indexes[func_idx]; + func_type = module->types[func_type_idx]; + func_ptr = module_inst->func_ptrs[func_idx]; + + bh_assert(func_idx < module->import_function_count); + + import_func = &module->import_functions[func_idx].u.function; + if (import_func->call_conv_wasm_c_api) { + if (module_inst->e->c_api_func_imports) { + c_api_func_import = module_inst->e->c_api_func_imports + func_idx; + func_ptr = c_api_func_import->func_ptr_linked; + } + else { + c_api_func_import = NULL; + func_ptr = NULL; + } + } + + if (!func_ptr) { + snprintf(buf, sizeof(buf), + "failed to call unlinked import function (%s, %s)", + import_func->module_name, import_func->field_name); + wasm_set_exception(module_inst, buf); + goto fail; + } + + attachment = import_func->attachment; + if (import_func->call_conv_wasm_c_api) { + ret = wasm_runtime_invoke_c_api_native( + (WASMModuleInstanceCommon *)module_inst, func_ptr, func_type, argc, + argv, c_api_func_import->with_env_arg, c_api_func_import->env_arg); + } + else if (!import_func->call_conv_raw) { + signature = import_func->signature; + ret = + wasm_runtime_invoke_native(exec_env, func_ptr, func_type, signature, + attachment, argv, argc, argv); + } + else { + signature = import_func->signature; + ret = wasm_runtime_invoke_native_raw(exec_env, func_ptr, func_type, + signature, attachment, argv, argc, + argv); + } + +fail: +#ifdef OS_ENABLE_HW_BOUND_CHECK + if (!ret) + wasm_runtime_access_exce_check_guard_page(); +#endif + return ret; +} + +#if WASM_ENABLE_BULK_MEMORY != 0 +bool +llvm_jit_memory_init(WASMModuleInstance *module_inst, uint32 seg_index, + uint32 offset, uint32 len, uint32 dst) +{ + WASMMemoryInstance *memory_inst; + WASMModule *module; + uint8 *data = NULL; + uint8 *maddr; + uint64 seg_len = 0; + +#if WASM_ENABLE_JIT != 0 + if (Wasm_Module_AoT == module_inst->module_type) { + return aot_memory_init(module_inst, seg_index, offset, len, dst); + } +#endif + + memory_inst = wasm_get_default_memory(module_inst); + module = module_inst->module; + seg_len = module->data_segments[seg_index]->data_length; + data = module->data_segments[seg_index]->data; + + if (!wasm_runtime_validate_app_addr((WASMModuleInstanceCommon *)module_inst, + dst, len)) + return false; + + if ((uint64)offset + (uint64)len > seg_len) { + wasm_set_exception(module_inst, "out of bounds memory access"); + return false; + } + + maddr = wasm_runtime_addr_app_to_native( + (WASMModuleInstanceCommon *)module_inst, dst); + + bh_memcpy_s(maddr, memory_inst->memory_data_size - dst, data + offset, len); + return true; +} + +bool +llvm_jit_data_drop(WASMModuleInstance *module_inst, uint32 seg_index) +{ +#if WASM_ENABLE_JIT != 0 + if (Wasm_Module_AoT == module_inst->module_type) { + return aot_data_drop(module_inst, seg_index); + } +#endif + + module_inst->module->data_segments[seg_index]->data_length = 0; + /* Currently we can't free the dropped data segment + as they are stored in wasm bytecode */ + return true; +} +#endif /* end of WASM_ENABLE_BULK_MEMORY != 0 */ + +#if WASM_ENABLE_REF_TYPES != 0 +void +llvm_jit_drop_table_seg(WASMModuleInstance *module_inst, uint32 tbl_seg_idx) +{ + WASMTableSeg *tbl_segs; + +#if WASM_ENABLE_JIT != 0 + if (Wasm_Module_AoT == module_inst->module_type) { + return aot_drop_table_seg(module_inst, tbl_seg_idx); + } +#endif + + tbl_segs = module_inst->module->table_segments; + tbl_segs[tbl_seg_idx].is_dropped = true; +} + +void +llvm_jit_table_init(WASMModuleInstance *module_inst, uint32 tbl_idx, + uint32 tbl_seg_idx, uint32 length, uint32 src_offset, + uint32 dst_offset) +{ + WASMTableInstance *tbl_inst; + WASMTableSeg *tbl_seg; + +#if WASM_ENABLE_JIT != 0 + if (Wasm_Module_AoT == module_inst->module_type) { + return aot_table_init(module_inst, tbl_idx, tbl_seg_idx, length, + src_offset, dst_offset); + } +#endif + + tbl_inst = wasm_get_table_inst(module_inst, tbl_idx); + tbl_seg = module_inst->module->table_segments + tbl_seg_idx; + + bh_assert(tbl_inst); + bh_assert(tbl_seg); + + if (!length) { + 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); + return; + } + + if (tbl_seg->is_dropped) { + jit_set_exception_with_id(module_inst, EXCE_OUT_OF_BOUNDS_TABLE_ACCESS); + return; + } + + if (!wasm_elem_is_passive(tbl_seg->mode)) { + jit_set_exception_with_id(module_inst, EXCE_OUT_OF_BOUNDS_TABLE_ACCESS); + return; + } + + bh_memcpy_s((uint8 *)tbl_inst + offsetof(WASMTableInstance, elems) + + dst_offset * sizeof(uint32), + (uint32)sizeof(uint32) * (tbl_inst->cur_size - dst_offset), + tbl_seg->func_indexes + src_offset, + (uint32)(length * sizeof(uint32))); +} + +void +llvm_jit_table_copy(WASMModuleInstance *module_inst, uint32 src_tbl_idx, + uint32 dst_tbl_idx, uint32 length, uint32 src_offset, + uint32 dst_offset) +{ + WASMTableInstance *src_tbl_inst; + WASMTableInstance *dst_tbl_inst; + +#if WASM_ENABLE_JIT != 0 + if (Wasm_Module_AoT == module_inst->module_type) { + aot_table_copy(module_inst, src_tbl_idx, dst_tbl_idx, length, + src_offset, dst_offset); + return; + } +#endif + + src_tbl_inst = wasm_get_table_inst(module_inst, src_tbl_idx); + dst_tbl_inst = wasm_get_table_inst(module_inst, dst_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) { + jit_set_exception_with_id(module_inst, EXCE_OUT_OF_BOUNDS_TABLE_ACCESS); + return; + } + + /* if src_offset >= dst_offset, copy from front to back */ + /* if src_offset < dst_offset, copy from back to front */ + /* merge all together */ + bh_memmove_s((uint8 *)dst_tbl_inst + offsetof(WASMTableInstance, elems) + + sizeof(uint32) * dst_offset, + (uint32)sizeof(uint32) * (dst_tbl_inst->cur_size - dst_offset), + (uint8 *)src_tbl_inst + offsetof(WASMTableInstance, elems) + + sizeof(uint32) * src_offset, + (uint32)sizeof(uint32) * length); +} + +void +llvm_jit_table_fill(WASMModuleInstance *module_inst, uint32 tbl_idx, + uint32 length, uint32 val, uint32 data_offset) +{ + WASMTableInstance *tbl_inst; + +#if WASM_ENABLE_JIT != 0 + if (Wasm_Module_AoT == module_inst->module_type) { + aot_table_fill(module_inst, tbl_idx, length, val, data_offset); + return; + } +#endif + + tbl_inst = wasm_get_table_inst(module_inst, tbl_idx); + bh_assert(tbl_inst); + + if (data_offset + length > tbl_inst->cur_size) { + jit_set_exception_with_id(module_inst, EXCE_OUT_OF_BOUNDS_TABLE_ACCESS); + return; + } + + for (; length != 0; data_offset++, length--) { + tbl_inst->elems[data_offset] = val; + } +} + +uint32 +llvm_jit_table_grow(WASMModuleInstance *module_inst, uint32 tbl_idx, + uint32 inc_size, uint32 init_val) +{ + WASMTableInstance *tbl_inst; + uint32 i, orig_size, total_size; + +#if WASM_ENABLE_JIT != 0 + if (Wasm_Module_AoT == module_inst->module_type) { + return aot_table_grow(module_inst, tbl_idx, inc_size, init_val); + } +#endif + + tbl_inst = wasm_get_table_inst(module_inst, tbl_idx); + if (!tbl_inst) { + return (uint32)-1; + } + + orig_size = tbl_inst->cur_size; + + if (!inc_size) { + return orig_size; + } + + if (tbl_inst->cur_size > UINT32_MAX - inc_size) { /* integer overflow */ + return (uint32)-1; + } + + total_size = tbl_inst->cur_size + inc_size; + if (total_size > tbl_inst->max_size) { + return (uint32)-1; + } + + /* fill in */ + for (i = 0; i < inc_size; ++i) { + tbl_inst->elems[tbl_inst->cur_size + i] = init_val; + } + + tbl_inst->cur_size = total_size; + return orig_size; +} +#endif /* end of WASM_ENABLE_REF_TYPES != 0 */ + +#if WASM_ENABLE_DUMP_CALL_STACK != 0 || WASM_ENABLE_PERF_PROFILING != 0 +bool +llvm_jit_alloc_frame(WASMExecEnv *exec_env, uint32 func_index) +{ + WASMModuleInstance *module_inst; + WASMInterpFrame *frame; + uint32 size; + +#if WASM_ENABLE_JIT != 0 + if (Wasm_Module_AoT == exec_env->module_inst->module_type) { + return aot_alloc_frame(exec_env, func_index); + } +#endif + + module_inst = (WASMModuleInstance *)exec_env->module_inst; + size = wasm_interp_interp_frame_size(0); + + frame = wasm_exec_env_alloc_wasm_frame(exec_env, size); + if (!frame) { + wasm_set_exception(module_inst, "wasm operand stack overflow"); + return false; + } + + frame->function = module_inst->e->functions + func_index; + frame->ip = NULL; + frame->sp = frame->lp; +#if WASM_ENABLE_PERF_PROFILING != 0 + frame->time_started = os_time_get_boot_microsecond(); +#endif + frame->prev_frame = wasm_exec_env_get_cur_frame(exec_env); + wasm_exec_env_set_cur_frame(exec_env, frame); + + return true; +} + +void +llvm_jit_free_frame(WASMExecEnv *exec_env) +{ + WASMInterpFrame *frame; + WASMInterpFrame *prev_frame; + +#if WASM_ENABLE_JIT != 0 + if (Wasm_Module_AoT == exec_env->module_inst->module_type) { + aot_free_frame(exec_env); + return; + } +#endif + + frame = wasm_exec_env_get_cur_frame(exec_env); + prev_frame = frame->prev_frame; + +#if WASM_ENABLE_PERF_PROFILING != 0 + if (frame->function) { + frame->function->total_exec_time += + os_time_get_boot_microsecond() - frame->time_started; + frame->function->total_exec_cnt++; + } +#endif + wasm_exec_env_free_wasm_frame(exec_env, frame); + wasm_exec_env_set_cur_frame(exec_env, prev_frame); +} +#endif /* end of WASM_ENABLE_DUMP_CALL_STACK != 0 \ + || WASM_ENABLE_PERF_PROFILING != 0 */ + +#endif /* end of WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0 */ + +#if WASM_ENABLE_LIBC_WASI != 0 && WASM_ENABLE_MULTI_MODULE != 0 +void +wasm_propagate_wasi_args(WASMModule *module) +{ + if (!module->import_count) + return; + + bh_assert(&module->import_module_list_head); + + WASMRegisteredModule *node = + bh_list_first_elem(&module->import_module_list_head); + while (node) { + WASIArguments *wasi_args_impt_mod = + &((WASMModule *)(node->module))->wasi_args; + bh_assert(wasi_args_impt_mod); + + bh_memcpy_s(wasi_args_impt_mod, sizeof(WASIArguments), + &module->wasi_args, sizeof(WASIArguments)); + node = bh_list_elem_next(node); + } +} +#endif diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm_runtime.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm_runtime.h new file mode 100644 index 00000000000..15169433ed8 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/interpreter/wasm_runtime.h @@ -0,0 +1,668 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef _WASM_RUNTIME_H +#define _WASM_RUNTIME_H + +#include "wasm.h" +#include "bh_hashmap.h" +#include "../common/wasm_runtime_common.h" +#include "../common/wasm_exec_env.h" + +#if WASM_ENABLE_WASI_NN != 0 +#include "../libraries/wasi-nn/src/wasi_nn_private.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#define EXCEPTION_BUF_LEN 128 + +typedef struct WASMModuleInstance WASMModuleInstance; +typedef struct WASMFunctionInstance WASMFunctionInstance; +typedef struct WASMMemoryInstance WASMMemoryInstance; +typedef struct WASMTableInstance WASMTableInstance; +typedef struct WASMGlobalInstance WASMGlobalInstance; + +/** + * When LLVM JIT, WAMR compiler or AOT is enabled, we should ensure that + * some offsets of the same field in the interpreter module instance and + * aot module instance are the same, so that the LLVM JITed/AOTed code + * can smoothly access the interpreter module instance. + * Same for the memory instance and table instance. + * We use the macro DefPointer to define some related pointer fields. + */ +#if (WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0 \ + || WASM_ENABLE_AOT != 0) \ + && UINTPTR_MAX == UINT32_MAX +/* Add u32 padding if LLVM JIT, WAMR compiler or AOT is enabled on + 32-bit platform */ +#define DefPointer(type, field) \ + type field; \ + uint32 field##_padding +#else +#define DefPointer(type, field) type field +#endif + +typedef enum WASMExceptionID { + EXCE_UNREACHABLE = 0, + EXCE_OUT_OF_MEMORY, + EXCE_OUT_OF_BOUNDS_MEMORY_ACCESS, + EXCE_INTEGER_OVERFLOW, + EXCE_INTEGER_DIVIDE_BY_ZERO, + EXCE_INVALID_CONVERSION_TO_INTEGER, + EXCE_INVALID_FUNCTION_TYPE_INDEX, + EXCE_INVALID_FUNCTION_INDEX, + EXCE_UNDEFINED_ELEMENT, + EXCE_UNINITIALIZED_ELEMENT, + EXCE_CALL_UNLINKED_IMPORT_FUNC, + EXCE_NATIVE_STACK_OVERFLOW, + EXCE_UNALIGNED_ATOMIC, + EXCE_AUX_STACK_OVERFLOW, + EXCE_AUX_STACK_UNDERFLOW, + EXCE_OUT_OF_BOUNDS_TABLE_ACCESS, + EXCE_OPERAND_STACK_OVERFLOW, + EXCE_FAILED_TO_COMPILE_FAST_JIT_FUNC, + EXCE_ALREADY_THROWN, + EXCE_NUM, +} WASMExceptionID; + +typedef union { + uint64 u64; + uint32 u32[2]; +} MemBound; + +struct WASMMemoryInstance { + /* Module type */ + uint32 module_type; + /* Shared memory flag */ + bool is_shared; + + /* Number bytes per page */ + uint32 num_bytes_per_page; + /* Current page count */ + uint32 cur_page_count; + /* Maximum page count */ + uint32 max_page_count; + /* Memory data size */ + uint32 memory_data_size; + /** + * Memory data begin address, Note: + * the app-heap might be inserted in to the linear memory, + * when memory is re-allocated, the heap data and memory data + * must be copied to new memory also + */ + DefPointer(uint8 *, memory_data); + /* Memory data end address */ + DefPointer(uint8 *, memory_data_end); + + /* Heap data base address */ + DefPointer(uint8 *, heap_data); + /* Heap data end address */ + DefPointer(uint8 *, heap_data_end); + /* The heap created */ + DefPointer(void *, heap_handle); + +#if WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0 \ + || WASM_ENABLE_WAMR_COMPILER != 0 || WASM_ENABLE_AOT != 0 + MemBound mem_bound_check_1byte; + MemBound mem_bound_check_2bytes; + MemBound mem_bound_check_4bytes; + MemBound mem_bound_check_8bytes; + MemBound mem_bound_check_16bytes; +#endif +}; + +struct WASMTableInstance { + /* Current size */ + uint32 cur_size; + /* Maximum size */ + uint32 max_size; + /* Table elements */ + uint32 elems[1]; +}; + +struct WASMGlobalInstance { + /* value type, VALUE_TYPE_I32/I64/F32/F64 */ + uint8 type; + /* mutable or constant */ + bool is_mutable; + /* data offset to base_addr of WASMMemoryInstance */ + uint32 data_offset; + /* initial value */ + WASMValue initial_value; +#if WASM_ENABLE_MULTI_MODULE != 0 + /* just for import, keep the reference here */ + WASMModuleInstance *import_module_inst; + WASMGlobalInstance *import_global_inst; +#endif +}; + +struct WASMFunctionInstance { + /* whether it is import function or WASM function */ + bool is_import_func; + /* parameter count */ + uint16 param_count; + /* local variable count, 0 for import function */ + uint16 local_count; + /* cell num of parameters */ + uint16 param_cell_num; + /* cell num of return type */ + uint16 ret_cell_num; + /* cell num of local variables, 0 for import function */ + uint16 local_cell_num; +#if WASM_ENABLE_FAST_INTERP != 0 + /* cell num of consts */ + uint16 const_cell_num; +#endif + uint16 *local_offsets; + /* parameter types */ + uint8 *param_types; + /* local types, NULL for import function */ + uint8 *local_types; + union { + WASMFunctionImport *func_import; + WASMFunction *func; + } u; +#if WASM_ENABLE_MULTI_MODULE != 0 + WASMModuleInstance *import_module_inst; + WASMFunctionInstance *import_func_inst; +#endif +#if WASM_ENABLE_PERF_PROFILING != 0 + /* total execution time */ + uint64 total_exec_time; + /* total execution count */ + uint32 total_exec_cnt; +#endif +}; + +typedef struct WASMExportFuncInstance { + char *name; + WASMFunctionInstance *function; +} WASMExportFuncInstance; + +typedef struct WASMExportGlobInstance { + char *name; + WASMGlobalInstance *global; +} WASMExportGlobInstance; + +typedef struct WASMExportTabInstance { + char *name; + WASMTableInstance *table; +} WASMExportTabInstance; + +typedef struct WASMExportMemInstance { + char *name; + WASMMemoryInstance *memory; +} WASMExportMemInstance; + +/* wasm-c-api import function info */ +typedef struct CApiFuncImport { + /* host func pointer after linked */ + void *func_ptr_linked; + /* whether the host func has env argument */ + bool with_env_arg; + /* the env argument of the host func */ + void *env_arg; +} CApiFuncImport; + +/* Extra info of WASM module instance for interpreter/jit mode */ +typedef struct WASMModuleInstanceExtra { + WASMGlobalInstance *globals; + WASMFunctionInstance *functions; + + uint32 global_count; + uint32 function_count; + + WASMFunctionInstance *start_function; + WASMFunctionInstance *malloc_function; + WASMFunctionInstance *free_function; + WASMFunctionInstance *retain_function; + + CApiFuncImport *c_api_func_imports; + RunningMode running_mode; + +#if WASM_ENABLE_MULTI_MODULE != 0 + bh_list sub_module_inst_list_head; + bh_list *sub_module_inst_list; + /* linked table instances of import table instances */ + WASMTableInstance **table_insts_linked; +#endif + +#if WASM_ENABLE_MEMORY_PROFILING != 0 + uint32 max_aux_stack_used; +#endif + +#if WASM_ENABLE_DEBUG_INTERP != 0 \ + || (WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_JIT != 0 \ + && WASM_ENABLE_LAZY_JIT != 0) + WASMModuleInstance *next; +#endif + +#if WASM_ENABLE_WASI_NN != 0 + WASINNContext *wasi_nn_ctx; +#endif +} WASMModuleInstanceExtra; + +struct AOTFuncPerfProfInfo; + +struct WASMModuleInstance { + /* Module instance type, for module instance loaded from + WASM bytecode binary, this field is Wasm_Module_Bytecode; + for module instance loaded from AOT file, this field is + Wasm_Module_AoT, and this structure should be treated as + AOTModuleInstance structure. */ + uint32 module_type; + + uint32 memory_count; + DefPointer(WASMMemoryInstance **, memories); + + /* global and table info */ + uint32 global_data_size; + uint32 table_count; + DefPointer(uint8 *, global_data); + /* For AOTModuleInstance, it denotes `AOTTableInstance *` */ + DefPointer(WASMTableInstance **, tables); + + /* import func ptrs + llvm jit func ptrs */ + DefPointer(void **, func_ptrs); + + /* function type indexes */ + DefPointer(uint32 *, func_type_indexes); + + uint32 export_func_count; + uint32 export_global_count; + uint32 export_memory_count; + uint32 export_table_count; + /* For AOTModuleInstance, it denotes `AOTFunctionInstance *` */ + DefPointer(WASMExportFuncInstance *, export_functions); + DefPointer(WASMExportGlobInstance *, export_globals); + DefPointer(WASMExportMemInstance *, export_memories); + DefPointer(WASMExportTabInstance *, export_tables); + + /* The exception buffer of wasm interpreter for current thread. */ + char cur_exception[EXCEPTION_BUF_LEN]; + + /* The WASM module or AOT module, for AOTModuleInstance, + it denotes `AOTModule *` */ + DefPointer(WASMModule *, module); + +#if WASM_ENABLE_LIBC_WASI + /* WASI context */ + DefPointer(WASIContext *, wasi_ctx); +#else + DefPointer(void *, wasi_ctx); +#endif + DefPointer(WASMExecEnv *, exec_env_singleton); + /* Array of function pointers to import functions, + not available in AOTModuleInstance */ + DefPointer(void **, import_func_ptrs); + /* Array of function pointers to fast jit functions, + not available in AOTModuleInstance: + Only when the multi-tier JIT macros are all enabled and the running + mode of current module instance is set to Mode_Fast_JIT, runtime + will allocate new memory for it, otherwise it always points to the + module->fast_jit_func_ptrs */ + DefPointer(void **, fast_jit_func_ptrs); + /* The custom data that can be set/get by wasm_{get|set}_custom_data */ + DefPointer(void *, custom_data); + /* Stack frames, used in call stack dump and perf profiling */ + DefPointer(Vector *, frames); + /* Function performance profiling info list, only available + in AOTModuleInstance */ + DefPointer(struct AOTFuncPerfProfInfo *, func_perf_profilings); + /* WASM/AOT module extra info, for AOTModuleInstance, + it denotes `AOTModuleInstanceExtra *` */ + DefPointer(WASMModuleInstanceExtra *, e); + + /* Default WASM operand stack size */ + uint32 default_wasm_stack_size; + uint32 reserved[3]; + + /* + * +------------------------------+ <-- memories + * | WASMMemoryInstance[mem_count], mem_count is always 1 for LLVM JIT/AOT + * +------------------------------+ <-- global_data + * | global data + * +------------------------------+ <-- tables + * | WASMTableInstance[table_count] + * +------------------------------+ <-- e + * | WASMModuleInstanceExtra + * +------------------------------+ + */ + union { + uint64 _make_it_8_byte_aligned_; + WASMMemoryInstance memory_instances[1]; + uint8 bytes[1]; + } global_table_data; +}; + +struct WASMInterpFrame; +typedef struct WASMInterpFrame WASMRuntimeFrame; + +#if WASM_ENABLE_MULTI_MODULE != 0 +typedef struct WASMSubModInstNode { + bh_list_link l; + /* point to a string pool */ + const char *module_name; + WASMModuleInstance *module_inst; +} WASMSubModInstNode; +#endif + +/** + * Return the code block of a function. + * + * @param func the WASM function instance + * + * @return the code block of the function + */ +static inline uint8 * +wasm_get_func_code(WASMFunctionInstance *func) +{ +#if WASM_ENABLE_FAST_INTERP == 0 + return func->is_import_func ? NULL : func->u.func->code; +#else + return func->is_import_func ? NULL : func->u.func->code_compiled; +#endif +} + +/** + * Return the code block end of a function. + * + * @param func the WASM function instance + * + * @return the code block end of the function + */ +static inline uint8 * +wasm_get_func_code_end(WASMFunctionInstance *func) +{ +#if WASM_ENABLE_FAST_INTERP == 0 + return func->is_import_func ? NULL + : func->u.func->code + func->u.func->code_size; +#else + return func->is_import_func + ? NULL + : func->u.func->code_compiled + func->u.func->code_compiled_size; +#endif +} + +WASMModule * +wasm_load(uint8 *buf, uint32 size, char *error_buf, uint32 error_buf_size); + +WASMModule * +wasm_load_from_sections(WASMSection *section_list, char *error_buf, + uint32 error_buf_size); + +void +wasm_unload(WASMModule *module); + +WASMModuleInstance * +wasm_instantiate(WASMModule *module, bool is_sub_inst, + WASMExecEnv *exec_env_main, uint32 stack_size, + uint32 heap_size, char *error_buf, uint32 error_buf_size); + +void +wasm_dump_perf_profiling(const WASMModuleInstance *module_inst); + +void +wasm_deinstantiate(WASMModuleInstance *module_inst, bool is_sub_inst); + +bool +wasm_set_running_mode(WASMModuleInstance *module_inst, + RunningMode running_mode); + +WASMFunctionInstance * +wasm_lookup_function(const WASMModuleInstance *module_inst, const char *name, + const char *signature); + +#if WASM_ENABLE_MULTI_MODULE != 0 +WASMGlobalInstance * +wasm_lookup_global(const WASMModuleInstance *module_inst, const char *name); + +WASMMemoryInstance * +wasm_lookup_memory(const WASMModuleInstance *module_inst, const char *name); + +WASMTableInstance * +wasm_lookup_table(const WASMModuleInstance *module_inst, const char *name); +#endif + +bool +wasm_call_function(WASMExecEnv *exec_env, WASMFunctionInstance *function, + unsigned argc, uint32 argv[]); + +void +wasm_set_exception(WASMModuleInstance *module, const char *exception); + +void +wasm_set_exception_with_id(WASMModuleInstance *module_inst, uint32 id); + +const char * +wasm_get_exception(WASMModuleInstance *module); + +/** + * @brief Copy exception in buffer passed as parameter. Thread-safe version of + * `wasm_get_exception()` + * @note Buffer size must be no smaller than EXCEPTION_BUF_LEN + * @return true if exception found + */ +bool +wasm_copy_exception(WASMModuleInstance *module_inst, char *exception_buf); + +uint32 +wasm_module_malloc_internal(WASMModuleInstance *module_inst, + WASMExecEnv *exec_env, uint32 size, + void **p_native_addr); + +uint32 +wasm_module_realloc_internal(WASMModuleInstance *module_inst, + WASMExecEnv *exec_env, uint32 ptr, uint32 size, + void **p_native_addr); + +void +wasm_module_free_internal(WASMModuleInstance *module_inst, + WASMExecEnv *exec_env, uint32 ptr); + +uint32 +wasm_module_malloc(WASMModuleInstance *module_inst, uint32 size, + void **p_native_addr); + +uint32 +wasm_module_realloc(WASMModuleInstance *module_inst, uint32 ptr, uint32 size, + void **p_native_addr); + +void +wasm_module_free(WASMModuleInstance *module_inst, uint32 ptr); + +uint32 +wasm_module_dup_data(WASMModuleInstance *module_inst, const char *src, + uint32 size); + +/** + * Check whether the app address and the buf is inside the linear memory, + * and convert the app address into native address + */ +bool +wasm_check_app_addr_and_convert(WASMModuleInstance *module_inst, bool is_str, + uint32 app_buf_addr, uint32 app_buf_size, + void **p_native_addr); + +WASMMemoryInstance * +wasm_get_default_memory(WASMModuleInstance *module_inst); + +bool +wasm_enlarge_memory(WASMModuleInstance *module_inst, uint32 inc_page_count); + +bool +wasm_call_indirect(WASMExecEnv *exec_env, uint32 tbl_idx, uint32 elem_idx, + uint32 argc, uint32 argv[]); + +#if WASM_ENABLE_THREAD_MGR != 0 +bool +wasm_set_aux_stack(WASMExecEnv *exec_env, uint32 start_offset, uint32 size); + +bool +wasm_get_aux_stack(WASMExecEnv *exec_env, uint32 *start_offset, uint32 *size); +#endif + +void +wasm_get_module_mem_consumption(const WASMModule *module, + WASMModuleMemConsumption *mem_conspn); + +void +wasm_get_module_inst_mem_consumption(const WASMModuleInstance *module, + WASMModuleInstMemConsumption *mem_conspn); + +#if WASM_ENABLE_REF_TYPES != 0 +static inline bool +wasm_elem_is_active(uint32 mode) +{ + return (mode & 0x1) == 0x0; +} + +static inline bool +wasm_elem_is_passive(uint32 mode) +{ + return (mode & 0x1) == 0x1; +} + +static inline bool +wasm_elem_is_declarative(uint32 mode) +{ + return (mode & 0x3) == 0x3; +} + +bool +wasm_enlarge_table(WASMModuleInstance *module_inst, uint32 table_idx, + uint32 inc_entries, uint32 init_val); +#endif /* WASM_ENABLE_REF_TYPES != 0 */ + +static inline WASMTableInstance * +wasm_get_table_inst(const WASMModuleInstance *module_inst, uint32 tbl_idx) +{ + /* careful, it might be a table in another module */ + WASMTableInstance *tbl_inst = module_inst->tables[tbl_idx]; +#if WASM_ENABLE_MULTI_MODULE != 0 + if (tbl_idx < module_inst->module->import_table_count + && module_inst->e->table_insts_linked[tbl_idx]) { + tbl_inst = module_inst->e->table_insts_linked[tbl_idx]; + } +#endif + bh_assert(tbl_inst); + return tbl_inst; +} + +#if WASM_ENABLE_DUMP_CALL_STACK != 0 +bool +wasm_interp_create_call_stack(struct WASMExecEnv *exec_env); + +/** + * @brief Dump wasm call stack or get the size + * + * @param exec_env the execution environment + * @param print whether to print to stdout or not + * @param buf buffer to store the dumped content + * @param len length of the buffer + * + * @return when print is true, return the bytes printed out to stdout; when + * print is false and buf is NULL, return the size required to store the + * callstack content; when print is false and buf is not NULL, return the size + * dumped to the buffer, 0 means error and data in buf may be invalid + */ +uint32 +wasm_interp_dump_call_stack(struct WASMExecEnv *exec_env, bool print, char *buf, + uint32 len); +#endif + +const uint8 * +wasm_loader_get_custom_section(WASMModule *module, const char *name, + uint32 *len); + +#if WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0 \ + || WASM_ENABLE_WAMR_COMPILER != 0 +void +jit_set_exception_with_id(WASMModuleInstance *module_inst, uint32 id); + +/** + * Check whether the app address and the buf is inside the linear memory, + * and convert the app address into native address + */ +bool +jit_check_app_addr_and_convert(WASMModuleInstance *module_inst, bool is_str, + uint32 app_buf_addr, uint32 app_buf_size, + void **p_native_addr); +#endif /* end of WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0 \ + || WASM_ENABLE_WAMR_COMPILER != 0 */ + +#if WASM_ENABLE_FAST_JIT != 0 +bool +fast_jit_call_indirect(WASMExecEnv *exec_env, uint32 tbl_idx, uint32 elem_idx, + uint32 type_idx, uint32 argc, uint32 *argv); + +bool +fast_jit_invoke_native(WASMExecEnv *exec_env, uint32 func_idx, + struct WASMInterpFrame *prev_frame); +#endif + +#if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0 +bool +llvm_jit_call_indirect(WASMExecEnv *exec_env, uint32 tbl_idx, uint32 elem_idx, + uint32 argc, uint32 *argv); + +bool +llvm_jit_invoke_native(WASMExecEnv *exec_env, uint32 func_idx, uint32 argc, + uint32 *argv); + +#if WASM_ENABLE_BULK_MEMORY != 0 +bool +llvm_jit_memory_init(WASMModuleInstance *module_inst, uint32 seg_index, + uint32 offset, uint32 len, uint32 dst); + +bool +llvm_jit_data_drop(WASMModuleInstance *module_inst, uint32 seg_index); +#endif + +#if WASM_ENABLE_REF_TYPES != 0 +void +llvm_jit_drop_table_seg(WASMModuleInstance *module_inst, uint32 tbl_seg_idx); + +void +llvm_jit_table_init(WASMModuleInstance *module_inst, uint32 tbl_idx, + uint32 tbl_seg_idx, uint32 length, uint32 src_offset, + uint32 dst_offset); + +void +llvm_jit_table_copy(WASMModuleInstance *module_inst, uint32 src_tbl_idx, + uint32 dst_tbl_idx, uint32 length, uint32 src_offset, + uint32 dst_offset); + +void +llvm_jit_table_fill(WASMModuleInstance *module_inst, uint32 tbl_idx, + uint32 length, uint32 val, uint32 data_offset); + +uint32 +llvm_jit_table_grow(WASMModuleInstance *module_inst, uint32 tbl_idx, + uint32 inc_entries, uint32 init_val); +#endif + +#if WASM_ENABLE_DUMP_CALL_STACK != 0 || WASM_ENABLE_PERF_PROFILING != 0 +bool +llvm_jit_alloc_frame(WASMExecEnv *exec_env, uint32 func_index); + +void +llvm_jit_free_frame(WASMExecEnv *exec_env); +#endif +#endif /* end of WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0 */ + +#if WASM_ENABLE_LIBC_WASI != 0 && WASM_ENABLE_MULTI_MODULE != 0 +void +wasm_propagate_wasi_args(WASMModule *module); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* end of _WASM_RUNTIME_H */ diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/debug-engine/debug_engine.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/debug-engine/debug_engine.c similarity index 78% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/debug-engine/debug_engine.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/debug-engine/debug_engine.c index e62ba5a2ff2..1b3db1d4966 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/debug-engine/debug_engine.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/debug-engine/debug_engine.c @@ -36,6 +36,23 @@ on_thread_stop_event(WASMDebugInstance *debug_inst, WASMExecEnv *exec_env) os_mutex_unlock(&debug_inst->wait_lock); } +void +on_thread_exit_event(WASMDebugInstance *debug_inst, WASMExecEnv *exec_env) +{ + os_mutex_lock(&debug_inst->wait_lock); + + /* DBG_LAUNCHING: exit when debugger detached, + * DBG_ERROR: exit when debugger error */ + if (debug_inst->current_state != DBG_LAUNCHING + && debug_inst->current_state != DBG_ERROR) { + /* only when exit normally the debugger thread will participate in + * teardown phase */ + debug_inst->stopped_thread = exec_env; + } + + os_mutex_unlock(&debug_inst->wait_lock); +} + static WASMDebugEngine *g_debug_engine; static uint32 current_instance_id = 1; @@ -55,9 +72,21 @@ allocate_instance_id() } static bool -should_stop(WASMDebugControlThread *control_thread) +is_thread_running(WASMDebugControlThread *control_thread) +{ + return control_thread->status == RUNNING; +} + +static bool +is_thread_stopped(WASMDebugControlThread *control_thread) +{ + return control_thread->status == STOPPED; +} + +static bool +is_thread_detached(WASMDebugControlThread *control_thread) { - return control_thread->status != RUNNING; + return control_thread->status == DETACHED; } static void * @@ -109,72 +138,94 @@ control_thread_routine(void *arg) os_cond_signal(&debug_inst->wait_cond); os_mutex_unlock(&debug_inst->wait_lock); - /* wait lldb client to connect */ if (!wasm_gdbserver_listen(control_thread->server)) { - LOG_ERROR("Failed while connecting debugger\n"); - wasm_runtime_free(control_thread->server); - return NULL; + LOG_ERROR("Failed while listening for debugger\n"); + goto fail; } + /* outer infinite loop: try to connect with the debugger */ while (true) { - os_mutex_lock(&control_thread->wait_lock); - if (!should_stop(control_thread)) { - /* send thread stop reply */ - if (debug_inst->stopped_thread - && debug_inst->current_state == APP_RUNNING) { - uint32 status; - korp_tid tid; - - status = - (uint32) - debug_inst->stopped_thread->current_status->signal_flag; - tid = debug_inst->stopped_thread->handle; - - if (debug_inst->stopped_thread->current_status->running_status - == STATUS_EXIT) { - /* If the thread exits, report "W00" if it's the last thread - * in the cluster, otherwise ignore this event */ - status = 0; - - /* By design, all the other threads should have been stopped - * at this moment, so it is safe to access the - * exec_env_list.len without lock */ - if (debug_inst->cluster->exec_env_list.len != 1) { - debug_inst->stopped_thread = NULL; - /* The exiting thread may wait for the signal */ - os_cond_signal(&debug_inst->wait_cond); - os_mutex_unlock(&control_thread->wait_lock); - continue; + /* wait lldb client to connect */ + if (!wasm_gdbserver_accept(control_thread->server)) { + LOG_ERROR("Failed while accepting debugger connection\n"); + goto fail; + } + + control_thread->status = RUNNING; + /* when reattached, send signal */ + wasm_cluster_send_signal_all(debug_inst->cluster, WAMR_SIG_SINGSTEP); + + /* inner infinite loop: keep serving until detach */ + while (true) { + os_mutex_lock(&control_thread->wait_lock); + if (is_thread_running(control_thread)) { + /* send thread stop reply */ + if (debug_inst->stopped_thread + && debug_inst->current_state == APP_RUNNING) { + uint32 status; + korp_tid tid; + + status = (uint32)debug_inst->stopped_thread->current_status + ->signal_flag; + tid = debug_inst->stopped_thread->handle; + + if (debug_inst->stopped_thread->current_status + ->running_status + == STATUS_EXIT) { + /* If the thread exits, report "W00" if it's the last + * thread in the cluster, otherwise ignore this event */ + status = 0; + + /* By design, all the other threads should have been + * stopped at this moment, so it is safe to access the + * exec_env_list.len without lock */ + if (debug_inst->cluster->exec_env_list.len != 1) { + debug_inst->stopped_thread = NULL; + /* The exiting thread may wait for the signal */ + os_cond_signal(&debug_inst->wait_cond); + os_mutex_unlock(&control_thread->wait_lock); + continue; + } } - } - wasm_debug_instance_set_cur_thread( - debug_inst, debug_inst->stopped_thread->handle); + wasm_debug_instance_set_cur_thread( + debug_inst, debug_inst->stopped_thread->handle); - send_thread_stop_status(control_thread->server, status, tid); + send_thread_stop_status(control_thread->server, status, + tid); - debug_inst->current_state = APP_STOPPED; - debug_inst->stopped_thread = NULL; + debug_inst->current_state = APP_STOPPED; + debug_inst->stopped_thread = NULL; - if (status == 0) { - /* The exiting thread may wait for the signal */ - os_cond_signal(&debug_inst->wait_cond); + if (status == 0) { + /* The exiting thread may wait for the signal */ + os_cond_signal(&debug_inst->wait_cond); + } } - } - /* Processing incoming requests */ - if (!wasm_gdbserver_handle_packet(control_thread->server)) { - control_thread->status = STOPPED; + /* Processing incoming requests */ + if (!wasm_gdbserver_handle_packet(control_thread->server)) { + control_thread->status = STOPPED; + LOG_ERROR("An error occurs when handling a packet\n"); + os_mutex_unlock(&control_thread->wait_lock); + goto fail; + } + } + else if (is_thread_detached(control_thread)) { + os_mutex_unlock(&control_thread->wait_lock); + break; + } + else if (is_thread_stopped(control_thread)) { + os_mutex_unlock(&control_thread->wait_lock); + return NULL; } - } - else { os_mutex_unlock(&control_thread->wait_lock); - break; } - os_mutex_unlock(&control_thread->wait_lock); } - - LOG_VERBOSE("control thread of debug object [%p] stopped\n", debug_inst); +fail: + wasm_debug_instance_on_failure(debug_inst); + LOG_VERBOSE("control thread of debug object [%p] stopped with failure\n", + debug_inst); return NULL; } @@ -218,7 +269,10 @@ wasm_debug_control_thread_create(WASMDebugInstance *debug_instance, int32 port) bh_list_insert(&g_debug_engine->debug_instance_list, debug_instance); os_mutex_unlock(&g_debug_engine->instance_list_lock); - wasm_cluster_send_signal_all(debug_instance->cluster, WAMR_SIG_STOP); + /* If we set WAMR_SIG_STOP here, the VSCode debugger adaptor will raise an + * exception in the UI. We use WAMR_SIG_SINGSTEP to avoid this exception for + * better user experience */ + wasm_cluster_send_signal_all(debug_instance->cluster, WAMR_SIG_SINGSTEP); return control_thread; @@ -338,6 +392,8 @@ wasm_debug_instance_create(WASMCluster *cluster, int32 port) } bh_list_init(&instance->break_point_list); + bh_list_init(&instance->watch_point_list_read); + bh_list_init(&instance->watch_point_list_write); instance->cluster = cluster; exec_env = bh_list_first_elem(&cluster->exec_env_list); @@ -398,6 +454,23 @@ wasm_debug_instance_destroy_breakpoints(WASMDebugInstance *instance) } } +static void +wasm_debug_instance_destroy_watchpoints(WASMDebugInstance *instance, + bh_list *watchpoints) +{ + WASMDebugWatchPoint *watchpoint, *next; + + watchpoint = bh_list_first_elem(watchpoints); + while (watchpoint) { + next = bh_list_elem_next(watchpoint); + + bh_list_remove(watchpoints, watchpoint); + wasm_runtime_free(watchpoint); + + watchpoint = next; + } +} + void wasm_debug_instance_destroy(WASMCluster *cluster) { @@ -418,6 +491,10 @@ wasm_debug_instance_destroy(WASMCluster *cluster) /* destroy all breakpoints */ wasm_debug_instance_destroy_breakpoints(instance); + wasm_debug_instance_destroy_watchpoints( + instance, &instance->watch_point_list_read); + wasm_debug_instance_destroy_watchpoints( + instance, &instance->watch_point_list_write); os_mutex_destroy(&instance->wait_lock); os_cond_destroy(&instance->wait_cond); @@ -617,7 +694,7 @@ wasm_debug_instance_get_memregion(WASMDebugInstance *instance, uint64 addr) break; case WasmMemory: { - memory = module_inst->default_memory; + memory = wasm_get_default_memory(module_inst); if (memory) { num_bytes_per_page = memory->num_bytes_per_page; @@ -715,7 +792,7 @@ wasm_debug_instance_get_linear_mem(WASMDebugInstance *instance, uint64 offset, return false; module_inst = (WASMModuleInstance *)exec_env->module_inst; - memory = module_inst->default_memory; + memory = wasm_get_default_memory(module_inst); if (memory) { num_bytes_per_page = memory->num_bytes_per_page; linear_mem_size = num_bytes_per_page * memory->cur_page_count; @@ -748,7 +825,7 @@ wasm_debug_instance_set_linear_mem(WASMDebugInstance *instance, uint64 offset, return false; module_inst = (WASMModuleInstance *)exec_env->module_inst; - memory = module_inst->default_memory; + memory = wasm_get_default_memory(module_inst); if (memory) { num_bytes_per_page = memory->num_bytes_per_page; linear_mem_size = num_bytes_per_page * memory->cur_page_count; @@ -941,6 +1018,103 @@ wasm_debug_instance_remove_breakpoint(WASMDebugInstance *instance, uint64 addr, return true; } +static bool +add_watchpoint(bh_list *list, uint64 addr, uint64 length) +{ + WASMDebugWatchPoint *watchpoint; + if (!(watchpoint = wasm_runtime_malloc(sizeof(WASMDebugWatchPoint)))) { + LOG_ERROR("WASM Debug Engine error: failed to allocate memory for " + "watchpoint"); + return false; + } + memset(watchpoint, 0, sizeof(WASMDebugWatchPoint)); + watchpoint->addr = addr; + watchpoint->length = length; + bh_list_insert(list, watchpoint); + return true; +} + +static bool +remove_watchpoint(bh_list *list, uint64 addr, uint64 length) +{ + WASMDebugWatchPoint *watchpoint = bh_list_first_elem(list); + while (watchpoint) { + WASMDebugWatchPoint *next = bh_list_elem_next(watchpoint); + if (watchpoint->addr == addr && watchpoint->length == length) { + bh_list_remove(list, watchpoint); + wasm_runtime_free(watchpoint); + } + watchpoint = next; + } + return true; +} + +bool +wasm_debug_instance_watchpoint_write_add(WASMDebugInstance *instance, + uint64 addr, uint64 length) +{ + return add_watchpoint(&instance->watch_point_list_write, addr, length); +} + +bool +wasm_debug_instance_watchpoint_write_remove(WASMDebugInstance *instance, + uint64 addr, uint64 length) +{ + return remove_watchpoint(&instance->watch_point_list_write, addr, length); +} + +bool +wasm_debug_instance_watchpoint_read_add(WASMDebugInstance *instance, + uint64 addr, uint64 length) +{ + return add_watchpoint(&instance->watch_point_list_read, addr, length); +} + +bool +wasm_debug_instance_watchpoint_read_remove(WASMDebugInstance *instance, + uint64 addr, uint64 length) +{ + return remove_watchpoint(&instance->watch_point_list_read, addr, length); +} + +bool +wasm_debug_instance_on_failure(WASMDebugInstance *instance) +{ + WASMExecEnv *exec_env; + + if (!instance) + return false; + + os_mutex_lock(&instance->wait_lock); + exec_env = bh_list_first_elem(&instance->cluster->exec_env_list); + if (!exec_env) { + os_mutex_unlock(&instance->wait_lock); + return false; + } + + if (instance->stopped_thread == NULL + && instance->current_state == DBG_LAUNCHING) { + /* if fail in start stage: may need wait for main thread to notify it */ + os_cond_wait(&instance->wait_cond, &instance->wait_lock); + } + instance->current_state = DBG_ERROR; + instance->stopped_thread = NULL; + + /* terminate the wasm execution thread */ + while (exec_env) { + /* Resume all threads so they can receive the TERM signal */ + os_mutex_lock(&exec_env->wait_lock); + wasm_cluster_thread_send_signal(exec_env, WAMR_SIG_TERM); + exec_env->current_status->running_status = STATUS_RUNNING; + os_cond_signal(&exec_env->wait_cond); + os_mutex_unlock(&exec_env->wait_lock); + exec_env = bh_list_elem_next(exec_env); + } + os_mutex_unlock(&instance->wait_lock); + + return true; +} + bool wasm_debug_instance_continue(WASMDebugInstance *instance) { @@ -987,6 +1161,36 @@ wasm_debug_instance_interrupt_all_threads(WASMDebugInstance *instance) return true; } +bool +wasm_debug_instance_detach(WASMDebugInstance *instance) +{ + WASMExecEnv *exec_env; + + if (!instance) + return false; + + exec_env = bh_list_first_elem(&instance->cluster->exec_env_list); + if (!exec_env) + return false; + + wasm_gdbserver_detach(instance->control_thread->server); + + while (exec_env) { + if (instance->current_state == APP_STOPPED) { + /* Resume all threads since remote debugger detached*/ + wasm_cluster_thread_continue(exec_env); + } + exec_env = bh_list_elem_next(exec_env); + } + + /* relaunch, accept new debug connection */ + instance->current_state = DBG_LAUNCHING; + instance->control_thread->status = DETACHED; + instance->stopped_thread = NULL; + + return true; +} + bool wasm_debug_instance_kill(WASMDebugInstance *instance) { @@ -1134,10 +1338,10 @@ wasm_debug_instance_get_global(WASMDebugInstance *instance, int32 frame_index, module_inst = (WASMModuleInstance *)exec_env->module_inst; global_data = module_inst->global_data; - globals = module_inst->globals; + globals = module_inst->e->globals; if ((global_index < 0) - || ((uint32)global_index >= module_inst->global_count)) { + || ((uint32)global_index >= module_inst->e->global_count)) { return false; } global = globals + global_index; diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/debug-engine/debug_engine.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/debug-engine/debug_engine.cmake similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/debug-engine/debug_engine.cmake rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/debug-engine/debug_engine.cmake diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/debug-engine/debug_engine.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/debug-engine/debug_engine.h similarity index 85% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/debug-engine/debug_engine.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/debug-engine/debug_engine.h index 70901551e05..e12f827bde5 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/debug-engine/debug_engine.h +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/debug-engine/debug_engine.h @@ -12,6 +12,7 @@ typedef enum WASMDebugControlThreadStatus { RUNNING, + DETACHED, STOPPED, } WASMDebugControlThreadStatus; @@ -35,13 +36,20 @@ typedef struct WASMDebugBreakPoint { uint64 orignal_data; } WASMDebugBreakPoint; +typedef struct WASMDebugWatchPoint { + bh_list_link next; + uint64 addr; + uint64 length; +} WASMDebugWatchPoint; + typedef enum debug_state_t { /* Debugger state conversion sequence: * DBG_LAUNCHING ---> APP_STOPPED <---> APP_RUNNING */ DBG_LAUNCHING, APP_RUNNING, - APP_STOPPED + APP_STOPPED, + DBG_ERROR } debug_state_t; typedef struct WASMDebugExecutionMemory { @@ -54,6 +62,8 @@ struct WASMDebugInstance { struct WASMDebugInstance *next; WASMDebugControlThread *control_thread; bh_list break_point_list; + bh_list watch_point_list_read; + bh_list watch_point_list_write; WASMCluster *cluster; uint32 id; korp_tid current_tid; @@ -107,6 +117,9 @@ typedef enum WasmAddressType { void on_thread_stop_event(WASMDebugInstance *debug_inst, WASMExecEnv *exec_env); +void +on_thread_exit_event(WASMDebugInstance *debug_inst, WASMExecEnv *exec_env); + WASMDebugInstance * wasm_debug_instance_create(WASMCluster *cluster, int32 port); @@ -179,12 +192,34 @@ bool wasm_debug_instance_remove_breakpoint(WASMDebugInstance *instance, uint64 addr, uint64 length); +bool +wasm_debug_instance_watchpoint_write_add(WASMDebugInstance *instance, + uint64 addr, uint64 length); + +bool +wasm_debug_instance_watchpoint_write_remove(WASMDebugInstance *instance, + uint64 addr, uint64 length); + +bool +wasm_debug_instance_watchpoint_read_add(WASMDebugInstance *instance, + uint64 addr, uint64 length); + +bool +wasm_debug_instance_watchpoint_read_remove(WASMDebugInstance *instance, + uint64 addr, uint64 length); + +bool +wasm_debug_instance_on_failure(WASMDebugInstance *instance); + bool wasm_debug_instance_interrupt_all_threads(WASMDebugInstance *instance); bool wasm_debug_instance_continue(WASMDebugInstance *instance); +bool +wasm_debug_instance_detach(WASMDebugInstance *instance); + bool wasm_debug_instance_kill(WASMDebugInstance *instance); diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/debug-engine/gdbserver.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/debug-engine/gdbserver.c similarity index 91% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/debug-engine/gdbserver.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/debug-engine/gdbserver.c index e347cc34a17..fbd876ac330 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/debug-engine/gdbserver.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/debug-engine/gdbserver.c @@ -34,6 +34,7 @@ static const struct packet_handler_elem packet_handler_table[255] = { DEL_HANDLER('c', handle_continue_request), DEL_HANDLER('k', handle_kill_request), DEL_HANDLER('_', handle____request), + DEL_HANDLER('D', handle_detach_request), }; WASMGDBServer * @@ -89,7 +90,6 @@ wasm_create_gdbserver(const char *host, int32 *port) bool wasm_gdbserver_listen(WASMGDBServer *server) { - bh_socket_t sockt_fd = (bh_socket_t)-1; int32 ret; ret = os_socket_listen(server->listen_fd, 1); @@ -98,6 +98,23 @@ wasm_gdbserver_listen(WASMGDBServer *server) goto fail; } + LOG_VERBOSE("listen for gdb client"); + return true; + +fail: + os_socket_shutdown(server->listen_fd); + os_socket_close(server->listen_fd); + return false; +} + +bool +wasm_gdbserver_accept(WASMGDBServer *server) +{ + + bh_socket_t sockt_fd = (bh_socket_t)-1; + + LOG_VERBOSE("waiting for gdb client to connect..."); + os_socket_accept(server->listen_fd, &sockt_fd, NULL, NULL); if (sockt_fd < 0) { LOG_ERROR("wasm gdb server error: socket accept failed"); @@ -115,6 +132,15 @@ wasm_gdbserver_listen(WASMGDBServer *server) return false; } +void +wasm_gdbserver_detach(WASMGDBServer *server) +{ + if (server->socket_fd > 0) { + os_socket_shutdown(server->socket_fd); + os_socket_close(server->socket_fd); + } +} + void wasm_close_gdbserver(WASMGDBServer *server) { @@ -263,8 +289,9 @@ wasm_gdbserver_handle_packet(WASMGDBServer *server) n = os_socket_recv(server->socket_fd, buf, sizeof(buf)); if (n == 0) { - LOG_VERBOSE("Debugger disconnected"); - return false; + handle_detach_request(server, NULL); + LOG_VERBOSE("Debugger disconnected, waiting for debugger reconnection"); + return true; } else if (n < 0) { #if defined(BH_PLATFORM_WINDOWS) diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/debug-engine/gdbserver.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/debug-engine/gdbserver.h similarity index 93% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/debug-engine/gdbserver.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/debug-engine/gdbserver.h index 98ff834350b..9e279a2e62e 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/debug-engine/gdbserver.h +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/debug-engine/gdbserver.h @@ -56,6 +56,12 @@ wasm_create_gdbserver(const char *host, int32 *port); bool wasm_gdbserver_listen(WASMGDBServer *server); +bool +wasm_gdbserver_accept(WASMGDBServer *server); + +void +wasm_gdbserver_detach(WASMGDBServer *server); + void wasm_close_gdbserver(WASMGDBServer *server); diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/debug-engine/handler.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/debug-engine/handler.c similarity index 84% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/debug-engine/handler.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/debug-engine/handler.c index da07f80dac9..8d451b1a358 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/debug-engine/handler.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/debug-engine/handler.c @@ -358,6 +358,14 @@ handle_general_query(WASMGDBServer *server, char *payload) send_thread_stop_status(server, status, tid); } + + if (!strcmp(name, "WatchpointSupportInfo")) { + os_mutex_lock(&tmpbuf_lock); + // Any uint32 is OK for the watchpoint support + snprintf(tmpbuf, MAX_PACKET_SIZE, "num:32;"); + write_packet(server, tmpbuf); + os_mutex_unlock(&tmpbuf_lock); + } } void @@ -643,46 +651,125 @@ handle_get_write_memory(WASMGDBServer *server, char *payload) os_mutex_unlock(&tmpbuf_lock); } +void +handle_breakpoint_software_add(WASMGDBServer *server, uint64 addr, + size_t length) +{ + bool ret = wasm_debug_instance_add_breakpoint( + (WASMDebugInstance *)server->thread->debug_instance, addr, length); + write_packet(server, ret ? "OK" : "EO1"); +} + +void +handle_breakpoint_software_remove(WASMGDBServer *server, uint64 addr, + size_t length) +{ + bool ret = wasm_debug_instance_remove_breakpoint( + (WASMDebugInstance *)server->thread->debug_instance, addr, length); + write_packet(server, ret ? "OK" : "EO1"); +} + +void +handle_watchpoint_write_add(WASMGDBServer *server, uint64 addr, size_t length) +{ + bool ret = wasm_debug_instance_watchpoint_write_add( + (WASMDebugInstance *)server->thread->debug_instance, addr, length); + write_packet(server, ret ? "OK" : "EO1"); +} + +void +handle_watchpoint_write_remove(WASMGDBServer *server, uint64 addr, + size_t length) +{ + bool ret = wasm_debug_instance_watchpoint_write_remove( + (WASMDebugInstance *)server->thread->debug_instance, addr, length); + write_packet(server, ret ? "OK" : "EO1"); +} + +void +handle_watchpoint_read_add(WASMGDBServer *server, uint64 addr, size_t length) +{ + bool ret = wasm_debug_instance_watchpoint_read_add( + (WASMDebugInstance *)server->thread->debug_instance, addr, length); + write_packet(server, ret ? "OK" : "EO1"); +} + +void +handle_watchpoint_read_remove(WASMGDBServer *server, uint64 addr, size_t length) +{ + bool ret = wasm_debug_instance_watchpoint_read_remove( + (WASMDebugInstance *)server->thread->debug_instance, addr, length); + write_packet(server, ret ? "OK" : "EO1"); +} + void handle_add_break(WASMGDBServer *server, char *payload) { + int arg_c; size_t type, length; uint64 addr; - if (sscanf(payload, "%zx,%" SCNx64 ",%zx", &type, &addr, &length) == 3) { - if (type == eBreakpointSoftware) { - bool ret = wasm_debug_instance_add_breakpoint( - (WASMDebugInstance *)server->thread->debug_instance, addr, - length); - if (ret) - write_packet(server, "OK"); - else - write_packet(server, "E01"); - return; - } + if ((arg_c = sscanf(payload, "%zx,%" SCNx64 ",%zx", &type, &addr, &length)) + != 3) { + LOG_ERROR("Unsupported number of add break arguments %d", arg_c); + write_packet(server, ""); + return; + } + + switch (type) { + case eBreakpointSoftware: + handle_breakpoint_software_add(server, addr, length); + break; + case eWatchpointWrite: + handle_watchpoint_write_add(server, addr, length); + break; + case eWatchpointRead: + handle_watchpoint_read_add(server, addr, length); + break; + case eWatchpointReadWrite: + handle_watchpoint_write_add(server, addr, length); + handle_watchpoint_read_add(server, addr, length); + break; + default: + LOG_ERROR("Unsupported breakpoint type %zu", type); + write_packet(server, ""); + break; } - write_packet(server, ""); } void handle_remove_break(WASMGDBServer *server, char *payload) { + int arg_c; size_t type, length; uint64 addr; - if (sscanf(payload, "%zx,%" SCNx64 ",%zx", &type, &addr, &length) == 3) { - if (type == eBreakpointSoftware) { - bool ret = wasm_debug_instance_remove_breakpoint( - (WASMDebugInstance *)server->thread->debug_instance, addr, - length); - if (ret) - write_packet(server, "OK"); - else - write_packet(server, "E01"); - return; - } + if ((arg_c = sscanf(payload, "%zx,%" SCNx64 ",%zx", &type, &addr, &length)) + != 3) { + LOG_ERROR("Unsupported number of remove break arguments %d", arg_c); + write_packet(server, ""); + return; + } + + switch (type) { + case eBreakpointSoftware: + handle_breakpoint_software_remove(server, addr, length); + break; + case eWatchpointWrite: + handle_watchpoint_write_remove(server, addr, length); + break; + case eWatchpointRead: + handle_watchpoint_read_remove(server, addr, length); + break; + case eWatchpointReadWrite: + handle_watchpoint_write_remove(server, addr, length); + handle_watchpoint_read_remove(server, addr, length); + break; + default: + LOG_ERROR("Unsupported breakpoint type %zu", type); + write_packet(server, ""); + break; } - write_packet(server, ""); } void @@ -777,3 +864,13 @@ handle____request(WASMGDBServer *server, char *payload) handle_free(server, args); } } + +void +handle_detach_request(WASMGDBServer *server, char *payload) +{ + if (payload != NULL) { + write_packet(server, "OK"); + } + wasm_debug_instance_detach( + (WASMDebugInstance *)server->thread->debug_instance); +} diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/debug-engine/handler.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/debug-engine/handler.h similarity index 95% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/debug-engine/handler.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/debug-engine/handler.h index 47422fddb76..af2566da59d 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/debug-engine/handler.h +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/debug-engine/handler.h @@ -62,6 +62,9 @@ handle_kill_request(WASMGDBServer *server, char *payload); void handle____request(WASMGDBServer *server, char *payload); +void +handle_detach_request(WASMGDBServer *server, char *payload); + void send_thread_stop_status(WASMGDBServer *server, uint32 status, korp_tid tid); #endif diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/debug-engine/packets.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/debug-engine/packets.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/debug-engine/packets.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/debug-engine/packets.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/debug-engine/packets.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/debug-engine/packets.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/debug-engine/packets.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/debug-engine/packets.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/debug-engine/utils.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/debug-engine/utils.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/debug-engine/utils.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/debug-engine/utils.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/debug-engine/utils.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/debug-engine/utils.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/debug-engine/utils.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/debug-engine/utils.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/lib-pthread/SConscript b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-pthread/SConscript similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/lib-pthread/SConscript rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-pthread/SConscript diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/lib-pthread/lib_pthread.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-pthread/lib_pthread.cmake similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/lib-pthread/lib_pthread.cmake rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-pthread/lib_pthread.cmake diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c similarity index 98% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c index 2fb7033f36c..206479c2a24 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c @@ -46,10 +46,6 @@ wasm_runtime_addr_native_to_app(module_inst, ptr) /* clang-format on */ -extern bool -wasm_runtime_call_indirect(wasm_exec_env_t exec_env, uint32 element_indices, - uint32 argc, uint32 argv[]); - enum { T_THREAD, T_MUTEX, @@ -494,7 +490,6 @@ pthread_start_routine(void *arg) { wasm_exec_env_t exec_env = (wasm_exec_env_t)arg; wasm_exec_env_t parent_exec_env; - wasm_module_inst_t module_inst = get_module_inst(exec_env); ThreadRoutineArgs *routine_args = exec_env->thread_arg; ThreadInfoNode *info_node = routine_args->info_node; uint32 argv[1]; @@ -504,7 +499,6 @@ pthread_start_routine(void *arg) info_node->exec_env = exec_env; info_node->u.thread = exec_env->handle; if (!append_thread_info_node(info_node)) { - wasm_runtime_deinstantiate_internal(module_inst, true); delete_thread_info_node(info_node); os_cond_signal(&parent_exec_env->wait_cond); os_mutex_unlock(&parent_exec_env->wait_lock); @@ -520,16 +514,12 @@ pthread_start_routine(void *arg) if (!wasm_runtime_call_indirect(exec_env, routine_args->elem_index, 1, argv)) { - if (wasm_runtime_get_exception(module_inst)) - wasm_cluster_spread_exception(exec_env); + /* Exception has already been spread during throwing */ } /* destroy pthread key values */ call_key_destructor(exec_env); - /* routine exit, destroy instance */ - wasm_runtime_deinstantiate_internal(module_inst, true); - wasm_runtime_free(routine_args); /* if the thread is joinable, store the result in its info node, @@ -590,7 +580,7 @@ pthread_create_wrapper(wasm_exec_env_t exec_env, #endif if (!(new_module_inst = wasm_runtime_instantiate_internal( - module, true, stack_size, 0, NULL, 0))) + module, true, exec_env, stack_size, 0, NULL, 0))) return -1; /* Set custom_data to new module instance */ @@ -603,6 +593,9 @@ pthread_create_wrapper(wasm_exec_env_t exec_env, wasm_runtime_set_wasi_ctx(new_module_inst, wasi_ctx); #endif + if (!(wasm_cluster_dup_c_api_imports(new_module_inst, module_inst))) + goto fail; + if (!(info_node = wasm_runtime_malloc(sizeof(ThreadInfoNode)))) goto fail; @@ -623,8 +616,9 @@ pthread_create_wrapper(wasm_exec_env_t exec_env, routine_args->module_inst = new_module_inst; os_mutex_lock(&exec_env->wait_lock); - ret = wasm_cluster_create_thread( - exec_env, new_module_inst, pthread_start_routine, (void *)routine_args); + ret = + wasm_cluster_create_thread(exec_env, new_module_inst, true, + pthread_start_routine, (void *)routine_args); if (ret != 0) { os_mutex_unlock(&exec_env->wait_lock); goto fail; diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/lib-rats/lib_rats.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-rats/lib_rats.cmake similarity index 75% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/lib-rats/lib_rats.cmake rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-rats/lib_rats.cmake index 482fd95656d..b773c837e38 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/lib-rats/lib_rats.cmake +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-rats/lib_rats.cmake @@ -4,9 +4,19 @@ set (LIB_RATS_DIR ${CMAKE_CURRENT_LIST_DIR}) +if ("$ENV{SGX_SSL_DIR}" STREQUAL "") + set (SGX_SSL_DIR "/opt/intel/sgxssl") +else() + set (SGX_SSL_DIR $ENV{SGX_SSL_DIR}) +endif() + +if (NOT EXISTS ${SGX_SSL_DIR}) + message(FATAL_ERROR "Can not find SGX_SSL, please install it first") +endif() + add_definitions (-DWASM_ENABLE_LIB_RATS=1) -include_directories(${LIB_RATS_DIR}) +include_directories(${LIB_RATS_DIR} ${SGX_SSL_DIR}/include) include(FetchContent) diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-rats/lib_rats_common.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-rats/lib_rats_common.h new file mode 100644 index 00000000000..929e105f059 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-rats/lib_rats_common.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2022 Intel Corporation + * Copyright (c) 2020-2021 Alibaba Cloud + * + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef _RATS_WAMR_COMMON_H +#define _RATS_WAMR_COMMON_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define SGX_QUOTE_MAX_SIZE 8192 +#define SGX_USER_DATA_SIZE 64 +#define SGX_MEASUREMENT_SIZE 32 + +/* clang-format off */ +typedef struct rats_sgx_evidence { + uint8_t quote[SGX_QUOTE_MAX_SIZE]; /* The quote of the Enclave */ + uint32_t quote_size; /* The size of the quote */ + uint8_t user_data[SGX_USER_DATA_SIZE]; /* The custom data in the quote */ + uint32_t product_id; /* Product ID of the Enclave */ + uint8_t mr_enclave[SGX_MEASUREMENT_SIZE]; /* The MRENCLAVE of the Enclave */ + uint32_t security_version; /* Security Version of the Enclave */ + uint8_t mr_signer[SGX_MEASUREMENT_SIZE]; /* The MRSIGNER of the Enclave */ + uint64_t att_flags; /* Flags of the Enclave in attributes */ + uint64_t att_xfrm; /* XSAVE Feature Request Mask */ +} rats_sgx_evidence_t; +/* clang-format on */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-rats/lib_rats_wrapper.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-rats/lib_rats_wrapper.c new file mode 100644 index 00000000000..59d61f4c828 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-rats/lib_rats_wrapper.c @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2022 Intel Corporation + * Copyright (c) 2020-2021 Alibaba Cloud + * + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include +#include +#include +#include +#include + +#include "sgx_quote_3.h" +#include "wasm_export.h" +#include "bh_common.h" +#include "lib_rats_common.h" + +static int +librats_collect_wrapper(wasm_exec_env_t exec_env, char **evidence_json, + const char *buffer, uint32_t buffer_size) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasm_module_t module = wasm_runtime_get_module(module_inst); + char *wasm_module_hash = wasm_runtime_get_module_hash(module); + + char *json, *str_ret; + uint32_t str_ret_offset; + uint8_t final_hash[SHA256_DIGEST_LENGTH]; + + SHA256_CTX sha256; + SHA256_Init(&sha256); + SHA256_Update(&sha256, wasm_module_hash, SHA256_DIGEST_LENGTH); + if (buffer != NULL) + SHA256_Update(&sha256, buffer, buffer_size); + SHA256_Final(final_hash, &sha256); + + int ret_code = librats_collect_evidence_to_json(final_hash, &json); + if (ret_code != 0) { + return ret_code; + } + + uint32_t json_size = strlen(json) + 1; + str_ret_offset = module_malloc(json_size, (void **)&str_ret); + if (!str_ret_offset) { + free(json); + return (int)RATS_ATTESTER_ERR_NO_MEM; + } + bh_memcpy_s(str_ret, json_size, json, json_size); + *((int *)evidence_json) = str_ret_offset; + free(json); + + return 0; +} + +static int +librats_verify_wrapper(wasm_exec_env_t exec_env, const char *evidence_json, + uint32_t evidence_size, const uint8_t *hash, + uint32_t hash_size) +{ + return librats_verify_evidence_from_json(evidence_json, hash); +} + +static int +librats_parse_evidence_wrapper(wasm_exec_env_t exec_env, + const char *evidence_json, uint32_t json_size, + rats_sgx_evidence_t *evidence, + uint32_t evidence_size) +{ + attestation_evidence_t att_ev; + + if (get_evidence_from_json(evidence_json, &att_ev) != 0) { + return -1; + } + + // Only supports parsing sgx evidence currently + if (strcmp(att_ev.type, "sgx_ecdsa") != 0) { + return -1; + } + + sgx_quote3_t *quote_ptr = (sgx_quote3_t *)att_ev.ecdsa.quote; + bh_memcpy_s(evidence->quote, att_ev.ecdsa.quote_len, att_ev.ecdsa.quote, + att_ev.ecdsa.quote_len); + evidence->quote_size = att_ev.ecdsa.quote_len; + bh_memcpy_s(evidence->user_data, SGX_REPORT_DATA_SIZE, + quote_ptr->report_body.report_data.d, SGX_REPORT_DATA_SIZE); + bh_memcpy_s(evidence->mr_enclave, sizeof(sgx_measurement_t), + quote_ptr->report_body.mr_enclave.m, sizeof(sgx_measurement_t)); + bh_memcpy_s(evidence->mr_signer, sizeof(sgx_measurement_t), + quote_ptr->report_body.mr_signer.m, sizeof(sgx_measurement_t)); + evidence->product_id = quote_ptr->report_body.isv_prod_id; + evidence->security_version = quote_ptr->report_body.isv_svn; + evidence->att_flags = quote_ptr->report_body.attributes.flags; + evidence->att_xfrm = quote_ptr->report_body.attributes.flags; + + return 0; +} + +/* clang-format off */ +#define REG_NATIVE_FUNC(func_name, signature) \ + { #func_name, func_name##_wrapper, signature, NULL } +/* clang-format on */ + +static NativeSymbol native_symbols_lib_rats[] = { + REG_NATIVE_FUNC(librats_collect, "(**~)i"), + REG_NATIVE_FUNC(librats_verify, "(*~*~)i"), + REG_NATIVE_FUNC(librats_parse_evidence, "(*~*~)i") +}; + +uint32_t +get_lib_rats_export_apis(NativeSymbol **p_lib_rats_apis) +{ + *p_lib_rats_apis = native_symbols_lib_rats; + return sizeof(native_symbols_lib_rats) / sizeof(NativeSymbol); +} diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-rats/lib_rats_wrapper.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-rats/lib_rats_wrapper.h new file mode 100644 index 00000000000..e334983e9aa --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-rats/lib_rats_wrapper.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2022 Intel Corporation + * Copyright (c) 2020-2021 Alibaba Cloud + * + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef _RATS_WAMR_API_H +#define _RATS_WAMR_API_H + +#include +#include + +#include "lib_rats_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +int +librats_collect(char **evidence_json, const char *buffer, uint32_t buffer_size); + +int +librats_verify(const char *evidence_json, uint32_t evidence_size, + const uint8_t *hash, uint32_t hash_size); + +int +librats_parse_evidence(const char *evidence_json, uint32_t json_size, + rats_sgx_evidence_t *evidence, uint32_t evidence_size); + +#define librats_collect(evidence_json, buffer) \ + librats_collect(evidence_json, buffer, buffer ? strlen(buffer) + 1 : 0) + +#define librats_verify(evidence_json, hash) \ + librats_verify(evidence_json, \ + evidence_json ? strlen(evidence_json) + 1 : 0, hash, \ + hash ? strlen((const char *)hash) + 1 : 0) + +#define librats_parse_evidence(evidence_json, evidence) \ + librats_parse_evidence(evidence_json, \ + evidence_json ? strlen(evidence_json) + 1 : 0, \ + evidence, sizeof(rats_sgx_evidence_t)) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/lib-socket/inc/wasi_socket_ext.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-socket/inc/wasi_socket_ext.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/lib-socket/inc/wasi_socket_ext.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-socket/inc/wasi_socket_ext.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/lib-socket/lib_socket_wasi.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-socket/lib_socket_wasi.cmake similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/lib-socket/lib_socket_wasi.cmake rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-socket/lib_socket_wasi.cmake diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/lib-socket/src/wasi/wasi_socket_ext.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-socket/src/wasi/wasi_socket_ext.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/lib-socket/src/wasi/wasi_socket_ext.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-socket/src/wasi/wasi_socket_ext.c diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-socket/test/build.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-socket/test/build.sh new file mode 100755 index 00000000000..24f5ee67635 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-socket/test/build.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +# Copyright (C) 2023 Amazon.com Inc. or its affiliates. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +set -eo pipefail +CC="${CC:=/opt/wasi-sdk/bin/clang}" +files=("tcp_udp.c" "nslookup.c") + +for file in "${files[@]}" +do + echo $file + $CC \ + --target=wasm32-wasi-threads \ + -I../inc \ + ../src/wasi/wasi_socket_ext.c -pthread -ftls-model=local-exec \ + -Wl,--allow-undefined \ + -Wl,--strip-all,--no-entry \ + -Wl,--export=__heap_base \ + -Wl,--export=__data_end \ + -Wl,--shared-memory,--max-memory=10485760 \ + -Wl,--export=malloc \ + -Wl,--export=free \ + -o "${file%.*}.wasm" "$file" +done \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-socket/test/nslookup.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-socket/test/nslookup.c new file mode 100644 index 00000000000..37150f1eb7f --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-socket/test/nslookup.c @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2023 Amazon.com Inc. or its affiliates. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include +#include +#ifdef __wasi__ +#include +#include +#include +#include +#else +#include +#endif + +void +test_nslookup(int af) +{ + struct addrinfo *res; + int count = 0; + struct addrinfo hints; + char *url = "google-public-dns-a.google.com"; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = af; + hints.ai_socktype = SOCK_STREAM; + int ret = getaddrinfo(url, 0, &hints, &res); + assert(ret == 0); + struct addrinfo *address = res; + while (address) { + assert(address->ai_family == af); + assert(address->ai_socktype == SOCK_STREAM); + count++; + address = address->ai_next; + } + + assert(count > 0); + freeaddrinfo(res); +} + +int +main() +{ + test_nslookup(AF_INET); /* for ipv4 */ + test_nslookup(AF_INET6); /* for ipv6 */ + + return 0; +} diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-socket/test/tcp_udp.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-socket/test/tcp_udp.c new file mode 100644 index 00000000000..49231de8999 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-socket/test/tcp_udp.c @@ -0,0 +1,193 @@ +/* + * Copyright (C) 2023 Amazon.com Inc. or its affiliates. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ +#include +#include +#include +#ifdef __wasi__ +#include +#include +#include +#endif +#include +#include +#define SERVER_MSG "Message from server." +#define PORT 8989 +pthread_mutex_t mut; +pthread_cond_t cond; +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; + int sock; +}; + +struct thread_args { + int family; + int protocol; +}; + +struct socket_info +init_socket_addr(int family, int protocol) +{ + int sock = socket(family, protocol, 0); + assert(sock != -1); + + 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; + } + 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; +} + +void +assert_thread_args(struct thread_args *args) +{ + assert(args->family == AF_INET || args->family == AF_INET6); + assert(args->protocol == SOCK_STREAM || args->protocol == SOCK_DGRAM); +} + +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; + struct sockaddr_storage client_addr; + strcpy(buffer, SERVER_MSG); + + 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); + + (args->protocol == SOCK_STREAM) && listen(server_sock, 1); + pthread_mutex_lock(&mut); + server_init_complete = 1; + pthread_mutex_unlock(&mut); + pthread_cond_signal(&cond); + + addr_size = sizeof(client_addr); + if (args->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); + } + 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); + } + + return NULL; +} + +void * +client(void *arg) +{ + struct thread_args *args = (struct thread_args *)arg; + assert_thread_args(args); + + pthread_mutex_lock(&mut); + + while (server_init_complete == 0) { + pthread_cond_wait(&cond, &mut); + } + + 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(close(sock) == 0); + return NULL; +} + +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); + + 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); + 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 +main(int argc, char **argv) +{ + /* test tcp with ipv4 and ipv6 */ + test_protocol(AF_INET, SOCK_STREAM); + test_protocol(AF_INET6, SOCK_STREAM); + + /* test udp with ipv4 and ipv6 */ + test_protocol(AF_INET, SOCK_DGRAM); + test_protocol(AF_INET6, SOCK_DGRAM); + + return 0; +} \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/lib_wasi_threads.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/lib_wasi_threads.cmake new file mode 100644 index 00000000000..54d2ba902c7 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/lib_wasi_threads.cmake @@ -0,0 +1,12 @@ +# Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +set (LIB_WASI_THREADS_DIR ${CMAKE_CURRENT_LIST_DIR}) + +add_definitions (-DWASM_ENABLE_LIB_WASI_THREADS=1 -DWASM_ENABLE_HEAP_AUX_STACK_ALLOCATION=1) + +include_directories(${LIB_WASI_THREADS_DIR}) + +set (LIB_WASI_THREADS_SOURCE + ${LIB_WASI_THREADS_DIR}/lib_wasi_threads_wrapper.c + ${LIB_WASI_THREADS_DIR}/tid_allocator.c) \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/lib_wasi_threads_wrapper.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/lib_wasi_threads_wrapper.c new file mode 100644 index 00000000000..6b36c9073fb --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/lib_wasi_threads_wrapper.c @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "bh_log.h" +#include "thread_manager.h" +#include "tid_allocator.h" + +#if WASM_ENABLE_INTERP != 0 +#include "wasm_runtime.h" +#endif + +#if WASM_ENABLE_AOT != 0 +#include "aot_runtime.h" +#endif + +static const char *THREAD_START_FUNCTION = "wasi_thread_start"; +static korp_mutex thread_id_lock; +static TidAllocator tid_allocator; + +typedef struct { + /* app's entry function */ + wasm_function_inst_t start_func; + /* arg of the app's entry function */ + uint32 arg; + /* thread id passed to the app */ + int32 thread_id; +} ThreadStartArg; + +static int32 +allocate_thread_id() +{ + os_mutex_lock(&thread_id_lock); + int32 id = tid_allocator_get_tid(&tid_allocator); + os_mutex_unlock(&thread_id_lock); + + return id; +} + +void +deallocate_thread_id(int32 thread_id) +{ + os_mutex_lock(&thread_id_lock); + tid_allocator_release_tid(&tid_allocator, thread_id); + os_mutex_unlock(&thread_id_lock); +} + +static void * +thread_start(void *arg) +{ + wasm_exec_env_t exec_env = (wasm_exec_env_t)arg; + ThreadStartArg *thread_arg = exec_env->thread_arg; + uint32 argv[2]; + + wasm_exec_env_set_thread_info(exec_env); + argv[0] = thread_arg->thread_id; + argv[1] = thread_arg->arg; + + if (!wasm_runtime_call_wasm(exec_env, thread_arg->start_func, 2, argv)) { + /* Exception has already been spread during throwing */ + } + + // Routine exit + deallocate_thread_id(thread_arg->thread_id); + wasm_runtime_free(thread_arg); + exec_env->thread_arg = NULL; + + return NULL; +} + +static int32 +thread_spawn_wrapper(wasm_exec_env_t exec_env, uint32 start_arg) +{ + wasm_module_t module = wasm_exec_env_get_module(exec_env); + wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasm_module_inst_t new_module_inst = NULL; + ThreadStartArg *thread_start_arg = NULL; + wasm_function_inst_t start_func; + int32 thread_id; + uint32 stack_size = 8192; + int32 ret = -1; +#if WASM_ENABLE_LIBC_WASI != 0 + WASIContext *wasi_ctx; +#endif + + bh_assert(module); + bh_assert(module_inst); + + 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))) + return -1; + + wasm_runtime_set_custom_data_internal( + new_module_inst, wasm_runtime_get_custom_data(module_inst)); + + if (!(wasm_cluster_dup_c_api_imports(new_module_inst, module_inst))) + goto thread_preparation_fail; + +#if WASM_ENABLE_LIBC_WASI != 0 + wasi_ctx = wasm_runtime_get_wasi_ctx(module_inst); + if (wasi_ctx) + wasm_runtime_set_wasi_ctx(new_module_inst, wasi_ctx); +#endif + + start_func = wasm_runtime_lookup_function(new_module_inst, + THREAD_START_FUNCTION, NULL); + if (!start_func) { + LOG_ERROR("Failed to find thread start function %s", + THREAD_START_FUNCTION); + goto thread_preparation_fail; + } + + if (!(thread_start_arg = wasm_runtime_malloc(sizeof(ThreadStartArg)))) { + LOG_ERROR("Runtime args allocation failed"); + goto thread_preparation_fail; + } + + thread_start_arg->thread_id = thread_id = allocate_thread_id(); + if (thread_id < 0) { + LOG_ERROR("Failed to get thread identifier"); + goto thread_preparation_fail; + } + thread_start_arg->arg = start_arg; + thread_start_arg->start_func = start_func; + + ret = wasm_cluster_create_thread(exec_env, new_module_inst, false, + thread_start, thread_start_arg); + if (ret != 0) { + LOG_ERROR("Failed to spawn a new thread"); + goto thread_spawn_fail; + } + + return thread_id; + +thread_spawn_fail: + deallocate_thread_id(thread_id); + +thread_preparation_fail: + if (new_module_inst) + wasm_runtime_deinstantiate_internal(new_module_inst, true); + if (thread_start_arg) + wasm_runtime_free(thread_start_arg); + + return -1; +} + +/* clang-format off */ +#define REG_NATIVE_FUNC(name, func_name, signature) \ + { name, func_name##_wrapper, signature, NULL } +/* clang-format on */ + +static NativeSymbol native_symbols_lib_wasi_threads[] = { REG_NATIVE_FUNC( + "thread-spawn", thread_spawn, "(i)i") }; + +uint32 +get_lib_wasi_threads_export_apis(NativeSymbol **p_lib_wasi_threads_apis) +{ + *p_lib_wasi_threads_apis = native_symbols_lib_wasi_threads; + return sizeof(native_symbols_lib_wasi_threads) / sizeof(NativeSymbol); +} + +bool +lib_wasi_threads_init(void) +{ + if (0 != os_mutex_init(&thread_id_lock)) + return false; + + if (!tid_allocator_init(&tid_allocator)) { + os_mutex_destroy(&thread_id_lock); + return false; + } + + return true; +} + +void +lib_wasi_threads_destroy(void) +{ + tid_allocator_deinit(&tid_allocator); + os_mutex_destroy(&thread_id_lock); +} diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/build.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/build.sh new file mode 100755 index 00000000000..32586c20c88 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/build.sh @@ -0,0 +1,35 @@ +#!/bin/bash + +# +# Copyright (C) 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# + +set -eo pipefail +CC=${CC:=/opt/wasi-sdk/bin/clang} +WAMR_DIR=../../../../.. + +for test_c in *.c; do + test_wasm="$(basename $test_c .c).wasm" + + if [ $test_wasm = "linear_memory_size_update.wasm" ]; then + thread_start_file="" + else + thread_start_file=$WAMR_DIR/samples/wasi-threads/wasm-apps/wasi_thread_start.S + fi + + echo "Compiling $test_c to $test_wasm" + $CC \ + -target wasm32-wasi-threads \ + -pthread -ftls-model=local-exec \ + -z stack-size=32768 \ + -Wl,--export=__heap_base \ + -Wl,--export=__data_end \ + -Wl,--shared-memory,--max-memory=1966080 \ + -Wl,--export=wasi_thread_start \ + -Wl,--export=malloc \ + -Wl,--export=free \ + -I $WAMR_DIR/samples/wasi-threads/wasm-apps \ + $thread_start_file \ + $test_c -o $test_wasm +done \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/common.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/common.h new file mode 100644 index 00000000000..01ca932c5e6 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/common.h @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2022 Amazon.com Inc. or its affiliates. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include +#include +#include +#include +#include +#include + +#if USE_CUSTOM_SYNC_PRIMITIVES != 0 +#include "sync_primitives.h" +#else +#include +#endif + +#include "wasi_thread_start.h" + +typedef enum { + BLOCKING_TASK_BUSY_WAIT, + BLOCKING_TASK_ATOMIC_WAIT, + BLOCKING_TASK_POLL_ONEOFF +} blocking_task_type_t; + +/* Parameter to change test behavior */ +static bool termination_by_trap; +static bool termination_in_main_thread; +static blocking_task_type_t blocking_task_type; + +#define NUM_THREADS 3 +static pthread_barrier_t barrier; + +typedef struct { + start_args_t base; + bool throw_exception; +} shared_t; + +void +run_long_task() +{ + if (blocking_task_type == BLOCKING_TASK_BUSY_WAIT) { + for (;;) { + } + } + else if (blocking_task_type == BLOCKING_TASK_ATOMIC_WAIT) { + __builtin_wasm_memory_atomic_wait32(0, 0, -1); + } + else { + sleep(UINT_MAX); + } +} + +void +start_job() +{ + /* Wait for all threads (including the main thread) to be ready */ + pthread_barrier_wait(&barrier); + run_long_task(); /* Task to be interrupted */ + assert(false && "Thread termination test failed"); +} + +void +terminate_process() +{ + /* Wait for all threads (including the main thread) to be ready */ + pthread_barrier_wait(&barrier); + + if (termination_by_trap) + __builtin_trap(); + else + __wasi_proc_exit(33); +} + +void +__wasi_thread_start_C(int thread_id, int *start_arg) +{ + shared_t *data = (shared_t *)start_arg; + + if (data->throw_exception) { + terminate_process(); + } + else { + start_job(); + } +} + +void +test_termination(bool trap, bool main, blocking_task_type_t task_type) +{ + termination_by_trap = trap; + termination_in_main_thread = main; + blocking_task_type = task_type; + + int thread_id = -1, i; + shared_t data[NUM_THREADS] = { 0 }; + assert(pthread_barrier_init(&barrier, NULL, NUM_THREADS + 1) == 0 + && "Failed to init barrier"); + + for (i = 0; i < NUM_THREADS; i++) { + /* No graceful memory free to simplify the test */ + assert(start_args_init(&data[i].base) + && "Failed to allocate thread's stack"); + } + + /* Create a thread that forces termination through trap or `proc_exit` */ + data[0].throw_exception = !termination_in_main_thread; + thread_id = __wasi_thread_spawn(&data[0]); + assert(thread_id > 0 && "Failed to create thread"); + + /* Create two additional threads to test exception propagation */ + data[1].throw_exception = false; + thread_id = __wasi_thread_spawn(&data[1]); + assert(thread_id > 0 && "Failed to create thread"); + data[2].throw_exception = false; + thread_id = __wasi_thread_spawn(&data[2]); + assert(thread_id > 0 && "Failed to create thread"); + + if (termination_in_main_thread) { + terminate_process(); + } + else { + start_job(); + } +} \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/create_threads_until_limit.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/create_threads_until_limit.c new file mode 100644 index 00000000000..23ba5f62777 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/create_threads_until_limit.c @@ -0,0 +1,128 @@ +/* + * 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 +#include +#include +#include + +#include "wasi_thread_start.h" + +enum CONSTANTS { + MAX_NUM_THREADS = 4, /* Should be the same as "--max-threads" */ + NUM_RETRY = 5, + SECOND = 1000 * 1000 * 1000, /* 1 second */ + TIMEOUT = 10LL * SECOND +}; + +int g_count = 0; + +typedef struct { + start_args_t base; + int th_ready; + int th_continue; + int th_done; + bool no_ops; +} shared_t; + +void +__wasi_thread_start_C(int thread_id, int *start_arg) +{ + shared_t *data = (shared_t *)start_arg; + + if (data->no_ops) { + __builtin_wasm_memory_atomic_wait32(NULL, 0, 2 * SECOND); + return; + } + + __atomic_store_n(&data->th_ready, 1, __ATOMIC_SEQ_CST); + __builtin_wasm_memory_atomic_notify(&data->th_ready, 1); + + if (__builtin_wasm_memory_atomic_wait32(&data->th_continue, 0, TIMEOUT) + == 2) { + assert(false && "Wait should not time out"); + } + + __atomic_fetch_add(&g_count, 1, __ATOMIC_SEQ_CST); + + __atomic_store_n(&data->th_done, 1, __ATOMIC_SEQ_CST); + __builtin_wasm_memory_atomic_notify(&data->th_done, 1); +} + +int +main(int argc, char **argv) +{ + shared_t data[MAX_NUM_THREADS] = { 0 }; + int thread_ids[MAX_NUM_THREADS]; + + for (int i = 0; i < MAX_NUM_THREADS; i++) { + assert(start_args_init(&data[i].base)); + thread_ids[i] = __wasi_thread_spawn(&data[i]); + printf("Thread created with id=%d\n", thread_ids[i]); + assert(thread_ids[i] > 0 && "Thread creation failed"); + + for (int j = 0; j < i; j++) { + assert(thread_ids[i] != thread_ids[j] && "Duplicated TIDs"); + } + + if (__builtin_wasm_memory_atomic_wait32(&data[i].th_ready, 0, TIMEOUT) + == 2) { + assert(false && "Wait should not time out"); + } + } + + printf("Attempt to create thread when not possible\n"); + shared_t data_fail = { 0 }; + assert(start_args_init(&data_fail.base)); + int thread_id = __wasi_thread_spawn(&data_fail); + start_args_deinit(&data_fail.base); + assert(thread_id < 0 && "Thread creation should fail"); + + printf("Unlock created threads\n"); + for (int i = 0; i < MAX_NUM_THREADS; i++) { + __atomic_store_n(&data[i].th_continue, 1, __ATOMIC_SEQ_CST); + __builtin_wasm_memory_atomic_notify(&data[i].th_continue, 1); + } + + printf("Wait for threads to finish\n"); + for (int i = 0; i < MAX_NUM_THREADS; i++) { + if (__builtin_wasm_memory_atomic_wait32(&data[i].th_done, 0, TIMEOUT) + == 2) { + assert(false && "Wait should not time out"); + } + + start_args_deinit(&data[i].base); + } + + printf("Value of count after update: %d\n", g_count); + assert(g_count == (MAX_NUM_THREADS) + && "Global count not updated correctly"); + + /* --------------------------------------------------- */ + + printf("Create new threads without waiting from them to finish\n"); + shared_t data_no_join[MAX_NUM_THREADS] = { 0 }; + for (int i = 0; i < MAX_NUM_THREADS; i++) { + /* No graceful memory free to simplify the test */ + assert(start_args_init(&data_no_join[i].base)); + data_no_join[i].no_ops = true; + + int thread_id = -1; + for (int j = 0; j < NUM_RETRY && thread_id < 0; j++) { + thread_id = __wasi_thread_spawn(&data_no_join[i]); + if (thread_id < 0) + __builtin_wasm_memory_atomic_wait32(NULL, 0, SECOND); + } + + printf("Thread created with id=%d\n", thread_id); + assert(thread_id > 0 && "Thread creation should succeed"); + } + + return EXIT_SUCCESS; +} diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/global_atomic.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/global_atomic.c new file mode 100644 index 00000000000..a38e753640f --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/global_atomic.c @@ -0,0 +1,70 @@ +/* + * 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 +#include +#include +#include + +#include "wasi_thread_start.h" + +enum CONSTANTS { + NUM_THREADS = 4, + NUM_ITER = 1000, + SECOND = 1000 * 1000 * 1000, /* 1 second */ + TIMEOUT = 10LL * SECOND +}; + +int g_count = 0; + +typedef struct { + start_args_t base; + int th_done; +} shared_t; + +void +__wasi_thread_start_C(int thread_id, int *start_arg) +{ + shared_t *data = (shared_t *)start_arg; + + for (int i = 0; i < NUM_ITER; i++) + __atomic_fetch_add(&g_count, 1, __ATOMIC_SEQ_CST); + + __atomic_store_n(&data->th_done, 1, __ATOMIC_SEQ_CST); + __builtin_wasm_memory_atomic_notify(&data->th_done, 1); +} + +int +main(int argc, char **argv) +{ + shared_t data[NUM_THREADS] = { 0 }; + int thread_ids[NUM_THREADS]; + + for (int i = 0; i < NUM_THREADS; i++) { + assert(start_args_init(&data[i].base)); + thread_ids[i] = __wasi_thread_spawn(&data[i]); + assert(thread_ids[i] > 0 && "Thread creation failed"); + } + + printf("Wait for threads to finish\n"); + for (int i = 0; i < NUM_THREADS; i++) { + if (__builtin_wasm_memory_atomic_wait32(&data[i].th_done, 0, TIMEOUT) + == 2) { + assert(false && "Wait should not time out"); + } + + start_args_deinit(&data[i].base); + } + + printf("Value of count after update: %d\n", g_count); + assert(g_count == (NUM_THREADS * NUM_ITER) + && "Global count not updated correctly"); + + return EXIT_SUCCESS; +} diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/global_lock.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/global_lock.c new file mode 100644 index 00000000000..f81fca49b90 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/global_lock.c @@ -0,0 +1,83 @@ +/* + * 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 +#include +#include +#include + +#if USE_CUSTOM_SYNC_PRIMITIVES != 0 +#include "sync_primitives.h" +#else +#include +#endif + +#include "wasi_thread_start.h" + +enum CONSTANTS { + NUM_THREADS = 4, + NUM_ITER = 200, + SECOND = 1000 * 1000 * 1000, /* 1 second */ + TIMEOUT = 10LL * SECOND +}; + +pthread_mutex_t mutex; +int g_count = 0; + +typedef struct { + start_args_t base; + int th_done; +} shared_t; + +void +__wasi_thread_start_C(int thread_id, int *start_arg) +{ + shared_t *data = (shared_t *)start_arg; + + for (int i = 0; i < NUM_ITER; i++) { + pthread_mutex_lock(&mutex); + g_count++; + pthread_mutex_unlock(&mutex); + } + + __atomic_store_n(&data->th_done, 1, __ATOMIC_SEQ_CST); + __builtin_wasm_memory_atomic_notify(&data->th_done, 1); +} + +int +main(int argc, char **argv) +{ + shared_t data[NUM_THREADS] = { 0 }; + int thread_ids[NUM_THREADS]; + + assert(pthread_mutex_init(&mutex, NULL) == 0 && "Failed to init mutex"); + + for (int i = 0; i < NUM_THREADS; i++) { + assert(start_args_init(&data[i].base)); + thread_ids[i] = __wasi_thread_spawn(&data[i]); + assert(thread_ids[i] > 0 && "Thread creation failed"); + } + + printf("Wait for threads to finish\n"); + for (int i = 0; i < NUM_THREADS; i++) { + if (__builtin_wasm_memory_atomic_wait32(&data[i].th_done, 0, TIMEOUT) + == 2) { + assert(false && "Wait should not time out"); + } + + start_args_deinit(&data[i].base); + } + + printf("Value of count after update: %d\n", g_count); + assert(g_count == (NUM_THREADS * NUM_ITER) + && "Global count not updated correctly"); + + assert(pthread_mutex_destroy(&mutex) == 0 && "Failed to destroy mutex"); + return EXIT_SUCCESS; +} diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/linear_memory_size_update.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/linear_memory_size_update.c new file mode 100644 index 00000000000..9dcb34a6cbd --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/linear_memory_size_update.c @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2023 Amazon.com Inc. or its affiliates. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ +#include +#include + +typedef enum { + APP_STARTED, + THREAD_STARTED, + MEMORY_ALLOCATED, +} app_state_t; +typedef struct { + + pthread_cond_t cond; + pthread_mutex_t mutex; + app_state_t state; + char *data; +} context_t; + +void +context_init(context_t *ctx) +{ + pthread_cond_init(&ctx->cond, NULL); + pthread_mutex_init(&ctx->mutex, NULL); + ctx->state = APP_STARTED; + ctx->data = NULL; +} + +void +context_destroy(context_t *ctx) +{ + pthread_cond_destroy(&ctx->cond); + pthread_mutex_destroy(&ctx->mutex); + if (ctx->data) { + free(ctx->data); + } +} + +void +context_set_state(context_t *ctx, app_state_t state) +{ + pthread_mutex_lock(&ctx->mutex); + ctx->state = state; + pthread_mutex_unlock(&ctx->mutex); + pthread_cond_signal(&ctx->cond); +} + +void +context_wait_for_state(context_t *ctx, app_state_t state) +{ + pthread_mutex_lock(&ctx->mutex); + while (ctx->state != state) { + pthread_cond_wait(&ctx->cond, &ctx->mutex); + } + pthread_mutex_unlock(&ctx->mutex); +} + +void * +fnc(void *p) +{ + context_t *ctx = (context_t *)p; + context_set_state(ctx, THREAD_STARTED); + + context_wait_for_state(ctx, MEMORY_ALLOCATED); + + // trigger memory.copy + __builtin_memcpy(ctx->data + 512 * 1024, ctx->data + 1024, 1024); + + return NULL; +} + +int +main() +{ + context_t ctx; + context_init(&ctx); + + pthread_t th; + pthread_create(&th, NULL, fnc, &ctx); + + context_wait_for_state(&ctx, THREAD_STARTED); + + // trigger memory.grow + ctx.data = calloc(1024 * 1024, 1); + + context_set_state(&ctx, MEMORY_ALLOCATED); + + pthread_join(th, NULL); + + context_destroy(&ctx); + + return 0; +} diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_proc_exit_busy.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_proc_exit_busy.c new file mode 100644 index 00000000000..19d3ec25619 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_proc_exit_busy.c @@ -0,0 +1,16 @@ +/* + * 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 "common.h" + +int +main(int argc, char **argv) +{ + test_termination(false, true, BLOCKING_TASK_BUSY_WAIT); +} \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_proc_exit_busy.json b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_proc_exit_busy.json new file mode 100644 index 00000000000..5370f66701b --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_proc_exit_busy.json @@ -0,0 +1,3 @@ +{ + "exit_code": 33 +} \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_proc_exit_sleep.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_proc_exit_sleep.c new file mode 100644 index 00000000000..a667e91227d --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_proc_exit_sleep.c @@ -0,0 +1,16 @@ +/* + * 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 "common.h" + +int +main(int argc, char **argv) +{ + test_termination(false, true, BLOCKING_TASK_POLL_ONEOFF); +} \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_proc_exit_sleep.json b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_proc_exit_sleep.json new file mode 100644 index 00000000000..5370f66701b --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_proc_exit_sleep.json @@ -0,0 +1,3 @@ +{ + "exit_code": 33 +} \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_proc_exit_wait.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_proc_exit_wait.c new file mode 100644 index 00000000000..dc8615adb0c --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_proc_exit_wait.c @@ -0,0 +1,16 @@ +/* + * 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 "common.h" + +int +main(int argc, char **argv) +{ + test_termination(false, true, BLOCKING_TASK_ATOMIC_WAIT); +} \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_proc_exit_wait.json b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_proc_exit_wait.json new file mode 100644 index 00000000000..5370f66701b --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_proc_exit_wait.json @@ -0,0 +1,3 @@ +{ + "exit_code": 33 +} \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_trap_busy.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_trap_busy.c new file mode 100644 index 00000000000..bb0ac8fa008 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_trap_busy.c @@ -0,0 +1,16 @@ +/* + * 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 "common.h" + +int +main(int argc, char **argv) +{ + test_termination(true, true, BLOCKING_TASK_BUSY_WAIT); +} \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_trap_busy.json b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_trap_busy.json new file mode 100644 index 00000000000..07689a1055c --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_trap_busy.json @@ -0,0 +1,3 @@ +{ + "exit_code": 1 +} \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_trap_sleep.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_trap_sleep.c new file mode 100644 index 00000000000..a2c248882f9 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_trap_sleep.c @@ -0,0 +1,16 @@ +/* + * 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 "common.h" + +int +main(int argc, char **argv) +{ + test_termination(true, true, BLOCKING_TASK_POLL_ONEOFF); +} \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_trap_sleep.json b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_trap_sleep.json new file mode 100644 index 00000000000..07689a1055c --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_trap_sleep.json @@ -0,0 +1,3 @@ +{ + "exit_code": 1 +} \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_trap_wait.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_trap_wait.c new file mode 100644 index 00000000000..0904f34bb0f --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_trap_wait.c @@ -0,0 +1,16 @@ +/* + * 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 "common.h" + +int +main(int argc, char **argv) +{ + test_termination(true, true, BLOCKING_TASK_ATOMIC_WAIT); +} \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_trap_wait.json b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_trap_wait.json new file mode 100644 index 00000000000..07689a1055c --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/main_trap_wait.json @@ -0,0 +1,3 @@ +{ + "exit_code": 1 +} \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_proc_exit_busy.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_proc_exit_busy.c new file mode 100644 index 00000000000..71fdcb817c1 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_proc_exit_busy.c @@ -0,0 +1,16 @@ +/* + * 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 "common.h" + +int +main(int argc, char **argv) +{ + test_termination(false, false, BLOCKING_TASK_BUSY_WAIT); +} \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_proc_exit_busy.json b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_proc_exit_busy.json new file mode 100644 index 00000000000..5370f66701b --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_proc_exit_busy.json @@ -0,0 +1,3 @@ +{ + "exit_code": 33 +} \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_proc_exit_sleep.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_proc_exit_sleep.c new file mode 100644 index 00000000000..14352cf4177 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_proc_exit_sleep.c @@ -0,0 +1,16 @@ +/* + * 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 "common.h" + +int +main(int argc, char **argv) +{ + test_termination(false, false, BLOCKING_TASK_POLL_ONEOFF); +} \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_proc_exit_sleep.json b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_proc_exit_sleep.json new file mode 100644 index 00000000000..5370f66701b --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_proc_exit_sleep.json @@ -0,0 +1,3 @@ +{ + "exit_code": 33 +} \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_proc_exit_wait.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_proc_exit_wait.c new file mode 100644 index 00000000000..0963aa02fab --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_proc_exit_wait.c @@ -0,0 +1,16 @@ +/* + * 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 "common.h" + +int +main(int argc, char **argv) +{ + test_termination(false, false, BLOCKING_TASK_ATOMIC_WAIT); +} \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_proc_exit_wait.json b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_proc_exit_wait.json new file mode 100644 index 00000000000..5370f66701b --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_proc_exit_wait.json @@ -0,0 +1,3 @@ +{ + "exit_code": 33 +} \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_trap_busy.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_trap_busy.c new file mode 100644 index 00000000000..b3e3af7dc06 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_trap_busy.c @@ -0,0 +1,16 @@ +/* + * 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 "common.h" + +int +main(int argc, char **argv) +{ + test_termination(true, false, BLOCKING_TASK_BUSY_WAIT); +} \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_trap_busy.json b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_trap_busy.json new file mode 100644 index 00000000000..07689a1055c --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_trap_busy.json @@ -0,0 +1,3 @@ +{ + "exit_code": 1 +} \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_trap_sleep.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_trap_sleep.c new file mode 100644 index 00000000000..a68ae8be50c --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_trap_sleep.c @@ -0,0 +1,16 @@ +/* + * 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 "common.h" + +int +main(int argc, char **argv) +{ + test_termination(true, false, BLOCKING_TASK_POLL_ONEOFF); +} \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_trap_sleep.json b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_trap_sleep.json new file mode 100644 index 00000000000..07689a1055c --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_trap_sleep.json @@ -0,0 +1,3 @@ +{ + "exit_code": 1 +} \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_trap_wait.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_trap_wait.c new file mode 100644 index 00000000000..52c684a5182 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_trap_wait.c @@ -0,0 +1,16 @@ +/* + * 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 "common.h" + +int +main(int argc, char **argv) +{ + test_termination(true, false, BLOCKING_TASK_ATOMIC_WAIT); +} \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_trap_wait.json b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_trap_wait.json new file mode 100644 index 00000000000..07689a1055c --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/nonmain_trap_wait.json @@ -0,0 +1,3 @@ +{ + "exit_code": 1 +} \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/spawn_multiple_times.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/spawn_multiple_times.c new file mode 100644 index 00000000000..24664c4705a --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/spawn_multiple_times.c @@ -0,0 +1,72 @@ +/* + * 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 +#include +#include +#include + +#include "wasi_thread_start.h" + +enum CONSTANTS { + NUM_ITER = 50, + NUM_RETRY = 5, + SECOND = 1000 * 1000 * 1000, /* 1 second */ + TIMEOUT = 5LL * SECOND +}; + +typedef struct { + start_args_t base; + int th_done; +} shared_t; + +int g_count = 0; + +void +__wasi_thread_start_C(int thread_id, int *start_arg) +{ + shared_t *data = (shared_t *)start_arg; + + g_count++; + + __atomic_store_n(&data->th_done, 1, __ATOMIC_SEQ_CST); + __builtin_wasm_memory_atomic_notify(&data->th_done, 1); +} + +int +main(int argc, char **argv) +{ + shared_t data = { 0 }; + assert(start_args_init(&data.base) && "Stack allocation for thread failed"); + + for (int i = 0; i < NUM_ITER; i++) { + data.th_done = 0; + + printf("Creating thread\n"); + int thread_id = -1; + for (int j = 0; j < NUM_RETRY && thread_id < 0; j++) { + thread_id = __wasi_thread_spawn(&data); + if (thread_id < 0) + __builtin_wasm_memory_atomic_wait32(NULL, 0, SECOND); + } + assert(thread_id > 0 && "Thread creation should succeed"); + + printf("Waiting for thread to finish\n"); + if (__builtin_wasm_memory_atomic_wait32(&data.th_done, 0, TIMEOUT) + == 2) { + assert(false && "Wait should not time out"); + } + printf("Thread has finished\n"); + } + + assert(g_count == NUM_ITER && "Count has not been updated correctly"); + + start_args_deinit(&data.base); + return EXIT_SUCCESS; +} diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/sync_primitives.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/sync_primitives.h new file mode 100644 index 00000000000..4b7dac8ec91 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/sync_primitives.h @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2023 Amazon.com Inc. or its affiliates. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include + +/* Mutex */ + +typedef int pthread_mutex_t; + +int +pthread_mutex_init(pthread_mutex_t *mutex, void *unused) +{ + *mutex = 0; + return 0; +} + +int +pthread_mutex_destroy(pthread_mutex_t *mutex) +{ + return 0; +} + +static bool +try_pthread_mutex_lock(pthread_mutex_t *mutex) +{ + int expected = 0; + return __atomic_compare_exchange_n(mutex, &expected, 1, false, + __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); +} + +int +pthread_mutex_lock(pthread_mutex_t *mutex) +{ + while (!try_pthread_mutex_lock(mutex)) + __builtin_wasm_memory_atomic_wait32(mutex, 1, -1); + return 0; +} + +int +pthread_mutex_unlock(pthread_mutex_t *mutex) +{ + __atomic_store_n(mutex, 0, __ATOMIC_SEQ_CST); + __builtin_wasm_memory_atomic_notify(mutex, 1); + return 0; +} + +/* Barrier */ + +typedef struct { + int count; + int num_threads; + int mutex; + int ready; +} pthread_barrier_t; + +int +pthread_barrier_init(pthread_barrier_t *barrier, void *unused, int num_threads) +{ + barrier->count = 0; + barrier->num_threads = num_threads; + barrier->ready = 0; + pthread_mutex_init(&barrier->mutex, NULL); + + return 0; +} + +int +pthread_barrier_wait(pthread_barrier_t *barrier) +{ + bool no_wait = false; + int count; + + pthread_mutex_lock(&barrier->mutex); + count = barrier->count++; + if (barrier->count >= barrier->num_threads) { + no_wait = true; + barrier->count = 0; + } + pthread_mutex_unlock(&barrier->mutex); + + if (no_wait) { + __atomic_store_n(&barrier->ready, 1, __ATOMIC_SEQ_CST); + __builtin_wasm_memory_atomic_notify(&barrier->ready, count); + return 0; + } + + __builtin_wasm_memory_atomic_wait32(&barrier->ready, 0, -1); + return 0; +} \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/trap_after_main_thread_finishes.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/trap_after_main_thread_finishes.c new file mode 100644 index 00000000000..69e125d407d --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/trap_after_main_thread_finishes.c @@ -0,0 +1,44 @@ +/* + * 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 +#include +#include + +#include "wasi_thread_start.h" + +enum CONSTANTS { + SECOND = 1000 * 1000 * 1000, /* 1 second */ + TIMEOUT = 1LL * SECOND +}; + +typedef struct { + start_args_t base; +} shared_t; + +void +__wasi_thread_start_C(int thread_id, int *start_arg) +{ + /* Wait so that the exception is raised after the main thread has finished + * already */ + __builtin_wasm_memory_atomic_wait32(NULL, 0, TIMEOUT); + __builtin_trap(); +} + +int +main(int argc, char **argv) +{ + shared_t data = { 0 }; + + assert(start_args_init(&data.base)); + int thread_id = __wasi_thread_spawn(&data); + assert(thread_id > 0 && "Thread creation failed"); + + return EXIT_SUCCESS; +} diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/trap_after_main_thread_finishes.json b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/trap_after_main_thread_finishes.json new file mode 100644 index 00000000000..9dc1e30d2b1 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/trap_after_main_thread_finishes.json @@ -0,0 +1,3 @@ +{ + "exit_code": 1 +} diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/update_shared_data_and_alloc_heap.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/update_shared_data_and_alloc_heap.c new file mode 100644 index 00000000000..b7fb9afba6b --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/test/update_shared_data_and_alloc_heap.c @@ -0,0 +1,97 @@ +/* + * 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 +#include +#include +#include +#include + +#include "wasi_thread_start.h" + +enum CONSTANTS { + NUM_THREADS = 4, + NUM_ITER = 30, + SECOND = 1000 * 1000 * 1000, /* 1 second */ + TIMEOUT = 10LL * SECOND +}; + +typedef struct { + start_args_t base; + int th_done; + int *count; + int iteration; + int *pval; +} shared_t; + +pthread_mutex_t mutex; +int *vals[NUM_THREADS]; + +void +__wasi_thread_start_C(int thread_id, int *start_arg) +{ + shared_t *data = (shared_t *)start_arg; + + for (int i = 0; i < NUM_ITER; i++) + __atomic_fetch_add(data->count, 1, __ATOMIC_SEQ_CST); + + *vals[data->iteration] = data->iteration; + + __atomic_store_n(&data->th_done, 1, __ATOMIC_SEQ_CST); + __builtin_wasm_memory_atomic_notify(&data->th_done, 1); +} + +int +main(int argc, char **argv) +{ + shared_t data[NUM_THREADS] = { 0 }; + int thread_ids[NUM_THREADS]; + int *count = calloc(1, sizeof(int)); + + assert(count != NULL && "Failed to call calloc"); + assert(pthread_mutex_init(&mutex, NULL) == 0 && "Failed to init mutex"); + + for (int i = 0; i < NUM_THREADS; i++) { + vals[i] = malloc(sizeof(int)); + assert(vals[i] != NULL && "Failed to call calloc"); + } + + for (int i = 0; i < NUM_THREADS; i++) { + assert(start_args_init(&data[i].base) + && "Stack allocation for thread failed"); + __atomic_store_n(&data[i].count, count, __ATOMIC_SEQ_CST); + data[i].iteration = i; + + thread_ids[i] = __wasi_thread_spawn(&data[i]); + assert(thread_ids[i] > 0 && "Thread creation failed"); + } + + printf("Wait for threads to finish\n"); + for (int i = 0; i < NUM_THREADS; i++) { + if (__builtin_wasm_memory_atomic_wait32(&data[i].th_done, 0, TIMEOUT) + == 2) { + assert(false && "Wait should not time out"); + } + + start_args_deinit(&data[i].base); + } + + assert(*count == (NUM_THREADS * NUM_ITER) && "Count not updated correctly"); + + for (int i = 0; i < NUM_THREADS; i++) { + printf("val=%d\n", *vals[i]); + assert(*vals[i] == i && "Value not updated correctly"); + free(vals[i]); + } + + free(count); + assert(pthread_mutex_destroy(&mutex) == 0 && "Failed to destroy mutex"); + + return EXIT_SUCCESS; +} diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/tid_allocator.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/tid_allocator.c new file mode 100644 index 00000000000..4d53da0c94f --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/tid_allocator.c @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "tid_allocator.h" +#include "wasm_export.h" +#include "bh_log.h" + +bh_static_assert(TID_MIN <= TID_MAX); +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) + +bool +tid_allocator_init(TidAllocator *tid_allocator) +{ + tid_allocator->size = MIN(TID_ALLOCATOR_INIT_SIZE, TID_MAX - TID_MIN + 1); + tid_allocator->pos = tid_allocator->size; + tid_allocator->ids = + wasm_runtime_malloc(tid_allocator->size * sizeof(int32)); + if (tid_allocator->ids == NULL) + return false; + + for (int64 i = tid_allocator->pos - 1; i >= 0; i--) + tid_allocator->ids[i] = TID_MIN + (tid_allocator->pos - 1 - i); + + return true; +} + +void +tid_allocator_deinit(TidAllocator *tid_allocator) +{ + wasm_runtime_free(tid_allocator->ids); +} + +int32 +tid_allocator_get_tid(TidAllocator *tid_allocator) +{ + if (tid_allocator->pos == 0) { // Resize stack and push new thread ids + if (tid_allocator->size == TID_MAX - TID_MIN + 1) { + LOG_ERROR("Maximum thread identifier reached"); + return -1; + } + + uint32 old_size = tid_allocator->size; + uint32 new_size = MIN(tid_allocator->size * 2, TID_MAX - TID_MIN + 1); + if (new_size != TID_MAX - TID_MIN + 1 + && new_size / 2 != tid_allocator->size) { + LOG_ERROR("Overflow detected during new size calculation"); + return -1; + } + + size_t realloc_size = new_size * sizeof(int32); + if (realloc_size / sizeof(int32) != new_size) { + LOG_ERROR("Overflow detected during realloc"); + return -1; + } + int32 *tmp = wasm_runtime_realloc(tid_allocator->ids, realloc_size); + if (tmp == NULL) { + LOG_ERROR("Thread ID allocator realloc failed"); + return -1; + } + + tid_allocator->size = new_size; + tid_allocator->pos = new_size - old_size; + tid_allocator->ids = tmp; + for (int64 i = tid_allocator->pos - 1; i >= 0; i--) + tid_allocator->ids[i] = TID_MIN + (tid_allocator->size - 1 - i); + } + + // Pop available thread identifier from the stack + return tid_allocator->ids[--tid_allocator->pos]; +} + +void +tid_allocator_release_tid(TidAllocator *tid_allocator, int32 thread_id) +{ + // Release thread identifier by pushing it into the stack + bh_assert(tid_allocator->pos < tid_allocator->size); + tid_allocator->ids[tid_allocator->pos++] = thread_id; +} \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/tid_allocator.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/tid_allocator.h new file mode 100644 index 00000000000..53af1719ff3 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/lib-wasi-threads/tid_allocator.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef _TID_ALLOCATOR_H +#define _TID_ALLOCATOR_H + +#include "platform_common.h" + +#define TID_ALLOCATOR_INIT_SIZE CLUSTER_MAX_THREAD_NUM +enum { + TID_MIN = 1, + TID_MAX = 0x1FFFFFFF +}; // Reserved TIDs (WASI specification) + +/* Stack data structure to track available thread identifiers */ +typedef struct { + int32 *ids; // Array used to store the stack + uint32 size; // Stack capacity + uint32 pos; // Index of the element after the stack top +} TidAllocator; + +bool +tid_allocator_init(TidAllocator *tid_allocator); + +void +tid_allocator_deinit(TidAllocator *tid_allocator); + +int32 +tid_allocator_get_tid(TidAllocator *tid_allocator); + +void +tid_allocator_release_tid(TidAllocator *tid_allocator, int32 thread_id); + +#endif /* _TID_ALLOCATOR_H */ \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-builtin/SConscript b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-builtin/SConscript similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-builtin/SConscript rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-builtin/SConscript diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-builtin/libc_builtin.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-builtin/libc_builtin.cmake similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-builtin/libc_builtin.cmake rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-builtin/libc_builtin.cmake diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c similarity index 99% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c index c24f789adc5..55916deb469 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-builtin/libc_builtin_wrapper.c @@ -952,13 +952,13 @@ print_wrapper(wasm_exec_env_t exec_env) static void print_i32_wrapper(wasm_exec_env_t exec_env, int32 i32) { - os_printf("in specttest.print_i32(%d)\n", i32); + os_printf("in specttest.print_i32(%" PRId32 ")\n", i32); } static void print_i32_f32_wrapper(wasm_exec_env_t exec_env, int32 i32, float f32) { - os_printf("in specttest.print_i32_f32(%d, %f)\n", i32, f32); + os_printf("in specttest.print_i32_f32(%" PRId32 ", %f)\n", i32, f32); } static void diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-emcc/SConscript b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-emcc/SConscript similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-emcc/SConscript rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-emcc/SConscript diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-emcc/libc_emcc.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-emcc/libc_emcc.cmake similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-emcc/libc_emcc.cmake rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-emcc/libc_emcc.cmake diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-emcc/libc_emcc_wrapper.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-emcc/libc_emcc_wrapper.c similarity index 99% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-emcc/libc_emcc_wrapper.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-emcc/libc_emcc_wrapper.c index e35f3908d13..23c02aad32e 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-emcc/libc_emcc_wrapper.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-emcc/libc_emcc_wrapper.c @@ -37,10 +37,6 @@ wasm_runtime_module_free(module_inst, offset) /* clang-format on */ -extern bool -wasm_runtime_call_indirect(wasm_exec_env_t exec_env, uint32 element_idx, - uint32 argc, uint32 argv[]); - static void invoke_viiii_wrapper(wasm_exec_env_t exec_env, uint32 elem_idx, int arg0, int arg1, int arg2, int arg3) diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-uvwasi/LICENSE_LIBUV b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-uvwasi/LICENSE_LIBUV similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-uvwasi/LICENSE_LIBUV rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-uvwasi/LICENSE_LIBUV diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-uvwasi/LICENSE_UVWASI b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-uvwasi/LICENSE_UVWASI similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-uvwasi/LICENSE_UVWASI rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-uvwasi/LICENSE_UVWASI diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-uvwasi/libc_uvwasi.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-uvwasi/libc_uvwasi.cmake similarity index 97% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-uvwasi/libc_uvwasi.cmake rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-uvwasi/libc_uvwasi.cmake index d0766c4a9f0..e0c8afa21f3 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-uvwasi/libc_uvwasi.cmake +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-uvwasi/libc_uvwasi.cmake @@ -3,7 +3,7 @@ set (LIBC_WASI_DIR ${CMAKE_CURRENT_LIST_DIR}) -set (LIBUV_VERSION v1.42.0) +set (LIBUV_VERSION v1.44.2) add_definitions (-DWASM_ENABLE_LIBC_WASI=1 -DWASM_ENABLE_UVWASI=1) diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-uvwasi/libc_uvwasi_wrapper.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-uvwasi/libc_uvwasi_wrapper.c similarity index 98% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-uvwasi/libc_uvwasi_wrapper.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-uvwasi/libc_uvwasi_wrapper.c index 187693ea96a..504ff7f93e4 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-uvwasi/libc_uvwasi_wrapper.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-uvwasi/libc_uvwasi_wrapper.c @@ -11,9 +11,6 @@ #define get_module_inst(exec_env) \ wasm_runtime_get_module_inst(exec_env) -#define get_wasi_ctx(module_inst) \ - wasm_runtime_get_wasi_ctx(module_inst) - #define validate_app_addr(offset, size) \ wasm_runtime_validate_app_addr(module_inst, offset, size) @@ -72,9 +69,24 @@ typedef struct iovec_app { uint32 buf_len; } iovec_app_t; +typedef struct WASIContext { + uvwasi_t uvwasi; + uint32_t exit_code; +} WASIContext; + void * wasm_runtime_get_wasi_ctx(wasm_module_inst_t module_inst); +static uvwasi_t * +get_wasi_ctx(wasm_module_inst_t module_inst) +{ + WASIContext *ctx = wasm_runtime_get_wasi_ctx(module_inst); + if (ctx == NULL) { + return NULL; + } + return &ctx->uvwasi; +} + static wasi_errno_t wasi_args_get(wasm_exec_env_t exec_env, uint32 *argv_offsets, char *argv_buf) { @@ -924,10 +936,12 @@ static void wasi_proc_exit(wasm_exec_env_t exec_env, wasi_exitcode_t rval) { wasm_module_inst_t module_inst = get_module_inst(exec_env); + WASIContext *wasi_ctx = wasm_runtime_get_wasi_ctx(module_inst); /* Here throwing exception is just to let wasm app exit, the upper layer should clear the exception and return as normal */ wasm_runtime_set_exception(module_inst, "wasi proc exit"); + wasi_ctx->exit_code = rval; } static wasi_errno_t diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-wasi/SConscript b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/SConscript similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-wasi/SConscript rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/SConscript diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-wasi/libc_wasi.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/libc_wasi.cmake similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-wasi/libc_wasi.cmake rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/libc_wasi.cmake diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c similarity index 94% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c index d9eea055188..afb11925ab3 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c @@ -6,6 +6,11 @@ #include "libc_wasi_wrapper.h" #include "bh_platform.h" #include "wasm_export.h" +#include "wasm_runtime_common.h" + +#if WASM_ENABLE_THREAD_MGR != 0 +#include "../../../thread-mgr/thread_manager.h" +#endif void wasm_runtime_set_exception(wasm_module_inst_t module, const char *exception); @@ -46,22 +51,23 @@ typedef struct iovec_app { uint32 buf_len; } iovec_app_t; -typedef struct WASIContext { - struct fd_table *curfds; - struct fd_prestats *prestats; - struct argv_environ_values *argv_environ; - struct addr_pool *addr_pool; - char *ns_lookup_buf; - char **ns_lookup_list; - char *argv_buf; - char **argv_list; - char *env_buf; - char **env_list; -} * wasi_ctx_t; +typedef struct WASIContext *wasi_ctx_t; wasi_ctx_t wasm_runtime_get_wasi_ctx(wasm_module_inst_t module_inst); +static inline uint64_t +min_uint64(uint64_t a, uint64_t b) +{ + return a > b ? b : a; +} + +static inline uint32_t +min_uint32(uint32_t a, uint32_t b) +{ + return a > b ? b : a; +} + static inline struct fd_table * wasi_ctx_get_curfds(wasm_module_inst_t module_inst, wasi_ctx_t wasi_ctx) { @@ -950,6 +956,108 @@ wasi_path_remove_directory(wasm_exec_env_t exec_env, wasi_fd_t fd, return wasmtime_ssp_path_remove_directory(curfds, fd, path, path_len); } +#if WASM_ENABLE_THREAD_MGR != 0 +static __wasi_timestamp_t +get_timeout_for_poll_oneoff(const wasi_subscription_t *in, + uint32 nsubscriptions) +{ + __wasi_timestamp_t timeout = (__wasi_timestamp_t)-1; + uint32 i = 0; + + for (i = 0; i < nsubscriptions; ++i) { + const __wasi_subscription_t *s = &in[i]; + if (s->u.type == __WASI_EVENTTYPE_CLOCK + && (s->u.u.clock.flags & __WASI_SUBSCRIPTION_CLOCK_ABSTIME) == 0) { + timeout = min_uint64(timeout, s->u.u.clock.timeout); + } + } + return timeout; +} + +static void +update_clock_subscription_data(wasi_subscription_t *in, uint32 nsubscriptions, + const wasi_timestamp_t new_timeout) +{ + uint32 i = 0; + for (i = 0; i < nsubscriptions; ++i) { + __wasi_subscription_t *s = &in[i]; + if (s->u.type == __WASI_EVENTTYPE_CLOCK) { + s->u.u.clock.timeout = new_timeout; + } + } +} + +static wasi_errno_t +execute_interruptible_poll_oneoff( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + const __wasi_subscription_t *in, __wasi_event_t *out, size_t nsubscriptions, + size_t *nevents, wasm_exec_env_t exec_env) +{ + if (nsubscriptions == 0) { + *nevents = 0; + return __WASI_ESUCCESS; + } + + wasi_errno_t err; + __wasi_timestamp_t elapsed = 0; + bool all_outs_are_type_clock; + uint32 i; + + const __wasi_timestamp_t timeout = get_timeout_for_poll_oneoff( + in, nsubscriptions), + time_quant = 1e9; + const uint64 size_to_copy = + nsubscriptions * (uint64)sizeof(wasi_subscription_t); + __wasi_subscription_t *in_copy = NULL; + + if (size_to_copy >= UINT32_MAX + || !(in_copy = (__wasi_subscription_t *)wasm_runtime_malloc( + (uint32)size_to_copy))) { + return __WASI_ENOMEM; + } + + bh_memcpy_s(in_copy, size_to_copy, in, size_to_copy); + + while (timeout == (__wasi_timestamp_t)-1 || elapsed <= timeout) { + /* update timeout for clock subscription events */ + update_clock_subscription_data( + in_copy, nsubscriptions, min_uint64(time_quant, timeout - elapsed)); + err = wasmtime_ssp_poll_oneoff(curfds, in_copy, out, nsubscriptions, + nevents); + elapsed += time_quant; + + if (err) { + wasm_runtime_free(in_copy); + return err; + } + + if (wasm_cluster_is_thread_terminated(exec_env)) { + wasm_runtime_free(in_copy); + return EINTR; + } + else if (*nevents > 0) { + all_outs_are_type_clock = true; + for (i = 0; i < *nevents; i++) { + if (out[i].type != __WASI_EVENTTYPE_CLOCK) { + all_outs_are_type_clock = false; + break; + } + } + + if (!all_outs_are_type_clock) { + wasm_runtime_free(in_copy); + return __WASI_ESUCCESS; + } + } + } + + wasm_runtime_free(in_copy); + return __WASI_ESUCCESS; +} +#endif + static wasi_errno_t wasi_poll_oneoff(wasm_exec_env_t exec_env, const wasi_subscription_t *in, wasi_event_t *out, uint32 nsubscriptions, uint32 *nevents_app) @@ -957,7 +1065,7 @@ wasi_poll_oneoff(wasm_exec_env_t exec_env, const wasi_subscription_t *in, wasm_module_inst_t module_inst = get_module_inst(exec_env); wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); struct fd_table *curfds = wasi_ctx_get_curfds(module_inst, wasi_ctx); - size_t nevents; + size_t nevents = 0; wasi_errno_t err; if (!wasi_ctx) @@ -968,7 +1076,12 @@ wasi_poll_oneoff(wasm_exec_env_t exec_env, const wasi_subscription_t *in, || !validate_native_addr(nevents_app, sizeof(uint32))) return (wasi_errno_t)-1; +#if WASM_ENABLE_THREAD_MGR == 0 err = wasmtime_ssp_poll_oneoff(curfds, in, out, nsubscriptions, &nevents); +#else + err = execute_interruptible_poll_oneoff(curfds, in, out, nsubscriptions, + &nevents, exec_env); +#endif if (err) return err; @@ -980,10 +1093,12 @@ static void wasi_proc_exit(wasm_exec_env_t exec_env, wasi_exitcode_t rval) { wasm_module_inst_t module_inst = get_module_inst(exec_env); + wasi_ctx_t wasi_ctx = get_wasi_ctx(module_inst); /* Here throwing exception is just to let wasm app exit, the upper layer should clear the exception and return as normal */ wasm_runtime_set_exception(module_inst, "wasi proc exit"); + wasi_ctx->exit_code = rval; } static wasi_errno_t @@ -1858,12 +1973,6 @@ allocate_iovec_app_buffer(wasm_module_inst_t module_inst, return __WASI_ESUCCESS; } -static inline size_t -min(size_t a, size_t b) -{ - return a > b ? b : a; -} - static wasi_errno_t copy_buffer_to_iovec_app(wasm_module_inst_t module_inst, uint8 *buf_begin, uint32 buf_size, iovec_app_t *data, uint32 data_len, @@ -1896,7 +2005,7 @@ copy_buffer_to_iovec_app(wasm_module_inst_t module_inst, uint8 *buf_begin, * only copy the amount in the app buffer. Otherwise, we fill the iovec * buffer and reduce size to copy on the next iteration */ - size_to_copy_into_iovec = min(data->buf_len, size_to_copy); + size_to_copy_into_iovec = min_uint32(data->buf_len, size_to_copy); native_addr = (void *)addr_app_to_native(data->buf_offset); bh_memcpy_s(native_addr, size_to_copy_into_iovec, buf, diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/LICENSE b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/LICENSE similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/LICENSE rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/LICENSE diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/LICENSE b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/LICENSE similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/LICENSE rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/LICENSE diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/wasmtime_ssp.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/wasmtime_ssp.h similarity index 96% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/wasmtime_ssp.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/wasmtime_ssp.h index 7c0405c5cfe..feadf2f9586 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/wasmtime_ssp.h +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include/wasmtime_ssp.h @@ -1062,6 +1062,70 @@ wasi_ssp_sock_connect( __wasi_fd_t fd, __wasi_addr_t *addr ) __attribute__((__warn_unused_result__)); +__wasi_errno_t +wasi_ssp_sock_get_recv_buf_size( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, __wasi_size_t *size +) __attribute__((__warn_unused_result__)); + +__wasi_errno_t +wasi_ssp_sock_get_reuse_addr( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, uint8_t *reuse +) __attribute__((__warn_unused_result__)); + +__wasi_errno_t +wasi_ssp_sock_get_reuse_port( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, uint8_t *reuse +) __attribute__((__warn_unused_result__)); + +__wasi_errno_t +wasi_ssp_sock_get_send_buf_size( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, __wasi_size_t *size +) __attribute__((__warn_unused_result__)); + +__wasi_errno_t +wasi_ssp_sock_set_recv_buf_size( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, __wasi_size_t size +) __attribute__((__warn_unused_result__)); + +__wasi_errno_t +wasi_ssp_sock_set_reuse_addr( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, uint8_t reuse +) __attribute__((__warn_unused_result__)); + +__wasi_errno_t +wasi_ssp_sock_set_reuse_port( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, uint8_t reuse +) __attribute__((__warn_unused_result__)); + +__wasi_errno_t +wasi_ssp_sock_set_send_buf_size( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, __wasi_size_t size +) __attribute__((__warn_unused_result__)); + __wasi_errno_t wasi_ssp_sock_listen( #if !defined(WASMTIME_SSP_STATIC_CURFDS) diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/LICENSE b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/LICENSE similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/LICENSE rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/LICENSE diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/README.md b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/README.md similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/README.md rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/README.md diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/gnuc.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/gnuc.h new file mode 100644 index 00000000000..70000ae0b9c --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/gnuc.h @@ -0,0 +1,14 @@ +/* + * Copyright (C) 2023 Amazon.com, Inc. or its affiliates. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#if !defined(__GNUC_PREREQ) && (defined(__GNUC__) || defined(__GNUG__)) \ + && !defined(__clang__) && defined(__GNUC_MINOR__) +/* Depending on the platform the macro is defined in sys/features.h or + features.h Given the macro is simple, we re-implement it here instead of + dealing with two different paths. + */ +#define __GNUC_PREREQ(maj, min) \ + ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min)) +#endif diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/locking.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/locking.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/locking.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/locking.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c similarity index 95% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c index b0e92c3a842..61e84183695 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c @@ -15,7 +15,6 @@ #include "bh_platform.h" #include "wasmtime_ssp.h" #include "locking.h" -#include "numeric_limits.h" #include "posix.h" #include "random.h" #include "refcount.h" @@ -686,9 +685,20 @@ fd_table_insert_existing(struct fd_table *ft, __wasi_fd_t in, int out) struct fd_object *fo; __wasi_errno_t error; - if (fd_determine_type_rights(out, &type, &rights_base, &rights_inheriting) - != 0) + error = + fd_determine_type_rights(out, &type, &rights_base, &rights_inheriting); + if (error != 0) { +#ifdef BH_PLATFORM_EGO + /** + * since it is an already opened file and we can assume the opened file + * has all necessary rights no matter how to get + */ + if (error != __WASI_ENOTSUP) + return false; +#else return false; +#endif + } error = fd_object_new(type, &fo); if (error != 0) @@ -2257,8 +2267,7 @@ convert_timestamp(__wasi_timestamp_t in, struct timespec *out) in /= 1000000000; // Clamp to the maximum in case it would overflow our system's time_t. - out->tv_sec = - (time_t)in < NUMERIC_MAX(time_t) ? (time_t)in : NUMERIC_MAX(time_t); + out->tv_sec = (time_t)in < BH_TIME_T_MAX ? (time_t)in : BH_TIME_T_MAX; } // Converts the provided timestamps and flags to a set of arguments for @@ -2604,6 +2613,8 @@ wasmtime_ssp_poll_oneoff( } #endif *nevents = 1; + if (out[0].error != 0) + return convert_errno(out[0].error); return 0; } @@ -2696,7 +2707,7 @@ wasmtime_ssp_poll_oneoff( timeout = ts > INT_MAX ? -1 : (int)ts; } else { - timeout = 1000; + timeout = -1; } int ret = poll(pfds, nsubscriptions, timeout); @@ -3081,14 +3092,15 @@ wasi_ssp_sock_addr_resolve( size_t _max_info_size; size_t actual_info_size; - if (!ns_lookup_list_search(ns_lookup_list, host)) { - return __WASI_EACCES; - } - if (!wamr_addr_info) { return __WASI_ENOMEM; } + if (!ns_lookup_list_search(ns_lookup_list, host)) { + wasm_runtime_free(wamr_addr_info); + return __WASI_EACCES; + } + int ret = os_socket_addr_resolve( host, service, hints->hints_enabled ? &hints_is_tcp : NULL, hints->hints_enabled ? &hints_is_ipv4 : NULL, wamr_addr_info, @@ -3149,6 +3161,122 @@ wasi_ssp_sock_connect( return __WASI_ESUCCESS; } +__wasi_errno_t +wasi_ssp_sock_get_recv_buf_size( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, __wasi_size_t *size) +{ + struct fd_object *fo; + int ret; + __wasi_errno_t error = fd_object_get(curfds, &fo, fd, 0, 0); + if (error != __WASI_ESUCCESS) + return error; + + int optval; + socklen_t optlen = sizeof(optval); + + ret = getsockopt(fd_number(fo), SOL_SOCKET, SO_RCVBUF, &optval, &optlen); + fd_object_release(fo); + if (BHT_OK != ret) { + return convert_errno(errno); + } + + *size = optval; + + return __WASI_ESUCCESS; +} + +__wasi_errno_t +wasi_ssp_sock_get_reuse_addr( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, uint8_t *reuse) +{ + + struct fd_object *fo; + int ret; + __wasi_errno_t error = fd_object_get(curfds, &fo, fd, 0, 0); + if (error != __WASI_ESUCCESS) + return error; + + int optval; + socklen_t optlen = sizeof(optval); + + ret = getsockopt(fd_number(fo), SOL_SOCKET, SO_REUSEADDR, &optval, &optlen); + fd_object_release(fo); + if (BHT_OK != ret) { + return convert_errno(errno); + } + + *reuse = optval; + + return __WASI_ESUCCESS; +} + +__wasi_errno_t +wasi_ssp_sock_get_reuse_port( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, uint8_t *reuse) +{ + struct fd_object *fo; + int ret; + __wasi_errno_t error = fd_object_get(curfds, &fo, fd, 0, 0); + if (error != __WASI_ESUCCESS) + return error; + + int optval; + socklen_t optlen = sizeof(optval); + +#if defined(SO_REUSEPORT) /* NuttX doesn't have SO_REUSEPORT */ + ret = getsockopt(fd_number(fo), SOL_SOCKET, SO_REUSEPORT, &optval, &optlen); +#else + errno = ENOTSUP; + ret = BHT_ERROR; + optval = 0; +#endif /* defined(SO_REUSEPORT) */ + + fd_object_release(fo); + if (BHT_OK != ret) { + return convert_errno(errno); + } + + *reuse = optval; + + return __WASI_ESUCCESS; +} + +__wasi_errno_t +wasi_ssp_sock_get_send_buf_size( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, __wasi_size_t *size) +{ + struct fd_object *fo; + int ret; + __wasi_errno_t error = fd_object_get(curfds, &fo, fd, 0, 0); + if (error != __WASI_ESUCCESS) + return error; + + int optval; + socklen_t optlen = sizeof(optval); + + ret = getsockopt(fd_number(fo), SOL_SOCKET, SO_SNDBUF, &optval, &optlen); + fd_object_release(fo); + if (BHT_OK != ret) { + return convert_errno(errno); + } + + *size = optval; + + return __WASI_ESUCCESS; +} + __wasi_errno_t wasi_ssp_sock_listen( #if !defined(WASMTIME_SSP_STATIC_CURFDS) @@ -3219,6 +3347,113 @@ wasi_ssp_sock_open( return __WASI_ESUCCESS; } +__wasi_errno_t +wasi_ssp_sock_set_recv_buf_size( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, __wasi_size_t size) +{ + struct fd_object *fo; + int ret; + __wasi_errno_t error = fd_object_get(curfds, &fo, fd, 0, 0); + if (error != __WASI_ESUCCESS) + return error; + + int optval = size; + + ret = setsockopt(fd_number(fo), SOL_SOCKET, SO_RCVBUF, &optval, + sizeof(optval)); + fd_object_release(fo); + if (BHT_OK != ret) { + return convert_errno(errno); + } + + return __WASI_ESUCCESS; +} + +__wasi_errno_t +wasi_ssp_sock_set_reuse_addr( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, uint8_t reuse) +{ + struct fd_object *fo; + int ret; + __wasi_errno_t error = fd_object_get(curfds, &fo, fd, 0, 0); + if (error != __WASI_ESUCCESS) + return error; + + int optval = reuse; + + ret = setsockopt(fd_number(fo), SOL_SOCKET, SO_REUSEADDR, &optval, + sizeof(optval)); + fd_object_release(fo); + if (BHT_OK != ret) { + return convert_errno(errno); + } + + return __WASI_ESUCCESS; +} + +__wasi_errno_t +wasi_ssp_sock_set_reuse_port( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, uint8_t reuse) +{ + struct fd_object *fo; + int ret; + __wasi_errno_t error = fd_object_get(curfds, &fo, fd, 0, 0); + if (error != __WASI_ESUCCESS) + return error; + + int optval = reuse; + +#if defined(SO_REUSEPORT) /* NuttX doesn't have SO_REUSEPORT */ + ret = setsockopt(fd_number(fo), SOL_SOCKET, SO_REUSEPORT, &optval, + sizeof(optval)); +#else + errno = ENOTSUP; + ret = BHT_ERROR; +#endif /* defined(SO_REUSEPORT) */ + + fd_object_release(fo); + if (BHT_OK != ret) { + return convert_errno(errno); + } + + return __WASI_ESUCCESS; +} + +__wasi_errno_t +wasi_ssp_sock_set_send_buf_size( +#if !defined(WASMTIME_SSP_STATIC_CURFDS) + struct fd_table *curfds, +#endif + __wasi_fd_t fd, __wasi_size_t size) +{ + struct fd_object *fo; + int ret; + __wasi_errno_t error = fd_object_get(curfds, &fo, fd, 0, 0); + if (error != __WASI_ESUCCESS) + return error; + + int optval = size; + + ret = setsockopt(fd_number(fo), SOL_SOCKET, SO_SNDBUF, &optval, + sizeof(optval)); + + fd_object_release(fo); + if (BHT_OK != ret) { + return convert_errno(errno); + } + + return __WASI_ESUCCESS; +} + __wasi_errno_t wasmtime_ssp_sock_recv( #if !defined(WASMTIME_SSP_STATIC_CURFDS) diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/queue.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/queue.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/queue.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/queue.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/random.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/random.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/random.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/random.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/random.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/random.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/random.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/random.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/refcount.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/refcount.h similarity index 74% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/refcount.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/refcount.h index ac348ebb4c6..03b4b87ac31 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/refcount.h +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/refcount.h @@ -16,6 +16,7 @@ #include "bh_platform.h" #include "locking.h" +#include "gnuc.h" #define PRODUCES(...) LOCKS_SHARED(__VA_ARGS__) NO_LOCK_ANALYSIS #define CONSUMES(...) UNLOCKS(__VA_ARGS__) NO_LOCK_ANALYSIS @@ -95,6 +96,42 @@ refcount_release(struct refcount *r) return old == 1; } +#elif defined(__GNUC_PREREQ) + +#if __GNUC_PREREQ(4, 7) + +struct refcount { + unsigned int count; +}; + +/* Initialize the reference counter. */ +static inline void +refcount_init(struct refcount *r, unsigned int count) +{ + __atomic_store_n(&r->count, count, __ATOMIC_SEQ_CST); +} + +/* Increment the reference counter. */ +static inline void +refcount_acquire(struct refcount *r) +{ + __atomic_fetch_add(&r->count, 1, __ATOMIC_ACQUIRE); +} + +/* Decrement the reference counter, returning whether the reference + dropped to zero. */ +static inline bool +refcount_release(struct refcount *r) +{ + int old = (int)__atomic_fetch_sub(&r->count, 1, __ATOMIC_RELEASE); + bh_assert(old != 0 && "Reference count becoming negative"); + return old == 1; +} + +#else /* else of __GNUC_PREREQ (4.7) */ +#error "Reference counter isn't implemented" +#endif /* end of __GNUC_PREREQ (4.7) */ + #else /* else of CONFIG_HAS_STD_ATOMIC */ #error "Reference counter isn't implemented" #endif /* end of CONFIG_HAS_STD_ATOMIC */ diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/rights.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/rights.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/rights.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/rights.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/ssp_config.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/ssp_config.h similarity index 73% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/ssp_config.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/ssp_config.h index 68b0faf345d..7f6e9b94192 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/ssp_config.h +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/ssp_config.h @@ -14,6 +14,7 @@ #ifndef SSP_CONFIG_H #define SSP_CONFIG_H +#include "gnuc.h" #include #if defined(__FreeBSD__) || defined(__APPLE__) \ @@ -40,7 +41,7 @@ #endif #if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__EMSCRIPTEN__) \ - && !defined(ESP_PLATFORM) + && !defined(ESP_PLATFORM) && !defined(DISABLE_CLOCK_NANOSLEEP) #define CONFIG_HAS_CLOCK_NANOSLEEP 1 #else #define CONFIG_HAS_CLOCK_NANOSLEEP 0 @@ -107,10 +108,31 @@ #endif #if !defined(BH_PLATFORM_LINUX_SGX) +/* Clang's __GNUC_PREREQ macro has a different meaning than GCC one, +so we have to handle this case specially */ +#if defined(__clang__) +/* Clang provides stdatomic.h since 3.6.0 +See https://releases.llvm.org/3.6.0/tools/clang/docs/ReleaseNotes.html */ +#if __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 6) #define CONFIG_HAS_STD_ATOMIC 1 #else #define CONFIG_HAS_STD_ATOMIC 0 #endif +#elif defined(__GNUC_PREREQ) +/* Even though older versions of GCC support C11, atomics were +not implemented until 4.9. See +https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58016 */ +#if __GNUC_PREREQ(4, 9) +#define CONFIG_HAS_STD_ATOMIC 1 +#else /* else of __GNUC_PREREQ(4, 9) */ +#define CONFIG_HAS_STD_ATOMIC 0 +#endif /* end of __GNUC_PREREQ(4, 9) */ +#else /* else of defined(__GNUC_PREREQ) */ +#define CONFIG_HAS_STD_ATOMIC 1 +#endif /* end of defined(__GNUC_PREREQ) */ +#else /* else of !defined(BH_PLATFORM_LINUX_SGX) */ +#define CONFIG_HAS_STD_ATOMIC 0 +#endif /* end of !defined(BH_PLATFORM_LINUX_SGX) */ #if !defined(__NuttX__) #define CONFIG_HAS_D_INO 1 diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/str.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/str.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/str.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/str.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/str.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/str.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/str.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/str.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/thread-mgr/SConscript b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/thread-mgr/SConscript similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/thread-mgr/SConscript rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/thread-mgr/SConscript diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/thread-mgr/thread_manager.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/thread-mgr/thread_manager.c similarity index 60% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/thread-mgr/thread_manager.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/thread-mgr/thread_manager.c index 2e15ac54e3f..9303eb3f5e2 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/thread-mgr/thread_manager.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/thread-mgr/thread_manager.c @@ -16,6 +16,10 @@ #include "debug_engine.h" #endif +#if WASM_ENABLE_SHARED_MEMORY != 0 +#include "wasm_shared_memory.h" +#endif + typedef struct { bh_list_link l; void (*destroy_cb)(WASMCluster *); @@ -76,9 +80,76 @@ traverse_list(bh_list *l, list_visitor visitor, void *user_data) } } +/* Assumes cluster->lock is locked */ +static bool +safe_traverse_exec_env_list(WASMCluster *cluster, list_visitor visitor, + void *user_data) +{ + Vector proc_nodes; + void *node; + bool ret = true; + + if (!bh_vector_init(&proc_nodes, cluster->exec_env_list.len, sizeof(void *), + false)) { + ret = false; + goto final; + } + + node = bh_list_first_elem(&cluster->exec_env_list); + + while (node) { + bool already_processed = false; + void *proc_node; + uint32 i; + for (i = 0; i < (uint32)bh_vector_size(&proc_nodes); i++) { + if (!bh_vector_get(&proc_nodes, i, &proc_node)) { + ret = false; + goto final; + } + if (proc_node == node) { + already_processed = true; + break; + } + } + if (already_processed) { + node = bh_list_elem_next(node); + continue; + } + + os_mutex_unlock(&cluster->lock); + visitor(node, user_data); + os_mutex_lock(&cluster->lock); + if (!bh_vector_append(&proc_nodes, &node)) { + ret = false; + goto final; + } + + node = bh_list_first_elem(&cluster->exec_env_list); + } + +final: + bh_vector_destroy(&proc_nodes); + + return ret; +} + +/* The caller must lock cluster->lock */ static bool -allocate_aux_stack(WASMCluster *cluster, uint32 *start, uint32 *size) +allocate_aux_stack(WASMExecEnv *exec_env, uint32 *start, uint32 *size) { + WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env); +#if WASM_ENABLE_HEAP_AUX_STACK_ALLOCATION != 0 + WASMModuleInstanceCommon *module_inst = + wasm_exec_env_get_module_inst(exec_env); + uint32 stack_end; + + stack_end = wasm_runtime_module_malloc_internal(module_inst, exec_env, + cluster->stack_size, NULL); + *start = stack_end + cluster->stack_size; + *size = cluster->stack_size; + + return stack_end != 0; +#else uint32 i; /* If the module doesn't have aux stack info, @@ -86,7 +157,6 @@ allocate_aux_stack(WASMCluster *cluster, uint32 *start, uint32 *size) if (!cluster->stack_segment_occupied) return false; - os_mutex_lock(&cluster->lock); for (i = 0; i < cluster_max_thread_num; i++) { if (!cluster->stack_segment_occupied[i]) { if (start) @@ -94,36 +164,52 @@ allocate_aux_stack(WASMCluster *cluster, uint32 *start, uint32 *size) if (size) *size = cluster->stack_size; cluster->stack_segment_occupied[i] = true; - os_mutex_unlock(&cluster->lock); return true; } } - os_mutex_unlock(&cluster->lock); + return false; +#endif } +/* The caller must lock cluster->lock */ static bool -free_aux_stack(WASMCluster *cluster, uint32 start) +free_aux_stack(WASMExecEnv *exec_env, uint32 start) { + WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env); + +#if WASM_ENABLE_HEAP_AUX_STACK_ALLOCATION != 0 + WASMModuleInstanceCommon *module_inst = + wasm_exec_env_get_module_inst(exec_env); + + if (!wasm_exec_env_is_aux_stack_managed_by_runtime(exec_env)) { + return true; + } + + bh_assert(start >= cluster->stack_size); + + wasm_runtime_module_free_internal(module_inst, exec_env, + start - cluster->stack_size); + + return true; +#else uint32 i; for (i = 0; i < cluster_max_thread_num; i++) { if (start == cluster->stack_tops[i]) { - os_mutex_lock(&cluster->lock); cluster->stack_segment_occupied[i] = false; - os_mutex_unlock(&cluster->lock); return true; } } return false; +#endif } WASMCluster * wasm_cluster_create(WASMExecEnv *exec_env) { WASMCluster *cluster; - uint64 total_size; - uint32 aux_stack_start, aux_stack_size, i; + uint32 aux_stack_start, aux_stack_size; bh_assert(exec_env->cluster == NULL); if (!(cluster = wasm_runtime_malloc(sizeof(WASMCluster)))) { @@ -145,7 +231,9 @@ wasm_cluster_create(WASMExecEnv *exec_env) /* Prepare the aux stack top and size for every thread */ if (!wasm_exec_env_get_aux_stack(exec_env, &aux_stack_start, &aux_stack_size)) { +#if WASM_ENABLE_LIB_WASI_THREADS == 0 LOG_VERBOSE("No aux stack info for this module, can't create thread"); +#endif /* If the module don't have aux stack info, don't throw error here, but remain stack_tops and stack_segment_occupied as NULL */ @@ -159,12 +247,16 @@ wasm_cluster_create(WASMExecEnv *exec_env) return cluster; } +#if WASM_ENABLE_HEAP_AUX_STACK_ALLOCATION != 0 + cluster->stack_size = aux_stack_size; +#else cluster->stack_size = aux_stack_size / (cluster_max_thread_num + 1); if (cluster->stack_size < WASM_THREAD_AUX_STACK_SIZE_MIN) { goto fail; } /* Make stack size 16-byte aligned */ cluster->stack_size = cluster->stack_size & (~15); +#endif /* Set initial aux stack top to the instance and aux stack boundary to the main exec_env */ @@ -172,8 +264,10 @@ wasm_cluster_create(WASMExecEnv *exec_env) cluster->stack_size)) goto fail; +#if WASM_ENABLE_HEAP_AUX_STACK_ALLOCATION == 0 if (cluster_max_thread_num != 0) { - total_size = cluster_max_thread_num * sizeof(uint32); + uint64 total_size = cluster_max_thread_num * sizeof(uint32); + uint32 i; if (total_size >= UINT32_MAX || !(cluster->stack_tops = wasm_runtime_malloc((uint32)total_size))) { @@ -195,6 +289,7 @@ wasm_cluster_create(WASMExecEnv *exec_env) cluster->stack_tops[i] = aux_stack_start - cluster->stack_size * i; } } +#endif os_mutex_lock(&cluster_list_lock); if (bh_list_insert(cluster_list, cluster) != 0) { @@ -234,10 +329,12 @@ wasm_cluster_destroy(WASMCluster *cluster) os_mutex_destroy(&cluster->lock); +#if WASM_ENABLE_HEAP_AUX_STACK_ALLOCATION == 0 if (cluster->stack_tops) wasm_runtime_free(cluster->stack_tops); if (cluster->stack_segment_occupied) wasm_runtime_free(cluster->stack_segment_occupied); +#endif #if WASM_ENABLE_DEBUG_INTERP != 0 wasm_debug_instance_destroy(cluster); @@ -265,22 +362,29 @@ wasm_exec_env_get_cluster(WASMExecEnv *exec_env) return exec_env->cluster; } -bool +/* The caller must lock cluster->lock */ +static bool wasm_cluster_add_exec_env(WASMCluster *cluster, WASMExecEnv *exec_env) { bool ret = true; exec_env->cluster = cluster; - os_mutex_lock(&cluster->lock); - if (bh_list_insert(&cluster->exec_env_list, exec_env) != 0) + if (cluster->exec_env_list.len == cluster_max_thread_num + 1) { + LOG_ERROR("thread manager error: " + "maximum number of threads exceeded"); ret = false; - os_mutex_unlock(&cluster->lock); + } + + if (ret && bh_list_insert(&cluster->exec_env_list, exec_env) != 0) + ret = false; + return ret; } -bool -wasm_cluster_del_exec_env(WASMCluster *cluster, WASMExecEnv *exec_env) +static bool +wasm_cluster_del_exec_env_internal(WASMCluster *cluster, WASMExecEnv *exec_env, + bool can_destroy_cluster) { bool ret = true; bh_assert(exec_env->cluster == cluster); @@ -293,25 +397,36 @@ wasm_cluster_del_exec_env(WASMCluster *cluster, WASMExecEnv *exec_env) other threads can't fire stop events */ os_mutex_lock(&cluster->debug_inst->wait_lock); while (cluster->debug_inst->stopped_thread == exec_env) { - os_cond_wait(&cluster->debug_inst->wait_cond, - &cluster->debug_inst->wait_lock); + /* either wakes up by signal or by 1-second timeout */ + os_cond_reltimedwait(&cluster->debug_inst->wait_cond, + &cluster->debug_inst->wait_lock, 1000000); } os_mutex_unlock(&cluster->debug_inst->wait_lock); } #endif - - os_mutex_lock(&cluster->lock); if (bh_list_remove(&cluster->exec_env_list, exec_env) != 0) ret = false; - os_mutex_unlock(&cluster->lock); - if (cluster->exec_env_list.len == 0) { - /* exec_env_list empty, destroy the cluster */ - wasm_cluster_destroy(cluster); + if (can_destroy_cluster) { + if (cluster->exec_env_list.len == 0) { + /* exec_env_list empty, destroy the cluster */ + wasm_cluster_destroy(cluster); + } } + else { + /* Don't destroy cluster as cluster->lock is being used */ + } + return ret; } +/* The caller should lock cluster->lock for thread safety */ +bool +wasm_cluster_del_exec_env(WASMCluster *cluster, WASMExecEnv *exec_env) +{ + return wasm_cluster_del_exec_env_internal(cluster, exec_env, true); +} + static WASMExecEnv * wasm_cluster_search_exec_env(WASMCluster *cluster, WASMModuleInstanceCommon *module_inst) @@ -373,6 +488,12 @@ wasm_cluster_spawn_exec_env(WASMExecEnv *exec_env) return NULL; } + os_mutex_lock(&cluster->lock); + + if (cluster->has_exception || cluster->processing) { + goto fail1; + } + #if WASM_ENABLE_INTERP != 0 if (module_inst->module_type == Wasm_Module_Bytecode) { stack_size = @@ -388,8 +509,8 @@ wasm_cluster_spawn_exec_env(WASMExecEnv *exec_env) #endif if (!(new_module_inst = wasm_runtime_instantiate_internal( - module, true, stack_size, 0, NULL, 0))) { - return NULL; + module, true, exec_env, stack_size, 0, NULL, 0))) { + goto fail1; } /* Set custom_data to new module instance */ @@ -404,32 +525,39 @@ wasm_cluster_spawn_exec_env(WASMExecEnv *exec_env) new_exec_env = wasm_exec_env_create_internal(new_module_inst, exec_env->wasm_stack_size); if (!new_exec_env) - goto fail1; + goto fail2; - if (!allocate_aux_stack(cluster, &aux_stack_start, &aux_stack_size)) { + if (!allocate_aux_stack(exec_env, &aux_stack_start, &aux_stack_size)) { LOG_ERROR("thread manager error: " "failed to allocate aux stack space for new thread"); - goto fail2; + goto fail3; } /* Set aux stack for current thread */ if (!wasm_exec_env_set_aux_stack(new_exec_env, aux_stack_start, aux_stack_size)) { - goto fail3; + goto fail4; } + /* Inherit suspend_flags of parent thread */ + new_exec_env->suspend_flags.flags = exec_env->suspend_flags.flags; + if (!wasm_cluster_add_exec_env(cluster, new_exec_env)) - goto fail3; + goto fail4; + + os_mutex_unlock(&cluster->lock); return new_exec_env; -fail3: +fail4: /* free the allocated aux stack space */ - free_aux_stack(cluster, aux_stack_start); + free_aux_stack(exec_env, aux_stack_start); +fail3: + wasm_exec_env_destroy_internal(new_exec_env); fail2: - wasm_exec_env_destroy(new_exec_env); -fail1: wasm_runtime_deinstantiate_internal(new_module_inst, true); +fail1: + os_mutex_unlock(&cluster->lock); return NULL; } @@ -441,12 +569,18 @@ wasm_cluster_destroy_spawned_exec_env(WASMExecEnv *exec_env) wasm_module_inst_t module_inst = wasm_runtime_get_module_inst(exec_env); bh_assert(cluster != NULL); + os_mutex_lock(&cluster->lock); + /* Free aux stack space */ - free_aux_stack(cluster, exec_env->aux_stack_bottom.bottom); - wasm_cluster_del_exec_env(cluster, exec_env); + free_aux_stack(exec_env, exec_env->aux_stack_bottom.bottom); + /* Remove exec_env */ + wasm_cluster_del_exec_env_internal(cluster, exec_env, false); + /* Destroy exec_env */ wasm_exec_env_destroy_internal(exec_env); - + /* Routine exit, destroy instance */ wasm_runtime_deinstantiate_internal(module_inst, true); + + os_mutex_unlock(&cluster->lock); } /* start routine of thread manager */ @@ -456,27 +590,59 @@ thread_manager_start_routine(void *arg) void *ret; WASMExecEnv *exec_env = (WASMExecEnv *)arg; WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env); + WASMModuleInstanceCommon *module_inst = + wasm_exec_env_get_module_inst(exec_env); + bh_assert(cluster != NULL); + bh_assert(module_inst != NULL); + os_mutex_lock(&exec_env->wait_lock); exec_env->handle = os_self_thread(); + /* Notify the parent thread to continue running */ + os_cond_signal(&exec_env->wait_cond); + os_mutex_unlock(&exec_env->wait_lock); + ret = exec_env->thread_start_routine(exec_env); #ifdef OS_ENABLE_HW_BOUND_CHECK + os_mutex_lock(&exec_env->wait_lock); if (exec_env->suspend_flags.flags & 0x08) ret = exec_env->thread_ret_value; + os_mutex_unlock(&exec_env->wait_lock); #endif /* Routine exit */ - /* Free aux stack space */ - free_aux_stack(cluster, exec_env->aux_stack_bottom.bottom); - /* Detach the native thread here to ensure the resources are freed */ - wasm_cluster_detach_thread(exec_env); + #if WASM_ENABLE_DEBUG_INTERP != 0 wasm_cluster_thread_exited(exec_env); #endif - /* Remove and destroy exec_env */ - wasm_cluster_del_exec_env(cluster, exec_env); + + os_mutex_lock(&cluster_list_lock); + + os_mutex_lock(&cluster->lock); + + /* Detach the native thread here to ensure the resources are freed */ + if (exec_env->wait_count == 0 && !exec_env->thread_is_detached) { + /* Only detach current thread when there is no other thread + joining it, otherwise let the system resources for the + thread be released after joining */ + os_thread_detach(exec_env->handle); + /* No need to set exec_env->thread_is_detached to true here + since we will exit soon */ + } + + /* Free aux stack space */ + free_aux_stack(exec_env, exec_env->aux_stack_bottom.bottom); + /* Remove exec_env */ + wasm_cluster_del_exec_env_internal(cluster, exec_env, false); + /* Destroy exec_env */ wasm_exec_env_destroy_internal(exec_env); + /* Routine exit, destroy instance */ + wasm_runtime_deinstantiate_internal(module_inst, true); + + os_mutex_unlock(&cluster->lock); + + os_mutex_unlock(&cluster_list_lock); os_thread_exit(ret); return ret; @@ -484,59 +650,138 @@ thread_manager_start_routine(void *arg) int32 wasm_cluster_create_thread(WASMExecEnv *exec_env, - wasm_module_inst_t module_inst, + wasm_module_inst_t module_inst, bool alloc_aux_stack, void *(*thread_routine)(void *), void *arg) { WASMCluster *cluster; WASMExecEnv *new_exec_env; - uint32 aux_stack_start, aux_stack_size; + uint32 aux_stack_start = 0, aux_stack_size; korp_tid tid; cluster = wasm_exec_env_get_cluster(exec_env); bh_assert(cluster); + os_mutex_lock(&cluster->lock); + + if (cluster->has_exception || cluster->processing) { + goto fail1; + } + new_exec_env = wasm_exec_env_create_internal(module_inst, exec_env->wasm_stack_size); if (!new_exec_env) - return -1; - - if (!allocate_aux_stack(cluster, &aux_stack_start, &aux_stack_size)) { - LOG_ERROR("thread manager error: " - "failed to allocate aux stack space for new thread"); goto fail1; - } - /* Set aux stack for current thread */ - if (!wasm_exec_env_set_aux_stack(new_exec_env, aux_stack_start, - aux_stack_size)) { - goto fail2; + if (alloc_aux_stack) { + if (!allocate_aux_stack(exec_env, &aux_stack_start, &aux_stack_size)) { + LOG_ERROR("thread manager error: " + "failed to allocate aux stack space for new thread"); + goto fail2; + } + + /* Set aux stack for current thread */ + if (!wasm_exec_env_set_aux_stack(new_exec_env, aux_stack_start, + aux_stack_size)) { + goto fail3; + } + } + else { + /* Disable aux stack */ + new_exec_env->aux_stack_boundary.boundary = 0; + new_exec_env->aux_stack_bottom.bottom = UINT32_MAX; } + /* Inherit suspend_flags of parent thread */ + new_exec_env->suspend_flags.flags = exec_env->suspend_flags.flags; + if (!wasm_cluster_add_exec_env(cluster, new_exec_env)) - goto fail2; + goto fail3; new_exec_env->thread_start_routine = thread_routine; new_exec_env->thread_arg = arg; + os_mutex_lock(&new_exec_env->wait_lock); + if (0 != os_thread_create(&tid, thread_manager_start_routine, (void *)new_exec_env, APP_THREAD_STACK_SIZE_DEFAULT)) { - goto fail3; + os_mutex_unlock(&new_exec_env->wait_lock); + goto fail4; } + /* Wait until the new_exec_env->handle is set to avoid it is + illegally accessed after unlocking cluster->lock */ + os_cond_wait(&new_exec_env->wait_cond, &new_exec_env->wait_lock); + os_mutex_unlock(&new_exec_env->wait_lock); + + os_mutex_unlock(&cluster->lock); + return 0; +fail4: + wasm_cluster_del_exec_env_internal(cluster, new_exec_env, false); fail3: - wasm_cluster_del_exec_env(cluster, new_exec_env); -fail2: /* free the allocated aux stack space */ - free_aux_stack(cluster, aux_stack_start); + if (alloc_aux_stack) + free_aux_stack(exec_env, aux_stack_start); +fail2: + wasm_exec_env_destroy_internal(new_exec_env); fail1: - wasm_exec_env_destroy(new_exec_env); + os_mutex_unlock(&cluster->lock); + return -1; } +bool +wasm_cluster_dup_c_api_imports(WASMModuleInstanceCommon *module_inst_dst, + const WASMModuleInstanceCommon *module_inst_src) +{ + /* workaround about passing instantiate-linking information */ + CApiFuncImport **new_c_api_func_imports = NULL; + CApiFuncImport *c_api_func_imports; + uint32 import_func_count = 0; + uint32 size_in_bytes = 0; + +#if WASM_ENABLE_INTERP != 0 + if (module_inst_src->module_type == Wasm_Module_Bytecode) { + new_c_api_func_imports = + &(((WASMModuleInstance *)module_inst_dst)->e->c_api_func_imports); + c_api_func_imports = ((const WASMModuleInstance *)module_inst_src) + ->e->c_api_func_imports; + import_func_count = + ((WASMModule *)(((const WASMModuleInstance *)module_inst_src) + ->module)) + ->import_function_count; + } +#endif +#if WASM_ENABLE_AOT != 0 + if (module_inst_src->module_type == Wasm_Module_AoT) { + AOTModuleInstanceExtra *e = + (AOTModuleInstanceExtra *)((AOTModuleInstance *)module_inst_dst)->e; + new_c_api_func_imports = &(e->c_api_func_imports); + + e = (AOTModuleInstanceExtra *)((AOTModuleInstance *)module_inst_src)->e; + c_api_func_imports = e->c_api_func_imports; + + import_func_count = + ((AOTModule *)(((AOTModuleInstance *)module_inst_src)->module)) + ->import_func_count; + } +#endif + + if (import_func_count != 0 && c_api_func_imports) { + size_in_bytes = sizeof(CApiFuncImport) * import_func_count; + *new_c_api_func_imports = wasm_runtime_malloc(size_in_bytes); + if (!(*new_c_api_func_imports)) + return false; + + bh_memcpy_s(*new_c_api_func_imports, size_in_bytes, c_api_func_imports, + size_in_bytes); + } + return true; +} + #if WASM_ENABLE_DEBUG_INTERP != 0 WASMCurrentEnvStatus * wasm_cluster_create_exenv_status() @@ -593,21 +838,30 @@ notify_debug_instance(WASMExecEnv *exec_env) on_thread_stop_event(cluster->debug_inst, exec_env); } -void -wasm_cluster_thread_stopped(WASMExecEnv *exec_env) +static void +notify_debug_instance_exit(WASMExecEnv *exec_env) { - exec_env->current_status->running_status = STATUS_STOP; - notify_debug_instance(exec_env); + WASMCluster *cluster; + + cluster = wasm_exec_env_get_cluster(exec_env); + bh_assert(cluster); + + if (!cluster->debug_inst) { + return; + } + + on_thread_exit_event(cluster->debug_inst, exec_env); } void wasm_cluster_thread_waiting_run(WASMExecEnv *exec_env) { - os_mutex_lock(&exec_env->wait_lock); + exec_env->current_status->running_status = STATUS_STOP; + notify_debug_instance(exec_env); + while (!wasm_cluster_thread_is_running(exec_env)) { os_cond_wait(&exec_env->wait_cond, &exec_env->wait_lock); } - os_mutex_unlock(&exec_env->wait_lock); } void @@ -624,22 +878,26 @@ void wasm_cluster_thread_exited(WASMExecEnv *exec_env) { exec_env->current_status->running_status = STATUS_EXIT; - notify_debug_instance(exec_env); + notify_debug_instance_exit(exec_env); } void wasm_cluster_thread_continue(WASMExecEnv *exec_env) { + os_mutex_lock(&exec_env->wait_lock); wasm_cluster_clear_thread_signal(exec_env); exec_env->current_status->running_status = STATUS_RUNNING; os_cond_signal(&exec_env->wait_cond); + os_mutex_unlock(&exec_env->wait_lock); } void wasm_cluster_thread_step(WASMExecEnv *exec_env) { + os_mutex_lock(&exec_env->wait_lock); exec_env->current_status->running_status = STATUS_STEP; os_cond_signal(&exec_env->wait_cond); + os_mutex_unlock(&exec_env->wait_lock); } void @@ -659,15 +917,18 @@ clusters_have_exec_env(WASMExecEnv *exec_env) WASMExecEnv *node; while (cluster) { + os_mutex_lock(&cluster->lock); node = bh_list_first_elem(&cluster->exec_env_list); while (node) { if (node == exec_env) { bh_assert(exec_env->cluster == cluster); + os_mutex_unlock(&cluster->lock); return true; } node = bh_list_elem_next(node); } + os_mutex_unlock(&cluster->lock); cluster = bh_list_elem_next(cluster); } @@ -681,6 +942,7 @@ wasm_cluster_join_thread(WASMExecEnv *exec_env, void **ret_val) korp_tid handle; os_mutex_lock(&cluster_list_lock); + if (!clusters_have_exec_env(exec_env) || exec_env->thread_is_detached) { /* Invalid thread, thread has exited or thread has been detached */ if (ret_val) @@ -688,9 +950,14 @@ wasm_cluster_join_thread(WASMExecEnv *exec_env, void **ret_val) os_mutex_unlock(&cluster_list_lock); return 0; } + + os_mutex_lock(&exec_env->wait_lock); exec_env->wait_count++; handle = exec_env->handle; + os_mutex_unlock(&exec_env->wait_lock); + os_mutex_unlock(&cluster_list_lock); + return os_thread_join(handle, ret_val); } @@ -720,6 +987,7 @@ void wasm_cluster_exit_thread(WASMExecEnv *exec_env, void *retval) { WASMCluster *cluster; + WASMModuleInstanceCommon *module_inst; #ifdef OS_ENABLE_HW_BOUND_CHECK if (exec_env->jmpbuf_stack_top) { @@ -744,35 +1012,74 @@ wasm_cluster_exit_thread(WASMExecEnv *exec_env, void *retval) wasm_cluster_clear_thread_signal(exec_env); wasm_cluster_thread_exited(exec_env); #endif + /* App exit the thread, free the resources before exit native thread */ - /* Free aux stack space */ - free_aux_stack(cluster, exec_env->aux_stack_bottom.bottom); + + os_mutex_lock(&cluster_list_lock); + + os_mutex_lock(&cluster->lock); + /* Detach the native thread here to ensure the resources are freed */ - wasm_cluster_detach_thread(exec_env); - /* Remove and destroy exec_env */ - wasm_cluster_del_exec_env(cluster, exec_env); + if (exec_env->wait_count == 0 && !exec_env->thread_is_detached) { + /* Only detach current thread when there is no other thread + joining it, otherwise let the system resources for the + thread be released after joining */ + os_thread_detach(exec_env->handle); + /* No need to set exec_env->thread_is_detached to true here + since we will exit soon */ + } + + module_inst = exec_env->module_inst; + + /* Free aux stack space */ + free_aux_stack(exec_env, exec_env->aux_stack_bottom.bottom); + /* Remove exec_env */ + wasm_cluster_del_exec_env_internal(cluster, exec_env, false); + /* Destroy exec_env */ wasm_exec_env_destroy_internal(exec_env); + /* Routine exit, destroy instance */ + wasm_runtime_deinstantiate_internal(module_inst, true); + + os_mutex_unlock(&cluster->lock); + + os_mutex_unlock(&cluster_list_lock); os_thread_exit(retval); } +static void +set_thread_cancel_flags(WASMExecEnv *exec_env) +{ + os_mutex_lock(&exec_env->wait_lock); + +#if WASM_ENABLE_DEBUG_INTERP != 0 + wasm_cluster_thread_send_signal(exec_env, WAMR_SIG_TERM); +#endif + exec_env->suspend_flags.flags |= 0x01; + + os_mutex_unlock(&exec_env->wait_lock); +} + int32 wasm_cluster_cancel_thread(WASMExecEnv *exec_env) { os_mutex_lock(&cluster_list_lock); - if (!clusters_have_exec_env(exec_env)) { - /* Invalid thread or the thread has exited */ + + if (!exec_env->cluster) { os_mutex_unlock(&cluster_list_lock); return 0; } + + if (!clusters_have_exec_env(exec_env)) { + /* Invalid thread or the thread has exited */ + goto final; + } + + set_thread_cancel_flags(exec_env); + +final: os_mutex_unlock(&cluster_list_lock); - /* Set the termination flag */ -#if WASM_ENABLE_DEBUG_INTERP != 0 - wasm_cluster_thread_send_signal(exec_env, WAMR_SIG_TERM); -#else - exec_env->suspend_flags.flags |= 0x01; -#endif return 0; } @@ -792,15 +1099,27 @@ terminate_thread_visitor(void *node, void *user_data) void wasm_cluster_terminate_all(WASMCluster *cluster) { - traverse_list(&cluster->exec_env_list, terminate_thread_visitor, NULL); + os_mutex_lock(&cluster->lock); + cluster->processing = true; + + safe_traverse_exec_env_list(cluster, terminate_thread_visitor, NULL); + + cluster->processing = false; + os_mutex_unlock(&cluster->lock); } void wasm_cluster_terminate_all_except_self(WASMCluster *cluster, WASMExecEnv *exec_env) { - traverse_list(&cluster->exec_env_list, terminate_thread_visitor, - (void *)exec_env); + os_mutex_lock(&cluster->lock); + cluster->processing = true; + + safe_traverse_exec_env_list(cluster, terminate_thread_visitor, + (void *)exec_env); + + cluster->processing = false; + os_mutex_unlock(&cluster->lock); } static void @@ -818,15 +1137,27 @@ wait_for_thread_visitor(void *node, void *user_data) void wams_cluster_wait_for_all(WASMCluster *cluster) { - traverse_list(&cluster->exec_env_list, wait_for_thread_visitor, NULL); + os_mutex_lock(&cluster->lock); + cluster->processing = true; + + safe_traverse_exec_env_list(cluster, wait_for_thread_visitor, NULL); + + cluster->processing = false; + os_mutex_unlock(&cluster->lock); } void wasm_cluster_wait_for_all_except_self(WASMCluster *cluster, WASMExecEnv *exec_env) { - traverse_list(&cluster->exec_env_list, wait_for_thread_visitor, - (void *)exec_env); + os_mutex_lock(&cluster->lock); + cluster->processing = true; + + safe_traverse_exec_env_list(cluster, wait_for_thread_visitor, + (void *)exec_env); + + cluster->processing = false; + os_mutex_unlock(&cluster->lock); } bool @@ -865,15 +1196,19 @@ suspend_thread_visitor(void *node, void *user_data) void wasm_cluster_suspend_all(WASMCluster *cluster) { + os_mutex_lock(&cluster->lock); traverse_list(&cluster->exec_env_list, suspend_thread_visitor, NULL); + os_mutex_unlock(&cluster->lock); } void wasm_cluster_suspend_all_except_self(WASMCluster *cluster, WASMExecEnv *exec_env) { + os_mutex_lock(&cluster->lock); traverse_list(&cluster->exec_env_list, suspend_thread_visitor, (void *)exec_env); + os_mutex_unlock(&cluster->lock); } void @@ -894,7 +1229,9 @@ resume_thread_visitor(void *node, void *user_data) void wasm_cluster_resume_all(WASMCluster *cluster) { + os_mutex_lock(&cluster->lock); traverse_list(&cluster->exec_env_list, resume_thread_visitor, NULL); + os_mutex_unlock(&cluster->lock); } static void @@ -903,24 +1240,71 @@ set_exception_visitor(void *node, void *user_data) WASMExecEnv *curr_exec_env = (WASMExecEnv *)node; WASMExecEnv *exec_env = (WASMExecEnv *)user_data; WASMModuleInstanceCommon *module_inst = get_module_inst(exec_env); - WASMModuleInstanceCommon *curr_module_inst = get_module_inst(curr_exec_env); - const char *exception = wasm_runtime_get_exception(module_inst); - /* skip "Exception: " */ - exception += 11; + WASMModuleInstance *wasm_inst = (WASMModuleInstance *)module_inst; + + if (curr_exec_env != exec_env) { + WASMModuleInstance *curr_wasm_inst = + (WASMModuleInstance *)get_module_inst(curr_exec_env); + + /* 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); +#endif + if (!strstr(wasm_inst->cur_exception, "wasi proc exit")) { + bh_memcpy_s(curr_wasm_inst->cur_exception, + sizeof(curr_wasm_inst->cur_exception), + wasm_inst->cur_exception, + sizeof(wasm_inst->cur_exception)); + } +#if WASM_ENABLE_SHARED_MEMORY != 0 + if (shared_mem_node) + os_mutex_unlock(&shared_mem_node->shared_mem_lock); +#endif + + /* Terminate the thread so it can exit from dead loops */ + set_thread_cancel_flags(curr_exec_env); + } +} + +static void +clear_exception_visitor(void *node, void *user_data) +{ + WASMExecEnv *exec_env = (WASMExecEnv *)user_data; + WASMExecEnv *curr_exec_env = (WASMExecEnv *)node; if (curr_exec_env != exec_env) { - curr_module_inst = get_module_inst(curr_exec_env); - wasm_runtime_set_exception(curr_module_inst, exception); + WASMModuleInstance *curr_wasm_inst = + (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); +#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); +#endif } } void -wasm_cluster_spread_exception(WASMExecEnv *exec_env) +wasm_cluster_spread_exception(WASMExecEnv *exec_env, bool clear) { WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env); bh_assert(cluster); - traverse_list(&cluster->exec_env_list, set_exception_visitor, exec_env); + os_mutex_lock(&cluster->lock); + cluster->has_exception = !clear; + traverse_list(&cluster->exec_env_list, + clear ? clear_exception_visitor : set_exception_visitor, + exec_env); + os_mutex_unlock(&cluster->lock); } static void @@ -948,7 +1332,20 @@ wasm_cluster_spread_custom_data(WASMModuleInstanceCommon *module_inst, cluster = wasm_exec_env_get_cluster(exec_env); bh_assert(cluster); + os_mutex_lock(&cluster->lock); traverse_list(&cluster->exec_env_list, set_custom_data_visitor, custom_data); + os_mutex_unlock(&cluster->lock); } } + +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; + os_mutex_unlock(&exec_env->wait_lock); + + return is_thread_terminated; +} diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/thread-mgr/thread_manager.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/thread-mgr/thread_manager.h similarity index 77% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/thread-mgr/thread_manager.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/thread-mgr/thread_manager.h index c84d3c02194..2060869c280 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/thread-mgr/thread_manager.h +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/thread-mgr/thread_manager.h @@ -26,14 +26,28 @@ struct WASMCluster { korp_mutex lock; bh_list exec_env_list; +#if WASM_ENABLE_HEAP_AUX_STACK_ALLOCATION == 0 /* The aux stack of a module with shared memory will be divided into several segments. This array store the stack top of different segments */ uint32 *stack_tops; - /* Size of every stack segment */ - uint32 stack_size; /* Record which segments are occupied */ bool *stack_segment_occupied; +#endif + /* Size of every stack segment */ + uint32 stack_size; + /* When has_exception == true, this cluster should refuse any spawn thread + * requests, this flag can be cleared by calling + * wasm_runtime_clear_exception on instances of any threads of this cluster + */ + bool has_exception; + /* When processing is true, this cluster should refuse any spawn thread + * requests. This is a short-lived state, must be cleared immediately once + * the processing finished. + * This is used to avoid dead lock when one thread waiting another thread + * with lock, see wams_cluster_wait_for_all and wasm_cluster_terminate_all + */ + bool processing; #if WASM_ENABLE_DEBUG_INTERP != 0 WASMDebugInstance *debug_inst; #endif @@ -60,9 +74,14 @@ wasm_cluster_destroy(WASMCluster *cluster); WASMCluster * wasm_exec_env_get_cluster(WASMExecEnv *exec_env); +/* Forward registered functions to a new thread */ +bool +wasm_cluster_dup_c_api_imports(WASMModuleInstanceCommon *module_inst_dst, + const WASMModuleInstanceCommon *module_inst_src); + int32 wasm_cluster_create_thread(WASMExecEnv *exec_env, - wasm_module_inst_t module_inst, + wasm_module_inst_t module_inst, bool alloc_aux_stack, void *(*thread_routine)(void *), void *arg); int32 @@ -113,9 +132,6 @@ void wasm_cluster_wait_for_all_except_self(WASMCluster *cluster, WASMExecEnv *exec_env); -bool -wasm_cluster_add_exec_env(WASMCluster *cluster, WASMExecEnv *exec_env); - bool wasm_cluster_del_exec_env(WASMCluster *cluster, WASMExecEnv *exec_env); @@ -123,7 +139,7 @@ WASMExecEnv * wasm_clusters_search_exec_env(WASMModuleInstanceCommon *module_inst); void -wasm_cluster_spread_exception(WASMExecEnv *exec_env); +wasm_cluster_spread_exception(WASMExecEnv *exec_env, bool clear); WASMExecEnv * wasm_cluster_spawn_exec_env(WASMExecEnv *exec_env); @@ -135,6 +151,9 @@ void wasm_cluster_spread_custom_data(WASMModuleInstanceCommon *module_inst, void *custom_data); +bool +wasm_cluster_is_thread_terminated(WASMExecEnv *exec_env); + #if WASM_ENABLE_DEBUG_INTERP != 0 #define WAMR_SIG_TRAP (5) #define WAMR_SIG_STOP (19) @@ -166,9 +185,9 @@ wasm_cluster_destroy_exenv_status(WASMCurrentEnvStatus *status); void wasm_cluster_send_signal_all(WASMCluster *cluster, uint32 signo); -void -wasm_cluster_thread_stopped(WASMExecEnv *exec_env); - +/* This function must be called with exec_env->wait_lock locked, otherwise we + * may miss the signal from debugger thread, see + * https://github.com/bytecodealliance/wasm-micro-runtime/issues/1860 */ void wasm_cluster_thread_waiting_run(WASMExecEnv *exec_env); diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/thread-mgr/thread_mgr.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/thread-mgr/thread_mgr.cmake similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/thread-mgr/thread_mgr.cmake rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/thread-mgr/thread_mgr.cmake diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/README.md b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/README.md new file mode 100644 index 00000000000..ac737c28115 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/README.md @@ -0,0 +1,96 @@ +# WASI-NN + +## How to use + +Enable WASI-NN in the WAMR by spefiying it in the cmake building configuration as follows, + +``` +set (WAMR_BUILD_WASI_NN 1) +``` + +The definition of the functions provided by WASI-NN is in the header file `core/iwasm/libraries/wasi-nn/wasi_nn.h`. + +By only including this file in your WASM application you will bind WASI-NN into your module. + +## Tests + +To run the tests we assume that the current directory is the root of the repository. + + +### Build the runtime + +Build the runtime image for your execution target type. + +`EXECUTION_TYPE` can be: +* `cpu` +* `nvidia-gpu` +* `vx-delegate` + +``` +EXECUTION_TYPE=cpu +docker build -t wasi-nn-${EXECUTION_TYPE} -f core/iwasm/libraries/wasi-nn/test/Dockerfile.${EXECUTION_TYPE} . +``` + + +### Build wasm app + +``` +docker build -t wasi-nn-compile -f core/iwasm/libraries/wasi-nn/test/Dockerfile.compile . +``` + +``` +docker run -v $PWD/core/iwasm/libraries/wasi-nn:/wasi-nn wasi-nn-compile +``` + + +### Run wasm app + +If all the tests have run properly you will the the following message in the terminal, + +``` +Tests: passed! +``` + +* CPU + +``` +docker run \ + -v $PWD/core/iwasm/libraries/wasi-nn/test:/assets wasi-nn-cpu \ + --dir=/assets \ + --env="TARGET=cpu" \ + /assets/test_tensorflow.wasm +``` + +* (NVIDIA) GPU + +``` +docker run \ + --runtime=nvidia \ + -v $PWD/core/iwasm/libraries/wasi-nn/test:/assets wasi-nn-nvidia-gpu \ + --dir=/assets \ + --env="TARGET=gpu" \ + /assets/test_tensorflow.wasm +``` + +* vx-delegate for NPU (x86 simulater) + +``` +docker run \ + -v $PWD/core/iwasm/libraries/wasi-nn/test:/assets wasi-nn-vx-delegate \ + --dir=/assets \ + --env="TARGET=gpu" \ + /assets/test_tensorflow.wasm +``` + + + +Requirements: +* [NVIDIA docker](https://github.com/NVIDIA/nvidia-docker). + +## What is missing + +Supported: + +* Graph encoding: `tensorflowlite`. +* Execution target: `cpu` and `gpu`. +* Tensor type: `fp32`. diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/cmake/Findtensorflow_lite.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/cmake/Findtensorflow_lite.cmake new file mode 100644 index 00000000000..bbeac3b148b --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/cmake/Findtensorflow_lite.cmake @@ -0,0 +1,41 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + + +find_library(TENSORFLOW_LITE + NAMES tensorflow-lite +) + +if(NOT EXISTS ${TENSORFLOW_LITE}) + if (NOT EXISTS "${WAMR_ROOT_DIR}/core/deps/tensorflow-src") + execute_process(COMMAND ${WAMR_ROOT_DIR}/core/deps/install_tensorflow.sh + RESULT_VARIABLE TENSORFLOW_RESULT + ) + else () + message("Tensorflow is already downloaded.") + endif() + set(TENSORFLOW_SOURCE_DIR "${WAMR_ROOT_DIR}/core/deps/tensorflow-src") + + if (WASI_NN_ENABLE_GPU EQUAL 1) + # Tensorflow specific: + # * https://www.tensorflow.org/lite/guide/build_cmake#available_options_to_build_tensorflow_lite + set (TFLITE_ENABLE_GPU ON) + endif () + + include_directories (${CMAKE_CURRENT_BINARY_DIR}/flatbuffers/include) + include_directories (${TENSORFLOW_SOURCE_DIR}) + add_subdirectory( + "${TENSORFLOW_SOURCE_DIR}/tensorflow/lite" + "${CMAKE_CURRENT_BINARY_DIR}/tensorflow-lite" EXCLUDE_FROM_ALL) + +else() + find_path(TENSORFLOW_LITE_INCLUDE_DIR + NAMES tensorflow/lite/interpreter.h + ) + find_path(FLATBUFFER_INCLUDE_DIR + NAMES flatbuffers/flatbuffers.h + ) + include_directories (${TENSORFLOW_LITE_INCLUDE_DIR}) + include_directories (${FLATBUFFER_INCLUDE_DIR}) +endif() + diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/src/utils/logger.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/src/utils/logger.h new file mode 100644 index 00000000000..a196429a079 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/src/utils/logger.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef WASI_NN_LOGGER_H +#define WASI_NN_LOGGER_H + +#include +#include + +#define __FILENAME__ \ + (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) + +/* Disable a level by removing the define */ +#ifndef NN_LOG_LEVEL +/* + 0 -> debug, info, warn, err + 1 -> info, warn, err + 2 -> warn, err + 3 -> err + 4 -> NO LOGS +*/ +#define NN_LOG_LEVEL 0 +#endif + +// Definition of the levels +#if NN_LOG_LEVEL <= 3 +#define NN_ERR_PRINTF(fmt, ...) \ + do { \ + printf("[%s:%d ERROR] " fmt, __FILENAME__, __LINE__, ##__VA_ARGS__); \ + printf("\n"); \ + fflush(stdout); \ + } while (0) +#else +#define NN_ERR_PRINTF(fmt, ...) +#endif +#if NN_LOG_LEVEL <= 2 +#define NN_WARN_PRINTF(fmt, ...) \ + do { \ + printf("[%s:%d WARNING] " fmt, __FILENAME__, __LINE__, ##__VA_ARGS__); \ + printf("\n"); \ + fflush(stdout); \ + } while (0) +#else +#define NN_WARN_PRINTF(fmt, ...) +#endif +#if NN_LOG_LEVEL <= 1 +#define NN_INFO_PRINTF(fmt, ...) \ + do { \ + printf("[%s:%d INFO] " fmt, __FILENAME__, __LINE__, ##__VA_ARGS__); \ + printf("\n"); \ + fflush(stdout); \ + } while (0) +#else +#define NN_INFO_PRINTF(fmt, ...) +#endif +#if NN_LOG_LEVEL <= 0 +#define NN_DBG_PRINTF(fmt, ...) \ + do { \ + printf("[%s:%d DEBUG] " fmt, __FILENAME__, __LINE__, ##__VA_ARGS__); \ + printf("\n"); \ + fflush(stdout); \ + } while (0) +#else +#define NN_DBG_PRINTF(fmt, ...) +#endif + +#endif diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/src/utils/wasi_nn_app_native.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/src/utils/wasi_nn_app_native.c new file mode 100644 index 00000000000..fe04b657bbc --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/src/utils/wasi_nn_app_native.c @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "wasi_nn_app_native.h" + +static error +graph_builder_app_native(wasm_module_inst_t instance, + graph_builder_wasm *builder_wasm, + graph_builder *builder) +{ + if (!wasm_runtime_validate_app_addr(instance, builder_wasm->buf_offset, + builder_wasm->size * sizeof(uint8_t))) { + NN_ERR_PRINTF("builder_wasm->buf_offset is invalid"); + return invalid_argument; + } + + builder->buf = (uint8_t *)wasm_runtime_addr_app_to_native( + instance, builder_wasm->buf_offset); + builder->size = builder_wasm->size; + return success; +} + +error +graph_builder_array_app_native(wasm_module_inst_t instance, + graph_builder_array_wasm *builder_array_wasm, + graph_builder_array *builder_array) +{ + if (!wasm_runtime_validate_native_addr(instance, builder_array_wasm, + sizeof(graph_builder_array_wasm))) { + NN_ERR_PRINTF("builder_array_wasm is invalid"); + return invalid_argument; + } + + NN_DBG_PRINTF("Graph builder array contains %d elements", + builder_array_wasm->size); + + if (!wasm_runtime_validate_app_addr( + instance, builder_array_wasm->buf_offset, + builder_array_wasm->size * sizeof(graph_builder_wasm))) { + NN_ERR_PRINTF("builder_array_wasm->buf_offset is invalid"); + return invalid_argument; + } + + graph_builder_wasm *builder_wasm = + (graph_builder_wasm *)wasm_runtime_addr_app_to_native( + instance, builder_array_wasm->buf_offset); + + graph_builder *builder = (graph_builder *)wasm_runtime_malloc( + builder_array_wasm->size * sizeof(graph_builder)); + if (builder == NULL) + return missing_memory; + + for (uint32_t i = 0; i < builder_array_wasm->size; ++i) { + error res; + if (success + != (res = graph_builder_app_native(instance, &builder_wasm[i], + &builder[i]))) { + wasm_runtime_free(builder); + return res; + } + + NN_DBG_PRINTF("Graph builder %d contains %d elements", i, + builder->size); + } + + builder_array->buf = builder; + builder_array->size = builder_array_wasm->size; + return success; +} + +static error +tensor_data_app_native(wasm_module_inst_t instance, uint32_t total_elements, + tensor_wasm *input_tensor_wasm, tensor_data *data) +{ + if (!wasm_runtime_validate_app_addr( + instance, input_tensor_wasm->data_offset, total_elements)) { + NN_ERR_PRINTF("input_tensor_wasm->data_offset is invalid"); + return invalid_argument; + } + *data = (tensor_data)wasm_runtime_addr_app_to_native( + instance, input_tensor_wasm->data_offset); + return success; +} + +static error +tensor_dimensions_app_native(wasm_module_inst_t instance, + tensor_wasm *input_tensor_wasm, + tensor_dimensions **dimensions) +{ + if (!wasm_runtime_validate_app_addr(instance, + input_tensor_wasm->dimensions_offset, + sizeof(tensor_dimensions_wasm))) { + NN_ERR_PRINTF("input_tensor_wasm->dimensions_offset is invalid"); + return invalid_argument; + } + + tensor_dimensions_wasm *dimensions_wasm = + (tensor_dimensions_wasm *)wasm_runtime_addr_app_to_native( + instance, input_tensor_wasm->dimensions_offset); + + if (!wasm_runtime_validate_app_addr(instance, dimensions_wasm->buf_offset, + sizeof(tensor_dimensions))) { + NN_ERR_PRINTF("dimensions_wasm->buf_offset is invalid"); + return invalid_argument; + } + + *dimensions = + (tensor_dimensions *)wasm_runtime_malloc(sizeof(tensor_dimensions)); + if (dimensions == NULL) + return missing_memory; + + (*dimensions)->size = dimensions_wasm->size; + (*dimensions)->buf = (uint32_t *)wasm_runtime_addr_app_to_native( + instance, dimensions_wasm->buf_offset); + + NN_DBG_PRINTF("Number of dimensions: %d", (*dimensions)->size); + return success; +} + +error +tensor_app_native(wasm_module_inst_t instance, tensor_wasm *input_tensor_wasm, + tensor *input_tensor) +{ + NN_DBG_PRINTF("Converting tensor_wasm to tensor"); + if (!wasm_runtime_validate_native_addr(instance, input_tensor_wasm, + sizeof(tensor_wasm))) { + NN_ERR_PRINTF("input_tensor_wasm is invalid"); + return invalid_argument; + } + + error res; + + tensor_dimensions *dimensions = NULL; + if (success + != (res = tensor_dimensions_app_native(instance, input_tensor_wasm, + &dimensions))) { + NN_ERR_PRINTF("error when parsing dimensions"); + return res; + } + + uint32_t total_elements = 1; + for (uint32_t i = 0; i < dimensions->size; ++i) { + total_elements *= dimensions->buf[i]; + NN_DBG_PRINTF("Dimension %d: %d", i, dimensions->buf[i]); + } + NN_DBG_PRINTF("Tensor type: %d", input_tensor_wasm->type); + NN_DBG_PRINTF("Total number of elements: %d", total_elements); + + tensor_data data = NULL; + if (success + != (res = tensor_data_app_native(instance, total_elements, + input_tensor_wasm, &data))) { + wasm_runtime_free(dimensions); + return res; + } + + input_tensor->type = input_tensor_wasm->type; + input_tensor->dimensions = dimensions; + input_tensor->data = data; + return success; +} diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/src/utils/wasi_nn_app_native.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/src/utils/wasi_nn_app_native.h new file mode 100644 index 00000000000..15154bd310d --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/src/utils/wasi_nn_app_native.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef WASI_NN_APP_NATIVE +#define WASI_NN_APP_NATIVE + +#include +#include +#include +#include +#include + +#include "wasi_nn.h" +#include "logger.h" + +#include "bh_platform.h" +#include "wasm_export.h" + +typedef struct { + uint32_t buf_offset; + uint32_t size; +} graph_builder_wasm; + +typedef struct { + uint32_t buf_offset; + uint32_t size; +} graph_builder_array_wasm; + +typedef struct { + uint32_t buf_offset; + uint32_t size; +} tensor_dimensions_wasm; + +typedef struct { + uint32_t dimensions_offset; + tensor_type type; + uint32_t data_offset; +} tensor_wasm; + +error +graph_builder_array_app_native(wasm_module_inst_t instance, + graph_builder_array_wasm *builder, + graph_builder_array *builder_native); + +error +tensor_app_native(wasm_module_inst_t instance, tensor_wasm *input_tensor, + tensor *input_tensor_native); + +#endif diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/src/wasi_nn.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/src/wasi_nn.c new file mode 100644 index 00000000000..466630f99f1 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/src/wasi_nn.c @@ -0,0 +1,306 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include +#include +#include +#include +#include +#include + +#include "wasi_nn.h" +#include "wasi_nn_app_native.h" +#include "logger.h" +#include "wasi_nn_tensorflowlite.hpp" + +#include "bh_platform.h" +#include "wasm_export.h" +#include "wasm_runtime.h" +#include "aot_runtime.h" + +/* Definition of 'wasi_nn.h' structs in WASM app format (using offset) */ + +typedef error (*LOAD)(void *, graph_builder_array *, graph_encoding, + execution_target, graph *); +typedef error (*INIT_EXECUTION_CONTEXT)(void *, graph, + graph_execution_context *); +typedef error (*SET_INPUT)(void *, graph_execution_context, uint32_t, tensor *); +typedef error (*COMPUTE)(void *, graph_execution_context); +typedef error (*GET_OUTPUT)(void *, graph_execution_context, uint32_t, + tensor_data, uint32_t *); + +typedef struct { + LOAD load; + INIT_EXECUTION_CONTEXT init_execution_context; + SET_INPUT set_input; + COMPUTE compute; + GET_OUTPUT get_output; +} api_function; + +/* Global variables */ + +static api_function lookup[] = { + { NULL, NULL, NULL, NULL, NULL }, + { NULL, NULL, NULL, NULL, NULL }, + { NULL, NULL, NULL, NULL, NULL }, + { NULL, NULL, NULL, NULL, NULL }, + { tensorflowlite_load, tensorflowlite_init_execution_context, + tensorflowlite_set_input, tensorflowlite_compute, + tensorflowlite_get_output } +}; + +/* Utils */ + +static bool +is_encoding_implemented(graph_encoding encoding) +{ + return lookup[encoding].load && lookup[encoding].init_execution_context + && lookup[encoding].set_input && lookup[encoding].compute + && lookup[encoding].get_output; +} + +static error +is_model_initialized(WASINNContext *wasi_nn_ctx) +{ + if (!wasi_nn_ctx->is_initialized) { + NN_ERR_PRINTF("Model not initialized."); + return runtime_error; + } + return success; +} + +WASINNContext * +wasm_runtime_get_wasi_nn_ctx(wasm_module_inst_t instance) +{ + WASINNContext *wasi_nn_ctx = NULL; +#if WASM_ENABLE_INTERP != 0 + if (instance->module_type == Wasm_Module_Bytecode) { + NN_DBG_PRINTF("Getting ctx from WASM"); + WASMModuleInstance *module_inst = (WASMModuleInstance *)instance; + wasi_nn_ctx = ((WASMModuleInstanceExtra *)module_inst->e)->wasi_nn_ctx; + } +#endif +#if WASM_ENABLE_AOT != 0 + if (instance->module_type == Wasm_Module_AoT) { + NN_DBG_PRINTF("Getting ctx from AOT"); + AOTModuleInstance *module_inst = (AOTModuleInstance *)instance; + wasi_nn_ctx = ((AOTModuleInstanceExtra *)module_inst->e)->wasi_nn_ctx; + } +#endif + bh_assert(wasi_nn_ctx != NULL); + NN_DBG_PRINTF("Returning ctx"); + return wasi_nn_ctx; +} + +/* WASI-NN implementation */ + +error +wasi_nn_load(wasm_exec_env_t exec_env, graph_builder_array_wasm *builder, + graph_encoding encoding, execution_target target, graph *g) +{ + NN_DBG_PRINTF("Running wasi_nn_load [encoding=%d, target=%d]...", encoding, + target); + + if (!is_encoding_implemented(encoding)) { + NN_ERR_PRINTF("Encoding not supported."); + return invalid_encoding; + } + + wasm_module_inst_t instance = wasm_runtime_get_module_inst(exec_env); + bh_assert(instance); + + error res; + graph_builder_array builder_native = { 0 }; + if (success + != (res = graph_builder_array_app_native(instance, builder, + &builder_native))) + return res; + + if (!wasm_runtime_validate_native_addr(instance, g, sizeof(graph))) { + NN_ERR_PRINTF("graph is invalid"); + res = invalid_argument; + goto fail; + } + + WASINNContext *wasi_nn_ctx = wasm_runtime_get_wasi_nn_ctx(instance); + res = lookup[encoding].load(wasi_nn_ctx->tflite_ctx, &builder_native, + encoding, target, g); + + NN_DBG_PRINTF("wasi_nn_load finished with status %d [graph=%d]", res, *g); + + wasi_nn_ctx->current_encoding = encoding; + wasi_nn_ctx->is_initialized = true; + +fail: + // XXX: Free intermediate structure pointers + if (builder_native.buf) + wasm_runtime_free(builder_native.buf); + + return res; +} + +error +wasi_nn_init_execution_context(wasm_exec_env_t exec_env, graph g, + graph_execution_context *ctx) +{ + NN_DBG_PRINTF("Running wasi_nn_init_execution_context [graph=%d]...", g); + + wasm_module_inst_t instance = wasm_runtime_get_module_inst(exec_env); + bh_assert(instance); + WASINNContext *wasi_nn_ctx = wasm_runtime_get_wasi_nn_ctx(instance); + + error res; + if (success != (res = is_model_initialized(wasi_nn_ctx))) + return res; + + if (!wasm_runtime_validate_native_addr(instance, ctx, + sizeof(graph_execution_context))) { + NN_ERR_PRINTF("ctx is invalid"); + return invalid_argument; + } + + res = lookup[wasi_nn_ctx->current_encoding].init_execution_context( + wasi_nn_ctx->tflite_ctx, g, ctx); + + NN_DBG_PRINTF( + "wasi_nn_init_execution_context finished with status %d [ctx=%d]", res, + *ctx); + return res; +} + +error +wasi_nn_set_input(wasm_exec_env_t exec_env, graph_execution_context ctx, + uint32_t index, tensor_wasm *input_tensor) +{ + NN_DBG_PRINTF("Running wasi_nn_set_input [ctx=%d, index=%d]...", ctx, + index); + + wasm_module_inst_t instance = wasm_runtime_get_module_inst(exec_env); + bh_assert(instance); + WASINNContext *wasi_nn_ctx = wasm_runtime_get_wasi_nn_ctx(instance); + + error res; + if (success != (res = is_model_initialized(wasi_nn_ctx))) + return res; + + tensor input_tensor_native = { 0 }; + if (success + != (res = tensor_app_native(instance, input_tensor, + &input_tensor_native))) + return res; + + res = lookup[wasi_nn_ctx->current_encoding].set_input( + wasi_nn_ctx->tflite_ctx, ctx, index, &input_tensor_native); + + // XXX: Free intermediate structure pointers + if (input_tensor_native.dimensions) + wasm_runtime_free(input_tensor_native.dimensions); + + NN_DBG_PRINTF("wasi_nn_set_input finished with status %d", res); + return res; +} + +error +wasi_nn_compute(wasm_exec_env_t exec_env, graph_execution_context ctx) +{ + NN_DBG_PRINTF("Running wasi_nn_compute [ctx=%d]...", ctx); + + wasm_module_inst_t instance = wasm_runtime_get_module_inst(exec_env); + bh_assert(instance); + WASINNContext *wasi_nn_ctx = wasm_runtime_get_wasi_nn_ctx(instance); + + error res; + if (success != (res = is_model_initialized(wasi_nn_ctx))) + return res; + + res = lookup[wasi_nn_ctx->current_encoding].compute(wasi_nn_ctx->tflite_ctx, + ctx); + NN_DBG_PRINTF("wasi_nn_compute finished with status %d", res); + return res; +} + +error +wasi_nn_get_output(wasm_exec_env_t exec_env, graph_execution_context ctx, + uint32_t index, tensor_data output_tensor, + uint32_t *output_tensor_size) +{ + NN_DBG_PRINTF("Running wasi_nn_get_output [ctx=%d, index=%d]...", ctx, + index); + + wasm_module_inst_t instance = wasm_runtime_get_module_inst(exec_env); + bh_assert(instance); + WASINNContext *wasi_nn_ctx = wasm_runtime_get_wasi_nn_ctx(instance); + + error res; + if (success != (res = is_model_initialized(wasi_nn_ctx))) + return res; + + if (!wasm_runtime_validate_native_addr(instance, output_tensor_size, + sizeof(uint32_t))) { + NN_ERR_PRINTF("output_tensor_size is invalid"); + return invalid_argument; + } + + res = lookup[wasi_nn_ctx->current_encoding].get_output( + wasi_nn_ctx->tflite_ctx, ctx, index, output_tensor, output_tensor_size); + NN_DBG_PRINTF("wasi_nn_get_output finished with status %d [data_size=%d]", + res, *output_tensor_size); + return res; +} + +/* Non-exposed public functions */ + +WASINNContext * +wasi_nn_initialize() +{ + NN_DBG_PRINTF("Initializing wasi-nn"); + WASINNContext *wasi_nn_ctx = + (WASINNContext *)wasm_runtime_malloc(sizeof(WASINNContext)); + if (wasi_nn_ctx == NULL) { + NN_ERR_PRINTF("Error when allocating memory for WASI-NN context"); + return NULL; + } + wasi_nn_ctx->is_initialized = true; + wasi_nn_ctx->current_encoding = 3; + tensorflowlite_initialize(&wasi_nn_ctx->tflite_ctx); + return wasi_nn_ctx; +} + +void +wasi_nn_destroy(WASINNContext *wasi_nn_ctx) +{ + if (wasi_nn_ctx == NULL) { + NN_ERR_PRINTF( + "Error when deallocating memory. WASI-NN context is NULL"); + return; + } + NN_DBG_PRINTF("Freeing wasi-nn"); + NN_DBG_PRINTF("-> is_initialized: %d", wasi_nn_ctx->is_initialized); + NN_DBG_PRINTF("-> current_encoding: %d", wasi_nn_ctx->current_encoding); + tensorflowlite_destroy(wasi_nn_ctx->tflite_ctx); + wasm_runtime_free(wasi_nn_ctx); +} + +/* Register WASI-NN in WAMR */ + +/* clang-format off */ +#define REG_NATIVE_FUNC(func_name, signature) \ + { #func_name, wasi_nn_##func_name, signature, NULL } +/* clang-format on */ + +static NativeSymbol native_symbols_wasi_nn[] = { + REG_NATIVE_FUNC(load, "(*ii*)i"), + REG_NATIVE_FUNC(init_execution_context, "(i*)i"), + REG_NATIVE_FUNC(set_input, "(ii*)i"), + REG_NATIVE_FUNC(compute, "(i)i"), + REG_NATIVE_FUNC(get_output, "(ii**)i"), +}; + +uint32_t +get_wasi_nn_export_apis(NativeSymbol **p_libc_wasi_apis) +{ + *p_libc_wasi_apis = native_symbols_wasi_nn; + return sizeof(native_symbols_wasi_nn) / sizeof(NativeSymbol); +} diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/src/wasi_nn_private.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/src/wasi_nn_private.h new file mode 100644 index 00000000000..52d16bd1da0 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/src/wasi_nn_private.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef WASI_NN_PRIVATE_H +#define WASI_NN_PRIVATE_H + +#include "wasi_nn_types.h" + +typedef struct { + bool is_initialized; + graph_encoding current_encoding; + void *tflite_ctx; +} WASINNContext; + +/** + * @brief Initialize wasi-nn + * + */ +WASINNContext * +wasi_nn_initialize(); +/** + * @brief Destroy wasi-nn on app exists + * + */ + +void +wasi_nn_destroy(WASINNContext *wasi_nn_ctx); + +#endif diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/src/wasi_nn_tensorflowlite.cpp b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/src/wasi_nn_tensorflowlite.cpp new file mode 100644 index 00000000000..dfd21787cd8 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/src/wasi_nn_tensorflowlite.cpp @@ -0,0 +1,417 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "wasi_nn.h" +#include "wasi_nn_tensorflowlite.hpp" +#include "logger.h" + +#include "bh_common.h" +#include "bh_platform.h" +#include "platform_common.h" + +#include +#include +#include +#include +#include + +#if defined(WASI_NN_ENABLE_GPU) +#include +#endif + +#if defined(WASI_NN_ENABLE_EXTERNAL_DELEGATE) +#include +#endif + +/* Maximum number of graphs per WASM instance */ +#define MAX_GRAPHS_PER_INST 10 +/* Maximum number of graph execution context per WASM instance*/ +#define MAX_GRAPH_EXEC_CONTEXTS_PER_INST 10 + +typedef struct { + std::unique_ptr interpreter; +} Interpreter; + +typedef struct { + char *model_pointer; + std::unique_ptr model; + execution_target target; +} Model; + +typedef struct { + uint32_t current_models; + Model models[MAX_GRAPHS_PER_INST]; + uint32_t current_interpreters; + Interpreter interpreters[MAX_GRAPH_EXEC_CONTEXTS_PER_INST]; + korp_mutex g_lock; + TfLiteDelegate *delegate; +} TFLiteContext; + +/* Utils */ + +static error +initialize_g(TFLiteContext *tfl_ctx, graph *g) +{ + os_mutex_lock(&tfl_ctx->g_lock); + if (tfl_ctx->current_models == MAX_GRAPHS_PER_INST) { + os_mutex_unlock(&tfl_ctx->g_lock); + NN_ERR_PRINTF("Excedded max graphs per WASM instance"); + return runtime_error; + } + *g = tfl_ctx->current_models++; + os_mutex_unlock(&tfl_ctx->g_lock); + return success; +} +static error +initialize_graph_ctx(TFLiteContext *tfl_ctx, graph g, + graph_execution_context *ctx) +{ + os_mutex_lock(&tfl_ctx->g_lock); + if (tfl_ctx->current_interpreters == MAX_GRAPH_EXEC_CONTEXTS_PER_INST) { + os_mutex_unlock(&tfl_ctx->g_lock); + NN_ERR_PRINTF("Excedded max graph execution context per WASM instance"); + return runtime_error; + } + *ctx = tfl_ctx->current_interpreters++; + os_mutex_unlock(&tfl_ctx->g_lock); + return success; +} + +static error +is_valid_graph(TFLiteContext *tfl_ctx, graph g) +{ + if (g >= MAX_GRAPHS_PER_INST) { + NN_ERR_PRINTF("Invalid graph: %d >= %d.", g, MAX_GRAPHS_PER_INST); + return runtime_error; + } + if (tfl_ctx->models[g].model_pointer == NULL) { + NN_ERR_PRINTF("Context (model) non-initialized."); + return runtime_error; + } + if (tfl_ctx->models[g].model == NULL) { + NN_ERR_PRINTF("Context (tflite model) non-initialized."); + return runtime_error; + } + return success; +} + +static error +is_valid_graph_execution_context(TFLiteContext *tfl_ctx, + graph_execution_context ctx) +{ + if (ctx >= MAX_GRAPH_EXEC_CONTEXTS_PER_INST) { + NN_ERR_PRINTF("Invalid graph execution context: %d >= %d", ctx, + MAX_GRAPH_EXEC_CONTEXTS_PER_INST); + return runtime_error; + } + if (tfl_ctx->interpreters[ctx].interpreter == NULL) { + NN_ERR_PRINTF("Context (interpreter) non-initialized."); + return runtime_error; + } + return success; +} + +/* WASI-NN (tensorflow) implementation */ + +error +tensorflowlite_load(void *tflite_ctx, graph_builder_array *builder, + graph_encoding encoding, execution_target target, graph *g) +{ + TFLiteContext *tfl_ctx = (TFLiteContext *)tflite_ctx; + + if (builder->size != 1) { + NN_ERR_PRINTF("Unexpected builder format."); + return invalid_argument; + } + + if (encoding != tensorflowlite) { + NN_ERR_PRINTF("Encoding is not tensorflowlite."); + return invalid_argument; + } + + if (target != cpu && target != gpu) { + NN_ERR_PRINTF("Only CPU and GPU target is supported."); + return invalid_argument; + } + + error res; + if (success != (res = initialize_g(tfl_ctx, g))) + return res; + + uint32_t size = builder->buf[0].size; + + // Save model + tfl_ctx->models[*g].model_pointer = (char *)wasm_runtime_malloc(size); + if (tfl_ctx->models[*g].model_pointer == NULL) { + NN_ERR_PRINTF("Error when allocating memory for model."); + return missing_memory; + } + + bh_memcpy_s(tfl_ctx->models[*g].model_pointer, size, builder->buf[0].buf, + size); + + // Save model flatbuffer + tfl_ctx->models[*g].model = + std::move(tflite::FlatBufferModel::BuildFromBuffer( + tfl_ctx->models[*g].model_pointer, size, NULL)); + + if (tfl_ctx->models[*g].model == NULL) { + NN_ERR_PRINTF("Loading model error."); + wasm_runtime_free(tfl_ctx->models[*g].model_pointer); + tfl_ctx->models[*g].model_pointer = NULL; + return missing_memory; + } + + // Save target + tfl_ctx->models[*g].target = target; + return success; +} + +error +tensorflowlite_init_execution_context(void *tflite_ctx, graph g, + graph_execution_context *ctx) +{ + TFLiteContext *tfl_ctx = (TFLiteContext *)tflite_ctx; + + error res; + if (success != (res = is_valid_graph(tfl_ctx, g))) + return res; + + if (success != (res = initialize_graph_ctx(tfl_ctx, g, ctx))) + return res; + + // Build the interpreter with the InterpreterBuilder. + tflite::ops::builtin::BuiltinOpResolver resolver; + tflite::InterpreterBuilder tflite_builder(*tfl_ctx->models[g].model, + resolver); + tflite_builder(&tfl_ctx->interpreters[*ctx].interpreter); + if (tfl_ctx->interpreters[*ctx].interpreter == NULL) { + NN_ERR_PRINTF("Error when generating the interpreter."); + return missing_memory; + } + + bool use_default = false; + switch (tfl_ctx->models[g].target) { + case gpu: + { +#if defined(WASI_NN_ENABLE_GPU) + NN_WARN_PRINTF("GPU enabled."); + // https://www.tensorflow.org/lite/performance/gpu + TfLiteGpuDelegateOptionsV2 options = + TfLiteGpuDelegateOptionsV2Default(); + options.inference_preference = + TFLITE_GPU_INFERENCE_PREFERENCE_SUSTAINED_SPEED; + options.inference_priority1 = + TFLITE_GPU_INFERENCE_PRIORITY_MIN_LATENCY; + tfl_ctx->delegate = TfLiteGpuDelegateV2Create(&options); + if (tfl_ctx->delegate == NULL) { + NN_ERR_PRINTF("Error when generating GPU delegate."); + use_default = true; + return missing_memory; + } + if (tfl_ctx->interpreters[*ctx] + .interpreter->ModifyGraphWithDelegate(tfl_ctx->delegate) + != kTfLiteOk) { + NN_ERR_PRINTF("Error when enabling GPU delegate."); + use_default = true; + } +#elif defined(WASI_NN_ENABLE_EXTERNAL_DELEGATE) + NN_WARN_PRINTF("external delegation enabled."); + TfLiteExternalDelegateOptions options = + TfLiteExternalDelegateOptionsDefault(WASI_NN_EXT_DELEGATE_PATH); + tfl_ctx->delegate = TfLiteExternalDelegateCreate(&options); + if (tfl_ctx->delegate == NULL) { + NN_ERR_PRINTF("Error when generating External delegate."); + use_default = true; + return missing_memory; + } + if (tfl_ctx->interpreters[*ctx] + .interpreter->ModifyGraphWithDelegate(tfl_ctx->delegate) + != kTfLiteOk) { + NN_ERR_PRINTF("Error when enabling External delegate."); + use_default = true; + } +#else + NN_WARN_PRINTF("GPU not enabled."); + use_default = true; +#endif + break; + } + default: + use_default = true; + } + if (use_default) + NN_WARN_PRINTF("Default encoding is CPU."); + + tfl_ctx->interpreters[*ctx].interpreter->AllocateTensors(); + return success; +} + +error +tensorflowlite_set_input(void *tflite_ctx, graph_execution_context ctx, + uint32_t index, tensor *input_tensor) +{ + TFLiteContext *tfl_ctx = (TFLiteContext *)tflite_ctx; + + error res; + if (success != (res = is_valid_graph_execution_context(tfl_ctx, ctx))) + return res; + + uint32_t num_tensors = + tfl_ctx->interpreters[ctx].interpreter->inputs().size(); + NN_DBG_PRINTF("Number of tensors (%d)", num_tensors); + if (index + 1 > num_tensors) { + return runtime_error; + } + + auto tensor = tfl_ctx->interpreters[ctx].interpreter->input_tensor(index); + if (tensor == NULL) { + NN_ERR_PRINTF("Missing memory"); + return missing_memory; + } + + uint32_t model_tensor_size = 1; + for (int i = 0; i < tensor->dims->size; ++i) + model_tensor_size *= (uint32_t)tensor->dims->data[i]; + + uint32_t input_tensor_size = 1; + for (uint32_t i = 0; i < input_tensor->dimensions->size; i++) + input_tensor_size *= (uint32_t)input_tensor->dimensions->buf[i]; + + if (model_tensor_size != input_tensor_size) { + NN_ERR_PRINTF("Input tensor shape from the model is different than the " + "one provided"); + return invalid_argument; + } + + auto *input = + tfl_ctx->interpreters[ctx].interpreter->typed_input_tensor( + index); + if (input == NULL) + return missing_memory; + + bh_memcpy_s(input, model_tensor_size * sizeof(float), input_tensor->data, + model_tensor_size * sizeof(float)); + return success; +} + +error +tensorflowlite_compute(void *tflite_ctx, graph_execution_context ctx) +{ + TFLiteContext *tfl_ctx = (TFLiteContext *)tflite_ctx; + + error res; + if (success != (res = is_valid_graph_execution_context(tfl_ctx, ctx))) + return res; + + tfl_ctx->interpreters[ctx].interpreter->Invoke(); + return success; +} + +error +tensorflowlite_get_output(void *tflite_ctx, graph_execution_context ctx, + uint32_t index, tensor_data output_tensor, + uint32_t *output_tensor_size) +{ + TFLiteContext *tfl_ctx = (TFLiteContext *)tflite_ctx; + + error res; + if (success != (res = is_valid_graph_execution_context(tfl_ctx, ctx))) + return res; + + uint32_t num_output_tensors = + tfl_ctx->interpreters[ctx].interpreter->outputs().size(); + NN_DBG_PRINTF("Number of tensors (%d)", num_output_tensors); + + if (index + 1 > num_output_tensors) { + return runtime_error; + } + + auto tensor = tfl_ctx->interpreters[ctx].interpreter->output_tensor(index); + if (tensor == NULL) { + NN_ERR_PRINTF("Missing memory"); + return missing_memory; + } + + uint32_t model_tensor_size = 1; + for (int i = 0; i < (int)tensor->dims->size; ++i) + model_tensor_size *= (uint32_t)tensor->dims->data[i]; + + if (*output_tensor_size < model_tensor_size) { + NN_ERR_PRINTF("Insufficient memory to copy tensor %d", index); + return missing_memory; + } + + float *tensor_f = + tfl_ctx->interpreters[ctx].interpreter->typed_output_tensor( + index); + for (uint32_t i = 0; i < model_tensor_size; ++i) + NN_DBG_PRINTF("output: %f", tensor_f[i]); + + *output_tensor_size = model_tensor_size; + bh_memcpy_s(output_tensor, model_tensor_size * sizeof(float), tensor_f, + model_tensor_size * sizeof(float)); + return success; +} + +void +tensorflowlite_initialize(void **tflite_ctx) +{ + TFLiteContext *tfl_ctx = new TFLiteContext(); + if (tfl_ctx == NULL) { + NN_ERR_PRINTF("Error when allocating memory for tensorflowlite."); + return; + } + + NN_DBG_PRINTF("Initializing models."); + tfl_ctx->current_models = 0; + for (int i = 0; i < MAX_GRAPHS_PER_INST; ++i) { + tfl_ctx->models[i].model_pointer = NULL; + } + NN_DBG_PRINTF("Initializing interpreters."); + tfl_ctx->current_interpreters = 0; + + if (os_mutex_init(&tfl_ctx->g_lock) != 0) { + NN_ERR_PRINTF("Error while initializing the lock"); + } + + tfl_ctx->delegate = NULL; + + *tflite_ctx = (void *)tfl_ctx; +} + +void +tensorflowlite_destroy(void *tflite_ctx) +{ + /* + TensorFlow Lite memory is internally managed by tensorflow + + Related issues: + * https://github.com/tensorflow/tensorflow/issues/15880 + */ + TFLiteContext *tfl_ctx = (TFLiteContext *)tflite_ctx; + + if (tfl_ctx->delegate != NULL) { +#if defined(WASI_NN_ENABLE_GPU) + TfLiteGpuDelegateV2Delete(tfl_ctx->delegate); +#elif defined(WASI_NN_ENABLE_EXTERNAL_DELEGATE) + TfLiteExternalDelegateDelete(tfl_ctx->delegate); +#endif + } + + NN_DBG_PRINTF("Freeing memory."); + for (int i = 0; i < MAX_GRAPHS_PER_INST; ++i) { + tfl_ctx->models[i].model.reset(); + if (tfl_ctx->models[i].model_pointer) + wasm_runtime_free(tfl_ctx->models[i].model_pointer); + tfl_ctx->models[i].model_pointer = NULL; + } + for (int i = 0; i < MAX_GRAPH_EXEC_CONTEXTS_PER_INST; ++i) { + tfl_ctx->interpreters[i].interpreter.reset(); + } + os_mutex_destroy(&tfl_ctx->g_lock); + delete tfl_ctx; + NN_DBG_PRINTF("Memory free'd."); +} diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/src/wasi_nn_tensorflowlite.hpp b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/src/wasi_nn_tensorflowlite.hpp new file mode 100644 index 00000000000..9605420ddb4 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/src/wasi_nn_tensorflowlite.hpp @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef WASI_NN_TENSORFLOWLITE_HPP +#define WASI_NN_TENSORFLOWLITE_HPP + +#include "wasi_nn.h" + +#ifdef __cplusplus +extern "C" { +#endif + +error +tensorflowlite_load(void *tflite_ctx, graph_builder_array *builder, + graph_encoding encoding, execution_target target, graph *g); + +error +tensorflowlite_init_execution_context(void *tflite_ctx, graph g, + graph_execution_context *ctx); + +error +tensorflowlite_set_input(void *tflite_ctx, graph_execution_context ctx, + uint32_t index, tensor *input_tensor); + +error +tensorflowlite_compute(void *tflite_ctx, graph_execution_context ctx); + +error +tensorflowlite_get_output(void *tflite_ctx, graph_execution_context ctx, + uint32_t index, tensor_data output_tensor, + uint32_t *output_tensor_size); + +void +tensorflowlite_initialize(void **tflite_ctx); + +void +tensorflowlite_destroy(void *tflite_ctx); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/wasi-nn/test/CMakeLists.txt b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/CMakeLists.txt similarity index 96% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/wasi-nn/test/CMakeLists.txt rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/CMakeLists.txt index 7951dec454c..33fad71eb5f 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/wasi-nn/test/CMakeLists.txt +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/CMakeLists.txt @@ -7,10 +7,10 @@ project (iwasm) set (CMAKE_VERBOSE_MAKEFILE OFF) # Reset default linker flags -set (CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") -set (CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") set (CMAKE_C_STANDARD 99) set (CMAKE_CXX_STANDARD 14) +set (CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") +set (CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") if (NOT DEFINED WAMR_BUILD_PLATFORM) set (WAMR_BUILD_PLATFORM "linux") @@ -110,11 +110,6 @@ if (WAMR_BUILD_DEBUG_INTERP EQUAL 1) set (WAMR_BUILD_SIMD 0) endif () -if (COLLECT_CODE_COVERAGE EQUAL 1) - set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage") - set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage") -endif () - set (WAMR_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../../../..) include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake) diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/Dockerfile.compile b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/Dockerfile.compile new file mode 100644 index 00000000000..51a59707b8d --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/Dockerfile.compile @@ -0,0 +1,23 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +FROM ubuntu:20.04 + +ENV DEBIAN_FRONTEND=noninteractive + +RUN apt-get update && apt-get install -y \ + cmake build-essential git wget python3.10 python3-pip + +ARG WASI_SDK_VER=19 +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 -fs /opt/wasi-sdk-${WASI_SDK_VER}.0 /opt/wasi-sdk \ + && rm /opt/wasi-sdk-${WASI_SDK_VER}.0-linux.tar.gz + +WORKDIR /wasi-nn/test + +COPY core/iwasm/libraries/wasi-nn/test/requirements.txt . + +RUN pip3 install -r requirements.txt && rm requirements.txt + +ENTRYPOINT [ "bash", "./build.sh" ] diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/Dockerfile.cpu b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/Dockerfile.cpu new file mode 100644 index 00000000000..532a53365b7 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/Dockerfile.cpu @@ -0,0 +1,27 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +FROM ubuntu:20.04 AS base + +ENV DEBIAN_FRONTEND=noninteractive + +RUN apt-get update && apt-get install -y \ + cmake build-essential git + +WORKDIR /home/wamr + +COPY . . + +WORKDIR /home/wamr/core/iwasm/libraries/wasi-nn/test/build + +RUN cmake \ + -DWAMR_BUILD_WASI_NN=1 \ + .. + +RUN make -j $(grep -c ^processor /proc/cpuinfo) + +FROM ubuntu:22.04 + +COPY --from=base /home/wamr/core/iwasm/libraries/wasi-nn/test/build/iwasm /run/iwasm + +ENTRYPOINT [ "/run/iwasm" ] diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/Dockerfile.nvidia-gpu b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/Dockerfile.nvidia-gpu new file mode 100644 index 00000000000..44963bd6388 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/Dockerfile.nvidia-gpu @@ -0,0 +1,40 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +FROM ubuntu:20.04 AS base + +ENV DEBIAN_FRONTEND=noninteractive + +RUN apt-get update && apt-get install -y \ + cmake build-essential git + +WORKDIR /home/wamr + +COPY . . + +WORKDIR /home/wamr/core/iwasm/libraries/wasi-nn/test/build + +RUN cmake \ + -DWAMR_BUILD_WASI_NN=1 \ + -DWASI_NN_ENABLE_GPU=1 \ + .. + +RUN make -j $(grep -c ^processor /proc/cpuinfo) + +FROM nvidia/cuda:11.3.0-runtime-ubuntu20.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + ocl-icd-libopencl1 \ + ocl-icd-opencl-dev \ + clinfo && \ + rm -rf /var/lib/apt/lists/* + +RUN mkdir -p /etc/OpenCL/vendors && \ + echo "libnvidia-opencl.so.1" > /etc/OpenCL/vendors/nvidia.icd + +ENV NVIDIA_VISIBLE_DEVICES=all +ENV NVIDIA_DRIVER_CAPABILITIES=compute,utility + +COPY --from=base /home/wamr/core/iwasm/libraries/wasi-nn/test/build/iwasm /run/iwasm + +ENTRYPOINT [ "/run/iwasm" ] diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/Dockerfile.vx-delegate b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/Dockerfile.vx-delegate new file mode 100644 index 00000000000..89cc1a9dea0 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/Dockerfile.vx-delegate @@ -0,0 +1,99 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +FROM ubuntu:20.04 AS base + +ENV DEBIAN_FRONTEND=noninteractive + + +RUN apt-get update && apt-get install -y \ + cmake build-essential git curl libssl-dev python3 + + +# Build TensorFlow Lite VX delegate default built for x86-64 simulator +WORKDIR /tmp +RUN git clone https://github.com/VeriSilicon/TIM-VX.git tim-vx +RUN git clone https://github.com/VeriSilicon/tflite-vx-delegate.git +RUN git clone https://github.com/tensorflow/tensorflow.git + + +# Build TIM-VX +WORKDIR /tmp/tim-vx/host_build +RUN cmake -DCMAKE_INSTALL_PREFIX=/usr/local ../ +RUN make -j$(grep -c ^processor /proc/cpuinfo) +RUN make install + +WORKDIR /tmp/tim-vx +#RUN mkdir -p prebuilt-sdk/x86_64_linux/lib/include +#RUN cp prebuilt-sdk/x86_64_linux/include/CL prebuilt-sdk/x86_64_linux/lib/include -fr + + +# Build TensorFlow Lite +WORKDIR /tmp/tensorflow/build +RUN cmake \ + -DBUILD_SHARED_LIBS=ON=on \ + -DTFLITE_ENABLE_RUY=on \ + -DTFLITE_ENABLE_NNAPI=off \ + -DTFLITE_ENABLE_XNNPACK=on \ + -DTFLITE_ENABLE_EXTERNAL_DELEGATE=on \ + ../tensorflow/lite/ +RUN make -j$(grep -c ^processor /proc/cpuinfo) +RUN make install +RUN cp --no-preserve=ownership -d lib*.so* /usr/local/lib +RUN cp -r --no-preserve=ownership -d flatbuffers/include/flatbuffers /usr/local/include +# install header files +RUN install -d /usr/local/include/tensorflow/lite && \ + cd /tmp/tensorflow/tensorflow/lite && \ + cp --parents \ + $(find . -name "*.h*") \ + /usr/local/include/tensorflow/lite +# install version.h from core +RUN install -d /usr/local/include/tensorflow/core/public && \ + cp /tmp/tensorflow/tensorflow/core/public/version.h /usr/local/include/tensorflow/core/public + + +# Build Vx Delegate default built for x86-64 simulator +WORKDIR /tmp/tflite-vx-delegate/build +RUN cmake \ + -DBUILD_SHARED_LIBS=ON \ + -DFETCHCONTENT_SOURCE_DIR_TENSORFLOW=/tmp/tensorflow \ + -DTFLITE_LIB_LOC=/usr/local/lib/libtensorflow-lite.so \ + -DTIM_VX_INSTALL=/usr/local \ + -DCMAKE_INSTALL_PREFIX=/usr/ \ + ../ +RUN make vx_delegate -j$(grep -c ^processor /proc/cpuinfo) +RUN make install +RUN cp --no-preserve=ownership -d lib*.so* /usr/lib +# install header files +RUN install -d /usr/local/include/tensorflow-lite-vx-delegate && \ + cd /tmp/tflite-vx-delegate/ && \ + cp --parents \ + $(find . -name "*.h*") \ + /usr/local/include/tensorflow-lite-vx-delegate + +ENV VIVANTE_SDK_DIR=/tmp/tim-vx/prebuilt-sdk/x86_64_linux/ +ENV VSIMULATOR_CONFIG=czl + +ENV LD_LIBRARY_PATH=/tmp/tim-vx/prebuilt-sdk/x86_64_linux/lib:/usr/local/lib:/lib/x86_64-linux-gnu/:/lib64/:/usr/lib:$LD_LIBRARY_PATH + + +# Build WASI-NN +WORKDIR /home/wamr + +COPY . . + +WORKDIR /home/wamr/core/iwasm/libraries/wasi-nn/test/build + +RUN cmake \ + -DCMAKE_LIBRARY_PATH=${CMAKE_LIBRARY_PATH}:/usr/local/lib/ \ + -DCMAKE_INCLUDE_PATH=${CMAKE_INCLUDE_PATH}:/usr/local/include/ \ + -DWAMR_BUILD_WASI_NN=1 \ + -DWAMR_BUILD_WASI_NN_ENABLE_EXT=1 \ + -DWASI_NN_EXT_DELEGATE_PATH="/usr/lib/libvx_delegate.so" \ + .. + +RUN make -j $(grep -c ^processor /proc/cpuinfo) + +RUN cp /home/wamr/core/iwasm/libraries/wasi-nn/test/build/iwasm /run/iwasm + +ENTRYPOINT [ "/run/iwasm" ] diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/wasi-nn/test/build.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/build.sh similarity index 82% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/wasi-nn/test/build.sh rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/build.sh index 4dc8d015117..33879eaf7ce 100755 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/wasi-nn/test/build.sh +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/build.sh @@ -7,8 +7,9 @@ -Wl,--allow-undefined \ -Wl,--strip-all,--no-entry \ --sysroot=/opt/wasi-sdk/share/wasi-sysroot \ - -I/home/wamr/core/iwasm/libraries/wasi-nn \ - -o test_tensorflow.wasm test_tensorflow.c + -I.. -I../src/utils \ + -o test_tensorflow.wasm \ + test_tensorflow.c utils.c # TFLite models to use in the tests diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/wasi-nn/test/models/average.py b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/models/average.py similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/wasi-nn/test/models/average.py rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/models/average.py diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/wasi-nn/test/models/max.py b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/models/max.py similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/wasi-nn/test/models/max.py rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/models/max.py diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/wasi-nn/test/models/mult_dimension.py b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/models/mult_dimension.py similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/wasi-nn/test/models/mult_dimension.py rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/models/mult_dimension.py diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/wasi-nn/test/models/mult_outputs.py b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/models/mult_outputs.py similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/wasi-nn/test/models/mult_outputs.py rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/models/mult_outputs.py diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/wasi-nn/test/models/sum.py b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/models/sum.py similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/wasi-nn/test/models/sum.py rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/models/sum.py diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/wasi-nn/test/models/utils.py b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/models/utils.py similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/libraries/wasi-nn/test/models/utils.py rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/models/utils.py diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/requirements.txt b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/requirements.txt new file mode 100644 index 00000000000..4cf2910db53 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/requirements.txt @@ -0,0 +1 @@ +tensorflow==2.11.1 \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/test_tensorflow.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/test_tensorflow.c new file mode 100644 index 00000000000..2fa5165384c --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/test_tensorflow.c @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include +#include +#include +#include +#include + +#include "utils.h" +#include "logger.h" + +void +test_sum(execution_target target) +{ + int dims[] = { 1, 5, 5, 1 }; + input_info input = create_input(dims); + + uint32_t output_size = 0; + float *output = run_inference(target, input.input_tensor, input.dim, + &output_size, "/assets/models/sum.tflite", 1); + + assert(output_size == 1); + assert(fabs(output[0] - 300.0) < EPSILON); + + free(input.dim); + free(input.input_tensor); + free(output); +} + +void +test_max(execution_target target) +{ + int dims[] = { 1, 5, 5, 1 }; + input_info input = create_input(dims); + + uint32_t output_size = 0; + float *output = run_inference(target, input.input_tensor, input.dim, + &output_size, "/assets/models/max.tflite", 1); + + assert(output_size == 1); + assert(fabs(output[0] - 24.0) < EPSILON); + NN_INFO_PRINTF("Result: max is %f", output[0]); + + free(input.dim); + free(input.input_tensor); + free(output); +} + +void +test_average(execution_target target) +{ + int dims[] = { 1, 5, 5, 1 }; + input_info input = create_input(dims); + + uint32_t output_size = 0; + float *output = + run_inference(target, input.input_tensor, input.dim, &output_size, + "/assets/models/average.tflite", 1); + + assert(output_size == 1); + assert(fabs(output[0] - 12.0) < EPSILON); + NN_INFO_PRINTF("Result: average is %f", output[0]); + + free(input.dim); + free(input.input_tensor); + free(output); +} + +void +test_mult_dimensions(execution_target target) +{ + int dims[] = { 1, 3, 3, 1 }; + input_info input = create_input(dims); + + uint32_t output_size = 0; + float *output = + run_inference(target, input.input_tensor, input.dim, &output_size, + "/assets/models/mult_dim.tflite", 1); + + assert(output_size == 9); + for (int i = 0; i < 9; i++) + assert(fabs(output[i] - i) < EPSILON); + + free(input.dim); + free(input.input_tensor); + free(output); +} + +void +test_mult_outputs(execution_target target) +{ + int dims[] = { 1, 4, 4, 1 }; + input_info input = create_input(dims); + + uint32_t output_size = 0; + float *output = + run_inference(target, input.input_tensor, input.dim, &output_size, + "/assets/models/mult_out.tflite", 2); + + assert(output_size == 8); + // first tensor check + for (int i = 0; i < 4; i++) + assert(fabs(output[i] - (i * 4 + 24)) < EPSILON); + // second tensor check + for (int i = 0; i < 4; i++) + assert(fabs(output[i + 4] - (i + 6)) < EPSILON); + + free(input.dim); + free(input.input_tensor); + free(output); +} + +int +main() +{ + char *env = getenv("TARGET"); + if (env == NULL) { + NN_INFO_PRINTF("Usage:\n--env=\"TARGET=[cpu|gpu]\""); + return 1; + } + execution_target target; + if (strcmp(env, "cpu") == 0) + target = cpu; + else if (strcmp(env, "gpu") == 0) + target = gpu; + else { + NN_ERR_PRINTF("Wrong target!"); + return 1; + } + NN_INFO_PRINTF("################### Testing sum..."); + test_sum(target); + NN_INFO_PRINTF("################### Testing max..."); + test_max(target); + NN_INFO_PRINTF("################### Testing average..."); + test_average(target); + NN_INFO_PRINTF("################### Testing multiple dimensions..."); + test_mult_dimensions(target); + NN_INFO_PRINTF("################### Testing multiple outputs..."); + test_mult_outputs(target); + + NN_INFO_PRINTF("Tests: passed!"); + return 0; +} diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/utils.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/utils.c new file mode 100644 index 00000000000..e0704cab421 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/utils.c @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "utils.h" +#include "logger.h" + +#include +#include + +error +wasm_load(char *model_name, graph *g, execution_target target) +{ + FILE *pFile = fopen(model_name, "r"); + if (pFile == NULL) + return invalid_argument; + + uint8_t *buffer; + size_t result; + + // allocate memory to contain the whole file: + buffer = (uint8_t *)malloc(sizeof(uint8_t) * MAX_MODEL_SIZE); + if (buffer == NULL) { + fclose(pFile); + return missing_memory; + } + + result = fread(buffer, 1, MAX_MODEL_SIZE, pFile); + if (result <= 0) { + fclose(pFile); + free(buffer); + return missing_memory; + } + + graph_builder_array arr; + + arr.size = 1; + arr.buf = (graph_builder *)malloc(sizeof(graph_builder)); + if (arr.buf == NULL) { + fclose(pFile); + free(buffer); + return missing_memory; + } + + arr.buf[0].size = result; + arr.buf[0].buf = buffer; + + error res = load(&arr, tensorflowlite, target, g); + + fclose(pFile); + free(buffer); + free(arr.buf); + return res; +} + +error +wasm_init_execution_context(graph g, graph_execution_context *ctx) +{ + return init_execution_context(g, ctx); +} + +error +wasm_set_input(graph_execution_context ctx, float *input_tensor, uint32_t *dim) +{ + tensor_dimensions dims; + dims.size = INPUT_TENSOR_DIMS; + dims.buf = (uint32_t *)malloc(dims.size * sizeof(uint32_t)); + if (dims.buf == NULL) + return missing_memory; + + tensor tensor; + tensor.dimensions = &dims; + for (int i = 0; i < tensor.dimensions->size; ++i) + tensor.dimensions->buf[i] = dim[i]; + tensor.type = fp32; + tensor.data = (uint8_t *)input_tensor; + error err = set_input(ctx, 0, &tensor); + + free(dims.buf); + return err; +} + +error +wasm_compute(graph_execution_context ctx) +{ + return compute(ctx); +} + +error +wasm_get_output(graph_execution_context ctx, uint32_t index, float *out_tensor, + uint32_t *out_size) +{ + return get_output(ctx, index, (uint8_t *)out_tensor, out_size); +} + +float * +run_inference(execution_target target, float *input, uint32_t *input_size, + uint32_t *output_size, char *model_name, + uint32_t num_output_tensors) +{ + graph graph; + if (wasm_load(model_name, &graph, target) != success) { + NN_ERR_PRINTF("Error when loading model."); + exit(1); + } + + graph_execution_context ctx; + if (wasm_init_execution_context(graph, &ctx) != success) { + NN_ERR_PRINTF("Error when initialixing execution context."); + exit(1); + } + + if (wasm_set_input(ctx, input, input_size) != success) { + NN_ERR_PRINTF("Error when setting input tensor."); + exit(1); + } + + if (wasm_compute(ctx) != success) { + NN_ERR_PRINTF("Error when running inference."); + exit(1); + } + + float *out_tensor = (float *)malloc(sizeof(float) * MAX_OUTPUT_TENSOR_SIZE); + if (out_tensor == NULL) { + NN_ERR_PRINTF("Error when allocating memory for output tensor."); + exit(1); + } + + uint32_t offset = 0; + for (int i = 0; i < num_output_tensors; ++i) { + *output_size = MAX_OUTPUT_TENSOR_SIZE - *output_size; + if (wasm_get_output(ctx, i, &out_tensor[offset], output_size) + != success) { + NN_ERR_PRINTF("Error when getting output."); + exit(1); + } + + offset += *output_size; + } + *output_size = offset; + return out_tensor; +} + +input_info +create_input(int *dims) +{ + input_info input = { .dim = NULL, .input_tensor = NULL, .elements = 1 }; + + input.dim = malloc(INPUT_TENSOR_DIMS * sizeof(uint32_t)); + if (input.dim) + for (int i = 0; i < INPUT_TENSOR_DIMS; ++i) { + input.dim[i] = dims[i]; + input.elements *= dims[i]; + } + + input.input_tensor = malloc(input.elements * sizeof(float)); + for (int i = 0; i < input.elements; ++i) + input.input_tensor[i] = i; + + return input; +} diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/utils.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/utils.h new file mode 100644 index 00000000000..6373be54214 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/utils.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef WASI_NN_UTILS +#define WASI_NN_UTILS + +#include + +#include "wasi_nn.h" + +#define MAX_MODEL_SIZE 85000000 +#define MAX_OUTPUT_TENSOR_SIZE 200 +#define INPUT_TENSOR_DIMS 4 +#define EPSILON 1e-8 + +typedef struct { + float *input_tensor; + uint32_t *dim; + uint32_t elements; +} input_info; + +/* wasi-nn wrappers */ + +error +wasm_load(char *model_name, graph *g, execution_target target); + +error +wasm_init_execution_context(graph g, graph_execution_context *ctx); + +error +wasm_set_input(graph_execution_context ctx, float *input_tensor, uint32_t *dim); + +error +wasm_compute(graph_execution_context ctx); + +error +wasm_get_output(graph_execution_context ctx, uint32_t index, float *out_tensor, + uint32_t *out_size); + +/* Utils */ + +float * +run_inference(execution_target target, float *input, uint32_t *input_size, + uint32_t *output_size, char *model_name, + uint32_t num_output_tensors); + +input_info +create_input(int *dims); + +#endif diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/wasi_nn.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/wasi_nn.cmake new file mode 100644 index 00000000000..019782c2e42 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/wasi_nn.cmake @@ -0,0 +1,22 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/cmake) + +# Find tensorflow-lite +find_package(tensorflow_lite REQUIRED) + +set (WASI_NN_DIR ${CMAKE_CURRENT_LIST_DIR}) + +include_directories (${WASI_NN_DIR}) +include_directories (${WASI_NN_DIR}/src) +include_directories (${WASI_NN_DIR}/src/utils) + +set ( + LIBC_WASI_NN_SOURCE + ${WASI_NN_DIR}/src/wasi_nn.c + ${WASI_NN_DIR}/src/wasi_nn_tensorflowlite.cpp + ${WASI_NN_DIR}/src/utils/wasi_nn_app_native.c +) + +set (TENSORFLOW_LIB tensorflow-lite) diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/wasi_nn.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/wasi_nn.h new file mode 100644 index 00000000000..2bf0a192c82 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/wasi_nn.h @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +/** + * Following definition from: + * [Oct 25th, 2022] + * https://github.com/WebAssembly/wasi-nn/blob/0f77c48ec195748990ff67928a4b3eef5f16c2de/wasi-nn.wit.md + */ + +#ifndef WASI_NN_H +#define WASI_NN_H + +#include +#include "wasi_nn_types.h" + +/** + * @brief Load an opaque sequence of bytes to use for inference. + * + * @param builder Model builder. + * @param encoding Model encoding. + * @param target Execution target. + * @param g Graph. + * @return error Execution status. + */ +error +load(graph_builder_array *builder, graph_encoding encoding, + execution_target target, graph *g) + __attribute__((import_module("wasi_nn"))); + +/** + * INFERENCE + * + */ + +// Bind a `graph` to the input and output tensors for an inference. +typedef uint32_t graph_execution_context; + +/** + * @brief Create an execution instance of a loaded graph. + * + * @param g Graph. + * @param ctx Execution context. + * @return error Execution status. + */ +error +init_execution_context(graph g, graph_execution_context *ctx) + __attribute__((import_module("wasi_nn"))); + +/** + * @brief Define the inputs to use for inference. + * + * @param ctx Execution context. + * @param index Input tensor index. + * @param tensor Input tensor. + * @return error Execution status. + */ +error +set_input(graph_execution_context ctx, uint32_t index, tensor *tensor) + __attribute__((import_module("wasi_nn"))); + +/** + * @brief Compute the inference on the given inputs. + * + * @param ctx Execution context. + * @return error Execution status. + */ +error +compute(graph_execution_context ctx) __attribute__((import_module("wasi_nn"))); + +/** + * @brief Extract the outputs after inference. + * + * @param ctx Execution context. + * @param index Output tensor index. + * @param output_tensor Buffer where output tensor with index `index` is + * copied. + * @param output_tensor_size Pointer to `output_tensor` maximum size. + * After the function call it is updated with the + * copied number of bytes. + * @return error Execution status. + */ +error +get_output(graph_execution_context ctx, uint32_t index, + tensor_data output_tensor, uint32_t *output_tensor_size) + __attribute__((import_module("wasi_nn"))); + +#endif diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/wasi_nn_types.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/wasi_nn_types.h new file mode 100644 index 00000000000..a2cebe49ecb --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/wasi_nn_types.h @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef WASI_NN_TYPES_H +#define WASI_NN_TYPES_H + +/** + * ERRORS + * + */ + +// Error codes returned by functions in this API. +typedef enum { + // No error occurred. + success = 0, + // Caller module passed an invalid argument. + invalid_argument, + // Invalid encoding. + invalid_encoding, + // Caller module is missing a memory export. + missing_memory, + // Device or resource busy. + busy, + // Runtime Error. + runtime_error, +} error; + +/** + * TENSOR + * + */ + +// The dimensions of a tensor. +// +// The array length matches the tensor rank and each element in the array +// describes the size of each dimension. +typedef struct { + uint32_t *buf; + uint32_t size; +} tensor_dimensions; + +// The type of the elements in a tensor. +typedef enum { fp16 = 0, fp32, up8, ip32 } tensor_type; + +// The tensor data. +// +// Initially conceived as a sparse representation, each empty cell would be +// filled with zeros and the array length must match the product of all of the +// dimensions and the number of bytes in the type (e.g., a 2x2 tensor with +// 4-byte f32 elements would have a data array of length 16). Naturally, this +// representation requires some knowledge of how to lay out data in +// memory--e.g., using row-major ordering--and could perhaps be improved. +typedef uint8_t *tensor_data; + +// A tensor. +typedef struct { + // Describe the size of the tensor (e.g., 2x2x2x2 -> [2, 2, 2, 2]). To + // represent a tensor containing a single value, use `[1]` for the tensor + // dimensions. + tensor_dimensions *dimensions; + // Describe the type of element in the tensor (e.g., f32). + tensor_type type; + // Contains the tensor data. + tensor_data data; +} tensor; + +/** + * GRAPH + * + */ + +// The graph initialization data. +// +// This consists of an array of buffers because implementing backends may encode +// their graph IR in parts (e.g., OpenVINO stores its IR and weights +// separately). +typedef struct { + uint8_t *buf; + uint32_t size; +} graph_builder; + +typedef struct { + graph_builder *buf; + uint32_t size; +} graph_builder_array; + +// An execution graph for performing inference (i.e., a model). +typedef uint32_t graph; + +// Describes the encoding of the graph. This allows the API to be implemented by +// various backends that encode (i.e., serialize) their graph IR with different +// formats. +typedef enum { + openvino = 0, + onnx, + tensorflow, + pytorch, + tensorflowlite +} graph_encoding; + +// Define where the graph should be executed. +typedef enum execution_target { cpu = 0, gpu, tpu } execution_target; + +#endif diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/coap/er-coap/LICENSE.md b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/coap/er-coap/LICENSE.md similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/coap/er-coap/LICENSE.md rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/coap/er-coap/LICENSE.md diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/coap/er-coap/coap-constants.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/coap/er-coap/coap-constants.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/coap/er-coap/coap-constants.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/coap/er-coap/coap-constants.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/coap/extension/coap_ext.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/coap/extension/coap_ext.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/coap/extension/coap_ext.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/coap/extension/coap_ext.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/coap/lib_coap.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/coap/lib_coap.cmake similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/coap/lib_coap.cmake rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/coap/lib_coap.cmake diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/mem-alloc/SConscript b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/mem-alloc/SConscript similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/mem-alloc/SConscript rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/mem-alloc/SConscript diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/mem-alloc/ems/ems_alloc.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/mem-alloc/ems/ems_alloc.c similarity index 96% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/mem-alloc/ems/ems_alloc.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/mem-alloc/ems/ems_alloc.c index 6f03fa58fc1..5c2a628a261 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/mem-alloc/ems/ems_alloc.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/mem-alloc/ems/ems_alloc.c @@ -25,7 +25,7 @@ static bool remove_tree_node(gc_heap_t *heap, hmu_tree_node_t *p) { hmu_tree_node_t *q = NULL, **slot = NULL, *parent; - hmu_tree_node_t *root = &heap->kfc_tree_root; + hmu_tree_node_t *root = heap->kfc_tree_root; gc_uint8 *base_addr = heap->base_addr; gc_uint8 *end_addr = base_addr + heap->current_size; @@ -38,13 +38,17 @@ remove_tree_node(gc_heap_t *heap, hmu_tree_node_t *p) goto fail; } - /* get the slot which holds pointer to node p*/ + /* get the slot which holds pointer to node p */ if (p == p->parent->right) { - slot = &p->parent->right; + /* Don't use `slot = &p->parent->right` to avoid compiler warning */ + slot = (hmu_tree_node_t **)((uint8 *)p->parent + + offsetof(hmu_tree_node_t, right)); } else if (p == p->parent->left) { - /* p should be a child of its parent*/ - slot = &p->parent->left; + /* p should be a child of its parent */ + /* Don't use `slot = &p->parent->left` to avoid compiler warning */ + slot = (hmu_tree_node_t **)((uint8 *)p->parent + + offsetof(hmu_tree_node_t, left)); } else { goto fail; @@ -241,7 +245,7 @@ gci_add_fc(gc_heap_t *heap, hmu_t *hmu, gc_size_t size) node->left = node->right = node->parent = NULL; /* find proper node to link this new node to */ - root = &heap->kfc_tree_root; + root = heap->kfc_tree_root; tp = root; bh_assert(tp->size < size); while (1) { @@ -289,6 +293,7 @@ alloc_hmu(gc_heap_t *heap, gc_size_t size) uint32 node_idx = 0, init_node_idx = 0; hmu_tree_node_t *root = NULL, *tp = NULL, *last_tp = NULL; hmu_t *next, *rest; + uintptr_t tp_ret; bh_assert(gci_is_heap_valid(heap)); bh_assert(size > 0 && !(size & 7)); @@ -354,7 +359,7 @@ alloc_hmu(gc_heap_t *heap, gc_size_t size) } /* need to find a node in tree*/ - root = &heap->kfc_tree_root; + root = heap->kfc_tree_root; /* find the best node*/ bh_assert(root); @@ -402,7 +407,8 @@ alloc_hmu(gc_heap_t *heap, gc_size_t size) heap->highmark_size = heap->current_size - heap->total_free_size; hmu_set_size((hmu_t *)last_tp, size); - return (hmu_t *)last_tp; + tp_ret = (uintptr_t)last_tp; + return (hmu_t *)tp_ret; } return NULL; diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/mem-alloc/ems/ems_gc.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/mem-alloc/ems/ems_gc.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/mem-alloc/ems/ems_gc.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/mem-alloc/ems/ems_gc.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/mem-alloc/ems/ems_gc_internal.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/mem-alloc/ems/ems_gc_internal.h similarity index 80% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/mem-alloc/ems/ems_gc_internal.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/mem-alloc/ems/ems_gc_internal.h index 39b1ff8f14a..e1ff9d61d85 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/mem-alloc/ems/ems_gc_internal.h +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/mem-alloc/ems/ems_gc_internal.h @@ -204,13 +204,47 @@ set_hmu_normal_node_next(hmu_normal_node_t *node, hmu_normal_node_t *next) } } +/** + * Define hmu_tree_node as a packed struct, since it is at the 4-byte + * aligned address and the size of hmu_head is 4, so in 64-bit target, + * the left/right/parent fields will be at 8-byte aligned address, + * we can access them directly. + */ +#if UINTPTR_MAX == UINT64_MAX +#if defined(_MSC_VER) +__pragma(pack(push, 1)); +#define __attr_packed +#elif defined(__GNUC__) || defined(__clang__) +#define __attr_packed __attribute__((packed)) +#else +#error "packed attribute isn't used to define struct hmu_tree_node" +#endif +#else /* else of UINTPTR_MAX == UINT64_MAX */ +#define __attr_packed +#endif + typedef struct hmu_tree_node { hmu_t hmu_header; - gc_size_t size; struct hmu_tree_node *left; struct hmu_tree_node *right; struct hmu_tree_node *parent; -} hmu_tree_node_t; + gc_size_t size; +} __attr_packed hmu_tree_node_t; + +#if UINTPTR_MAX == UINT64_MAX +#if defined(_MSC_VER) +__pragma(pack(pop)); +#endif +#endif + +bh_static_assert(sizeof(hmu_tree_node_t) == 8 + 3 * sizeof(void *)); +bh_static_assert(offsetof(hmu_tree_node_t, left) == 4); + +#define ASSERT_TREE_NODE_ALIGNED_ACCESS(tree_node) \ + do { \ + bh_assert((((uintptr_t)&tree_node->left) & (sizeof(uintptr_t) - 1)) \ + == 0); \ + } while (0) typedef struct gc_heap_struct { /* for double checking*/ @@ -223,8 +257,16 @@ typedef struct gc_heap_struct { hmu_normal_list_t kfc_normal_list[HMU_NORMAL_NODE_CNT]; - /* order in kfc_tree is: size[left] <= size[cur] < size[right]*/ - hmu_tree_node_t kfc_tree_root; +#if UINTPTR_MAX == UINT64_MAX + /* make kfc_tree_root_buf 4-byte aligned and not 8-byte aligned, + so kfc_tree_root's left/right/parent fields are 8-byte aligned + and we can access them directly */ + uint32 __padding; +#endif + uint8 kfc_tree_root_buf[sizeof(hmu_tree_node_t)]; + /* point to kfc_tree_root_buf, the order in kfc_tree is: + size[left] <= size[cur] < size[right] */ + hmu_tree_node_t *kfc_tree_root; /* whether heap is corrupted, e.g. the hmu nodes are modified by user */ diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/mem-alloc/ems/ems_hmu.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/mem-alloc/ems/ems_hmu.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/mem-alloc/ems/ems_hmu.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/mem-alloc/ems/ems_hmu.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/mem-alloc/ems/ems_kfc.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/mem-alloc/ems/ems_kfc.c similarity index 84% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/mem-alloc/ems/ems_kfc.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/mem-alloc/ems/ems_kfc.c index cb405fd165b..80d20267943 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/mem-alloc/ems/ems_kfc.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/mem-alloc/ems/ems_kfc.c @@ -12,7 +12,6 @@ gc_init_internal(gc_heap_t *heap, char *base_addr, gc_size_t heap_max_size) int ret; memset(heap, 0, sizeof *heap); - memset(base_addr, 0, heap_max_size); ret = os_mutex_init(&heap->lock); if (ret != BHT_OK) { @@ -28,7 +27,7 @@ gc_init_internal(gc_heap_t *heap, char *base_addr, gc_size_t heap_max_size) heap->total_free_size = heap->current_size; heap->highmark_size = 0; - root = &heap->kfc_tree_root; + root = heap->kfc_tree_root = (hmu_tree_node_t *)heap->kfc_tree_root_buf; memset(root, 0, sizeof *root); root->size = sizeof *root; hmu_set_ut(&root->hmu_header, HMU_FC); @@ -39,6 +38,9 @@ gc_init_internal(gc_heap_t *heap, char *base_addr, gc_size_t heap_max_size) hmu_set_ut(&q->hmu_header, HMU_FC); hmu_set_size(&q->hmu_header, heap->current_size); + ASSERT_TREE_NODE_ALIGNED_ACCESS(q); + ASSERT_TREE_NODE_ALIGNED_ACCESS(root); + hmu_mark_pinuse(&q->hmu_header); root->right = q; q->parent = root; @@ -140,7 +142,6 @@ gc_destroy_with_pool(gc_handle_t handle) #endif os_mutex_destroy(&heap->lock); - memset(heap->base_addr, 0, heap->current_size); memset(heap, 0, sizeof(gc_heap_t)); return ret; } @@ -155,7 +156,7 @@ static void adjust_ptr(uint8 **p_ptr, intptr_t offset) { if (*p_ptr) - *p_ptr += offset; + *p_ptr = (uint8 *)((intptr_t)(*p_ptr) + offset); } int @@ -167,6 +168,7 @@ gc_migrate(gc_handle_t handle, char *pool_buf_new, gc_size_t pool_buf_size) intptr_t offset = (uint8 *)base_addr_new - (uint8 *)heap->base_addr; hmu_t *cur = NULL, *end = NULL; hmu_tree_node_t *tree_node; + uint8 **p_left, **p_right, **p_parent; gc_size_t heap_max_size, size; if ((((uintptr_t)pool_buf_new) & 7) != 0) { @@ -190,9 +192,18 @@ gc_migrate(gc_handle_t handle, char *pool_buf_new, gc_size_t pool_buf_size) } heap->base_addr = (uint8 *)base_addr_new; - adjust_ptr((uint8 **)&heap->kfc_tree_root.left, offset); - adjust_ptr((uint8 **)&heap->kfc_tree_root.right, offset); - adjust_ptr((uint8 **)&heap->kfc_tree_root.parent, offset); + + ASSERT_TREE_NODE_ALIGNED_ACCESS(heap->kfc_tree_root); + + p_left = (uint8 **)((uint8 *)heap->kfc_tree_root + + offsetof(hmu_tree_node_t, left)); + p_right = (uint8 **)((uint8 *)heap->kfc_tree_root + + offsetof(hmu_tree_node_t, right)); + p_parent = (uint8 **)((uint8 *)heap->kfc_tree_root + + offsetof(hmu_tree_node_t, parent)); + adjust_ptr(p_left, offset); + adjust_ptr(p_right, offset); + adjust_ptr(p_parent, offset); cur = (hmu_t *)heap->base_addr; end = (hmu_t *)((char *)heap->base_addr + heap->current_size); @@ -208,12 +219,21 @@ gc_migrate(gc_handle_t handle, char *pool_buf_new, gc_size_t pool_buf_size) if (hmu_get_ut(cur) == HMU_FC && !HMU_IS_FC_NORMAL(size)) { tree_node = (hmu_tree_node_t *)cur; - adjust_ptr((uint8 **)&tree_node->left, offset); - adjust_ptr((uint8 **)&tree_node->right, offset); - if (tree_node->parent != &heap->kfc_tree_root) + + ASSERT_TREE_NODE_ALIGNED_ACCESS(tree_node); + + p_left = (uint8 **)((uint8 *)tree_node + + offsetof(hmu_tree_node_t, left)); + p_right = (uint8 **)((uint8 *)tree_node + + offsetof(hmu_tree_node_t, right)); + p_parent = (uint8 **)((uint8 *)tree_node + + offsetof(hmu_tree_node_t, parent)); + adjust_ptr(p_left, offset); + adjust_ptr(p_right, offset); + if (tree_node->parent != heap->kfc_tree_root) /* The root node belongs to heap structure, it is fixed part and isn't changed. */ - adjust_ptr((uint8 **)&tree_node->parent, offset); + adjust_ptr(p_parent, offset); } cur = (hmu_t *)((char *)cur + size); } diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/mem-alloc/mem_alloc.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/mem-alloc/mem_alloc.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/mem-alloc/mem_alloc.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/mem-alloc/mem_alloc.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/mem-alloc/mem_alloc.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/mem-alloc/mem_alloc.cmake similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/mem-alloc/mem_alloc.cmake rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/mem-alloc/mem_alloc.cmake diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/mem-alloc/mem_alloc.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/mem-alloc/mem_alloc.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/mem-alloc/mem_alloc.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/mem-alloc/mem_alloc.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/README.md b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/README.md similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/README.md rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/README.md diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/alios/alios_platform.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/alios/alios_platform.c similarity index 91% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/alios/alios_platform.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/alios/alios_platform.c index 64185873739..c9f5f17e641 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/alios/alios_platform.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/alios/alios_platform.c @@ -40,6 +40,12 @@ void os_free(void *ptr) {} +int +os_dumps_proc_mem_info(char *out, unsigned int size) +{ + return -1; +} + void * os_mmap(void *hint, size_t size, int prot, int flags) { diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/alios/alios_thread.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/alios/alios_thread.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/alios/alios_thread.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/alios/alios_thread.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/alios/alios_time.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/alios/alios_time.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/alios/alios_time.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/alios/alios_time.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/alios/platform_internal.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/alios/platform_internal.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/alios/platform_internal.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/alios/platform_internal.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/alios/shared_platform.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/alios/shared_platform.cmake similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/alios/shared_platform.cmake rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/alios/shared_platform.cmake diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/android/platform_init.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/android/platform_init.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/android/platform_init.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/android/platform_init.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/android/platform_internal.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/android/platform_internal.h similarity index 97% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/android/platform_internal.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/android/platform_internal.h index 3adc8726ee2..521fa0c555b 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/android/platform_internal.h +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/android/platform_internal.h @@ -57,6 +57,8 @@ typedef pthread_cond_t korp_cond; typedef pthread_t korp_thread; typedef sem_t korp_sem; +#define OS_THREAD_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER + #define os_thread_local_attribute __thread #define bh_socket_t int diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/android/shared_platform.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/android/shared_platform.cmake similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/android/shared_platform.cmake rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/android/shared_platform.cmake diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/common/freertos/freertos_malloc.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/common/freertos/freertos_malloc.c similarity index 80% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/common/freertos/freertos_malloc.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/common/freertos/freertos_malloc.c index 19cf4d5f1d6..e47a8cce16b 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/common/freertos/freertos_malloc.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/common/freertos/freertos_malloc.c @@ -20,3 +20,9 @@ os_realloc(void *ptr, unsigned size) void os_free(void *ptr) {} + +int +os_dumps_proc_mem_info(char *out, unsigned int size) +{ + return -1; +} diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/common/freertos/freertos_thread.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/common/freertos/freertos_thread.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/common/freertos/freertos_thread.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/common/freertos/freertos_thread.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/common/freertos/freertos_time.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/common/freertos/freertos_time.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/common/freertos/freertos_time.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/common/freertos/freertos_time.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/common/freertos/platform_api_freertos.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/common/freertos/platform_api_freertos.cmake similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/common/freertos/platform_api_freertos.cmake rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/common/freertos/platform_api_freertos.cmake diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/common/math/COPYRIGHT b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/common/math/COPYRIGHT similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/common/math/COPYRIGHT rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/common/math/COPYRIGHT diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/common/math/math.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/common/math/math.c similarity index 99% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/common/math/math.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/common/math/math.c index a9fcf021952..2ba9f4d28b2 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/common/math/math.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/common/math/math.c @@ -449,8 +449,6 @@ ivln2 = 1.44269504088896338700e+00, /* 0x3FF71547, 0x652B82FE =1/ln2 */ ivln2_h = 1.44269502162933349609e+00, /* 0x3FF71547, 0x60000000 =24b 1/ln2*/ ivln2_l = 1.92596299112661746887e-08; /* 0x3E54AE0B, 0xF85DDF44 =1/ln2 tail*/ -static double -freebsd_sqrt(double x); static double freebsd_floor(double x); static double @@ -622,6 +620,7 @@ freebsd_atan2(double y, double x) } } +#ifndef BH_HAS_SQRTF static float freebsd_sqrtf(float x) { @@ -689,7 +688,9 @@ freebsd_sqrtf(float x) SET_FLOAT_WORD(z, ix); return z; } +#endif /* end of BH_HAS_SQRTF */ +#ifndef BH_HAS_SQRT static double freebsd_sqrt(double x) /* wrapper sqrt */ { @@ -799,6 +800,7 @@ freebsd_sqrt(double x) /* wrapper sqrt */ return z; } +#endif /* end of BH_HAS_SQRT */ static double freebsd_floor(double x) @@ -1554,11 +1556,13 @@ atan2(double y, double x) return freebsd_atan2(y, x); } +#ifndef BH_HAS_SQRT double sqrt(double x) { return freebsd_sqrt(x); } +#endif double floor(double x) @@ -1656,11 +1660,13 @@ fmaxf(float x, float y) return freebsd_fmaxf(x, y); } +#ifndef BH_HAS_SQRTF float sqrtf(float x) { return freebsd_sqrtf(x); } +#endif double pow(double x, double y) diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/common/math/platform_api_math.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/common/math/platform_api_math.cmake similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/common/math/platform_api_math.cmake rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/common/math/platform_api_math.cmake diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/common/posix/platform_api_posix.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/common/posix/platform_api_posix.cmake similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/common/posix/platform_api_posix.cmake rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/common/posix/platform_api_posix.cmake diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/common/posix/posix_malloc.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/common/posix/posix_malloc.c new file mode 100644 index 00000000000..912998ee071 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/common/posix/posix_malloc.c @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "platform_api_vmcore.h" + +void * +os_malloc(unsigned size) +{ + return malloc(size); +} + +void * +os_realloc(void *ptr, unsigned size) +{ + return realloc(ptr, size); +} + +void +os_free(void *ptr) +{ + free(ptr); +} + +int +os_dumps_proc_mem_info(char *out, unsigned int size) +{ + int ret = -1; + FILE *f; + char line[128] = { 0 }; + unsigned int out_idx = 0; + + if (!out || !size) + goto quit; + + f = fopen("/proc/self/status", "r"); + if (!f) { + perror("fopen failed: "); + goto quit; + } + + memset(out, 0, size); + + while (fgets(line, sizeof(line), f)) { +#if WASM_ENABLE_MEMORY_PROFILING != 0 + if (strncmp(line, "Vm", 2) == 0 || strncmp(line, "Rss", 3) == 0) { +#else + if (strncmp(line, "VmRSS", 5) == 0 + || strncmp(line, "RssAnon", 7) == 0) { +#endif + size_t line_len = strlen(line); + if (line_len >= size - 1 - out_idx) + goto close_file; + + /* copying without null-terminated byte */ + memcpy(out + out_idx, line, line_len); + out_idx += line_len; + } + } + + if (ferror(f)) { + perror("fgets failed: "); + goto close_file; + } + + ret = 0; +close_file: + fclose(f); +quit: + return ret; +} \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/common/posix/posix_memmap.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/common/posix/posix_memmap.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/common/posix/posix_memmap.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/common/posix/posix_memmap.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/common/posix/posix_socket.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/common/posix/posix_socket.c similarity index 94% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/common/posix/posix_socket.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/common/posix/posix_socket.c index a720874f705..e33781d7d2e 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/common/posix/posix_socket.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/common/posix/posix_socket.c @@ -16,7 +16,9 @@ textual_addr_to_sockaddr(const char *textual, int port, struct sockaddr *out, socklen_t *out_len) { struct sockaddr_in *v4; +#ifdef IPPROTO_IPV6 struct sockaddr_in6 *v6; +#endif assert(textual); @@ -28,6 +30,7 @@ textual_addr_to_sockaddr(const char *textual, int port, struct sockaddr *out, return true; } +#ifdef IPPROTO_IPV6 v6 = (struct sockaddr_in6 *)out; if (inet_pton(AF_INET6, textual, &v6->sin6_addr.s6_addr) == 1) { v6->sin6_family = AF_INET6; @@ -35,12 +38,13 @@ textual_addr_to_sockaddr(const char *textual, int port, struct sockaddr *out, *out_len = sizeof(struct sockaddr_in6); return true; } +#endif return false; } static int -sockaddr_to_bh_sockaddr(const struct sockaddr *sockaddr, socklen_t socklen, +sockaddr_to_bh_sockaddr(const struct sockaddr *sockaddr, bh_sockaddr_t *bh_sockaddr) { switch (sockaddr->sa_family) { @@ -48,20 +52,17 @@ sockaddr_to_bh_sockaddr(const struct sockaddr *sockaddr, socklen_t socklen, { struct sockaddr_in *addr = (struct sockaddr_in *)sockaddr; - assert(socklen >= sizeof(struct sockaddr_in)); - bh_sockaddr->port = ntohs(addr->sin_port); bh_sockaddr->addr_bufer.ipv4 = ntohl(addr->sin_addr.s_addr); bh_sockaddr->is_ipv4 = true; return BHT_OK; } +#ifdef IPPROTO_IPV6 case AF_INET6: { struct sockaddr_in6 *addr = (struct sockaddr_in6 *)sockaddr; size_t i; - assert(socklen >= sizeof(struct sockaddr_in6)); - bh_sockaddr->port = ntohs(addr->sin6_port); for (i = 0; i < sizeof(bh_sockaddr->addr_bufer.ipv6) @@ -75,6 +76,7 @@ sockaddr_to_bh_sockaddr(const struct sockaddr *sockaddr, socklen_t socklen, bh_sockaddr->is_ipv4 = false; return BHT_OK; } +#endif default: errno = EAFNOSUPPORT; return BHT_ERROR; @@ -92,6 +94,7 @@ bh_sockaddr_to_sockaddr(const bh_sockaddr_t *bh_sockaddr, addr->sin_addr.s_addr = htonl(bh_sockaddr->addr_bufer.ipv4); *socklen = sizeof(*addr); } +#ifdef IPPROTO_IPV6 else { struct sockaddr_in6 *addr = (struct sockaddr_in6 *)sockaddr; size_t i; @@ -108,6 +111,7 @@ bh_sockaddr_to_sockaddr(const bh_sockaddr_t *bh_sockaddr, *socklen = sizeof(*addr); } +#endif } int @@ -143,18 +147,18 @@ os_socket_bind(bh_socket_t socket, const char *host, int *port) ling.l_onoff = 1; ling.l_linger = 0; - ret = fcntl(socket, F_SETFD, FD_CLOEXEC); - if (ret < 0) { + if (!textual_addr_to_sockaddr(host, *port, (struct sockaddr *)&addr, + &socklen)) { goto fail; } - ret = setsockopt(socket, SOL_SOCKET, SO_LINGER, &ling, sizeof(ling)); + ret = fcntl(socket, F_SETFD, FD_CLOEXEC); if (ret < 0) { goto fail; } - if (!textual_addr_to_sockaddr(host, *port, (struct sockaddr *)&addr, - &socklen)) { + ret = setsockopt(socket, SOL_SOCKET, SO_LINGER, &ling, sizeof(ling)); + if (ret < 0) { goto fail; } @@ -168,9 +172,16 @@ os_socket_bind(bh_socket_t socket, const char *host, int *port) goto fail; } - *port = ntohs(addr.ss_family == AF_INET - ? ((struct sockaddr_in *)&addr)->sin_port - : ((struct sockaddr_in6 *)&addr)->sin6_port); + if (addr.ss_family == AF_INET) { + *port = ntohs(((struct sockaddr_in *)&addr)->sin_port); + } + else { +#ifdef IPPROTO_IPV6 + *port = ntohs(((struct sockaddr_in6 *)&addr)->sin6_port); +#else + goto fail; +#endif + } return BHT_OK; @@ -208,10 +219,7 @@ int os_socket_accept(bh_socket_t server_sock, bh_socket_t *sock, void *addr, unsigned int *addrlen) { - struct sockaddr addr_tmp; - unsigned int len = sizeof(struct sockaddr); - - *sock = accept(server_sock, &addr_tmp, &len); + *sock = accept(server_sock, addr, addrlen); if (*sock < 0) { return BHT_ERROR; @@ -262,8 +270,7 @@ os_socket_recv_from(bh_socket_t socket, void *buf, unsigned int len, int flags, } if (src_addr && socklen > 0) { - if (sockaddr_to_bh_sockaddr((struct sockaddr *)&sock_addr, socklen, - src_addr) + if (sockaddr_to_bh_sockaddr((struct sockaddr *)&sock_addr, src_addr) == BHT_ERROR) { return -1; } @@ -287,7 +294,7 @@ os_socket_send_to(bh_socket_t socket, const void *buf, unsigned int len, bh_sockaddr_to_sockaddr(dest_addr, &sock_addr, &socklen); - return sendto(socket, buf, len, 0, (const struct sockaddr *)&sock_addr, + return sendto(socket, buf, len, flags, (const struct sockaddr *)&sock_addr, socklen); } @@ -319,12 +326,17 @@ os_socket_inet_network(bool is_ipv4, const char *cp, bh_ip_addr_buffer_t *out) out->ipv4 = ntohl(out->ipv4); } else { +#ifdef IPPROTO_IPV6 if (inet_pton(AF_INET6, cp, out->ipv6) != 1) { return BHT_ERROR; } for (int i = 0; i < 8; i++) { out->ipv6[i] = ntohs(out->ipv6[i]); } +#else + errno = EAFNOSUPPORT; + return BHT_ERROR; +#endif } return BHT_OK; @@ -394,9 +406,8 @@ os_socket_addr_resolve(const char *host, const char *service, continue; } - ret = sockaddr_to_bh_sockaddr(res->ai_addr, - sizeof(struct sockaddr_in), - &addr_info[pos].sockaddr); + ret = + sockaddr_to_bh_sockaddr(res->ai_addr, &addr_info[pos].sockaddr); if (ret == BHT_ERROR) { freeaddrinfo(result); @@ -746,8 +757,13 @@ int os_socket_set_ip_multicast_loop(bh_socket_t socket, bool ipv6, bool is_enabled) { if (ipv6) { +#ifdef IPPROTO_IPV6 return os_socket_setbooloption(socket, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, is_enabled); +#else + errno = EAFNOSUPPORT; + return BHT_ERROR; +#endif } else { return os_socket_setbooloption(socket, IPPROTO_IP, IP_MULTICAST_LOOP, @@ -759,8 +775,13 @@ int os_socket_get_ip_multicast_loop(bh_socket_t socket, bool ipv6, bool *is_enabled) { if (ipv6) { +#ifdef IPPROTO_IPV6 return os_socket_getbooloption(socket, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, is_enabled); +#else + errno = EAFNOSUPPORT; + return BHT_ERROR; +#endif } else { return os_socket_getbooloption(socket, IPPROTO_IP, IP_MULTICAST_LOOP, @@ -775,6 +796,7 @@ os_socket_set_ip_add_membership(bh_socket_t socket, { assert(imr_multiaddr); if (is_ipv6) { +#ifdef IPPROTO_IPV6 struct ipv6_mreq mreq; for (int i = 0; i < 8; i++) { ((uint16_t *)mreq.ipv6mr_multiaddr.s6_addr)[i] = @@ -786,6 +808,10 @@ os_socket_set_ip_add_membership(bh_socket_t socket, != 0) { return BHT_ERROR; } +#else + errno = EAFNOSUPPORT; + return BHT_ERROR; +#endif } else { struct ip_mreq mreq; @@ -808,6 +834,7 @@ os_socket_set_ip_drop_membership(bh_socket_t socket, { assert(imr_multiaddr); if (is_ipv6) { +#ifdef IPPROTO_IPV6 struct ipv6_mreq mreq; for (int i = 0; i < 8; i++) { ((uint16_t *)mreq.ipv6mr_multiaddr.s6_addr)[i] = @@ -819,6 +846,10 @@ os_socket_set_ip_drop_membership(bh_socket_t socket, != 0) { return BHT_ERROR; } +#else + errno = EAFNOSUPPORT; + return BHT_ERROR; +#endif } else { struct ip_mreq mreq; @@ -881,15 +912,25 @@ os_socket_get_ip_multicast_ttl(bh_socket_t socket, uint8_t *ttl_s) int os_socket_set_ipv6_only(bh_socket_t socket, bool is_enabled) { +#ifdef IPPROTO_IPV6 return os_socket_setbooloption(socket, IPPROTO_IPV6, IPV6_V6ONLY, is_enabled); +#else + errno = EAFNOSUPPORT; + return BHT_ERROR; +#endif } int os_socket_get_ipv6_only(bh_socket_t socket, bool *is_enabled) { +#ifdef IPPROTO_IPV6 return os_socket_getbooloption(socket, IPPROTO_IPV6, IPV6_V6ONLY, is_enabled); +#else + errno = EAFNOSUPPORT; + return BHT_ERROR; +#endif } int @@ -967,8 +1008,7 @@ os_socket_addr_local(bh_socket_t socket, bh_sockaddr_t *sockaddr) return BHT_ERROR; } - return sockaddr_to_bh_sockaddr((struct sockaddr *)&addr_storage, addr_len, - sockaddr); + return sockaddr_to_bh_sockaddr((struct sockaddr *)&addr_storage, sockaddr); } int @@ -984,6 +1024,5 @@ os_socket_addr_remote(bh_socket_t socket, bh_sockaddr_t *sockaddr) return BHT_ERROR; } - return sockaddr_to_bh_sockaddr((struct sockaddr *)&addr_storage, addr_len, - sockaddr); + return sockaddr_to_bh_sockaddr((struct sockaddr *)&addr_storage, sockaddr); } diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/common/posix/posix_thread.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/common/posix/posix_thread.c similarity index 95% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/common/posix/posix_thread.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/common/posix/posix_thread.c index 44b4135b4b3..5e814c41824 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/common/posix/posix_thread.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/common/posix/posix_thread.c @@ -61,8 +61,9 @@ os_thread_create_with_prio(korp_tid *tid, thread_start_routine_t start, pthread_attr_init(&tattr); pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_JOINABLE); if (pthread_attr_setstacksize(&tattr, stack_size) != 0) { - os_printf("Invalid thread stack size %u. Min stack size on Linux = %u", - stack_size, PTHREAD_STACK_MIN); + os_printf("Invalid thread stack size %u. " + "Min stack size on Linux = %u\n", + stack_size, (unsigned int)PTHREAD_STACK_MIN); pthread_attr_destroy(&tattr); return BHT_ERROR; } @@ -425,6 +426,7 @@ os_thread_get_stack_boundary() */ static os_thread_local_attribute bool thread_signal_inited = false; +#if WASM_DISABLE_STACK_HW_BOUND_CHECK == 0 /* The signal alternate stack base addr */ static os_thread_local_attribute uint8 *sigalt_stack_base_addr; @@ -488,6 +490,7 @@ destroy_stack_guard_pages() os_mprotect(stack_min_addr, page_size * guard_page_count, MMAP_PROT_READ | MMAP_PROT_WRITE); } +#endif /* end of WASM_DISABLE_STACK_HW_BOUND_CHECK == 0 */ static void mask_signals(int how) @@ -553,13 +556,16 @@ int os_thread_signal_init(os_signal_handler handler) { struct sigaction sig_act; +#if WASM_DISABLE_STACK_HW_BOUND_CHECK == 0 stack_t sigalt_stack_info; uint32 map_size = SIG_ALT_STACK_SIZE; uint8 *map_addr; +#endif if (thread_signal_inited) return 0; +#if WASM_DISABLE_STACK_HW_BOUND_CHECK == 0 if (!init_stack_guard_pages()) { os_printf("Failed to init stack guard pages\n"); return -1; @@ -581,13 +587,17 @@ os_thread_signal_init(os_signal_handler handler) os_printf("Failed to init signal alternate stack\n"); goto fail2; } +#endif memset(&prev_sig_act_SIGSEGV, 0, sizeof(struct sigaction)); memset(&prev_sig_act_SIGBUS, 0, sizeof(struct sigaction)); /* Install signal hanlder */ sig_act.sa_sigaction = signal_callback; - sig_act.sa_flags = SA_SIGINFO | SA_ONSTACK | SA_NODEFER; + sig_act.sa_flags = SA_SIGINFO | SA_NODEFER; +#if WASM_DISABLE_STACK_HW_BOUND_CHECK == 0 + sig_act.sa_flags |= SA_ONSTACK; +#endif sigemptyset(&sig_act.sa_mask); if (sigaction(SIGSEGV, &sig_act, &prev_sig_act_SIGSEGV) != 0 || sigaction(SIGBUS, &sig_act, &prev_sig_act_SIGBUS) != 0) { @@ -595,12 +605,15 @@ os_thread_signal_init(os_signal_handler handler) goto fail3; } +#if WASM_DISABLE_STACK_HW_BOUND_CHECK == 0 sigalt_stack_base_addr = map_addr; +#endif signal_handler = handler; thread_signal_inited = true; return 0; fail3: +#if WASM_DISABLE_STACK_HW_BOUND_CHECK == 0 memset(&sigalt_stack_info, 0, sizeof(stack_t)); sigalt_stack_info.ss_flags = SS_DISABLE; sigalt_stack_info.ss_size = map_size; @@ -609,17 +622,21 @@ os_thread_signal_init(os_signal_handler handler) os_munmap(map_addr, map_size); fail1: destroy_stack_guard_pages(); +#endif return -1; } void os_thread_signal_destroy() { +#if WASM_DISABLE_STACK_HW_BOUND_CHECK == 0 stack_t sigalt_stack_info; +#endif if (!thread_signal_inited) return; +#if WASM_DISABLE_STACK_HW_BOUND_CHECK == 0 /* Disable signal alternate stack */ memset(&sigalt_stack_info, 0, sizeof(stack_t)); sigalt_stack_info.ss_flags = SS_DISABLE; @@ -629,6 +646,7 @@ os_thread_signal_destroy() os_munmap(sigalt_stack_base_addr, SIG_ALT_STACK_SIZE); destroy_stack_guard_pages(); +#endif thread_signal_inited = false; } @@ -648,6 +666,7 @@ os_signal_unmask() void os_sigreturn() { +#if WASM_DISABLE_STACK_HW_BOUND_CHECK == 0 #if defined(__APPLE__) #define UC_RESET_ALT_STACK 0x80000000 extern int __sigreturn(void *, int); @@ -656,5 +675,6 @@ os_sigreturn() after exiting the signal handler. */ __sigreturn(NULL, UC_RESET_ALT_STACK); #endif +#endif } #endif /* end of OS_ENABLE_HW_BOUND_CHECK */ diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/common/posix/posix_time.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/common/posix/posix_time.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/common/posix/posix_time.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/common/posix/posix_time.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/darwin/platform_init.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/darwin/platform_init.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/darwin/platform_init.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/darwin/platform_init.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/darwin/platform_internal.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/darwin/platform_internal.h similarity index 97% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/darwin/platform_internal.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/darwin/platform_internal.h index 284e376e7b4..3fd1c258e25 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/darwin/platform_internal.h +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/darwin/platform_internal.h @@ -60,6 +60,8 @@ typedef pthread_cond_t korp_cond; typedef pthread_t korp_thread; typedef sem_t korp_sem; +#define OS_THREAD_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER + #define os_thread_local_attribute __thread #define bh_socket_t int diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/darwin/shared_platform.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/darwin/shared_platform.cmake similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/darwin/shared_platform.cmake rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/darwin/shared_platform.cmake diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/ego/platform_init.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/ego/platform_init.c new file mode 100644 index 00000000000..38a0e80492a --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/ego/platform_init.c @@ -0,0 +1,6 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "../linux/platform_init.c" \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/ego/platform_internal.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/ego/platform_internal.h new file mode 100644 index 00000000000..1ece346be65 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/ego/platform_internal.h @@ -0,0 +1,6 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "../linux/platform_internal.h" diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/ego/shared_platform.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/ego/shared_platform.cmake new file mode 100644 index 00000000000..9b84c58414c --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/ego/shared_platform.cmake @@ -0,0 +1,20 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +set (PLATFORM_SHARED_DIR ${CMAKE_CURRENT_LIST_DIR}) + +add_definitions(-DBH_PLATFORM_EGO) + +include_directories(${PLATFORM_SHARED_DIR}) +include_directories(${PLATFORM_SHARED_DIR}/../include) + +include (${CMAKE_CURRENT_LIST_DIR}/../common/posix/platform_api_posix.cmake) + +set (PLATFORM_SHARED_SOURCE + ${PLATFORM_COMMON_POSIX_SOURCE} + ${CMAKE_CURRENT_LIST_DIR}/platform_init.c +) + +LIST (APPEND RUNTIME_LIB_HEADER_LIST + ${CMAKE_CURRENT_LIST_DIR}/platform_internal.h +) \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/esp-idf/espidf_malloc.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/esp-idf/espidf_malloc.c similarity index 95% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/esp-idf/espidf_malloc.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/esp-idf/espidf_malloc.c index 8fde7c8d343..08ec883058b 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/esp-idf/espidf_malloc.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/esp-idf/espidf_malloc.c @@ -76,3 +76,9 @@ os_free(void *ptr) free(mem_origin); } } + +int +os_dumps_proc_mem_info(char *out, unsigned int size) +{ + return -1; +} diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/esp-idf/espidf_memmap.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/esp-idf/espidf_memmap.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/esp-idf/espidf_memmap.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/esp-idf/espidf_memmap.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/esp-idf/espidf_platform.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/esp-idf/espidf_platform.c similarity index 97% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/esp-idf/espidf_platform.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/esp-idf/espidf_platform.c index d05b19f503e..35b893d814f 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/esp-idf/espidf_platform.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/esp-idf/espidf_platform.c @@ -215,7 +215,7 @@ unlinkat(int fd, const char *path, int flag) } int -utimensat(int fd, const char *path, const struct timespec ts[2], int flag) +utimensat(int fd, const char *path, const struct timespec *ts, int flag) { errno = ENOSYS; return -1; @@ -238,7 +238,7 @@ ftruncate(int fd, off_t length) #endif int -futimens(int fd, const struct timespec times[2]) +futimens(int fd, const struct timespec *times) { errno = ENOSYS; return -1; diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/esp-idf/espidf_socket.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/esp-idf/espidf_socket.c new file mode 100644 index 00000000000..9f441b71218 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/esp-idf/espidf_socket.c @@ -0,0 +1,228 @@ +/* + * Copyright (C) 2021 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "platform_api_vmcore.h" +#include "platform_api_extension.h" + +#include + +static void +textual_addr_to_sockaddr(const char *textual, int port, struct sockaddr_in *out) +{ + assert(textual); + + out->sin_family = AF_INET; + out->sin_port = htons(port); + out->sin_addr.s_addr = inet_addr(textual); +} + +static int +sockaddr_to_bh_sockaddr(const struct sockaddr *sockaddr, socklen_t socklen, + bh_sockaddr_t *bh_sockaddr) +{ + switch (sockaddr->sa_family) { + case AF_INET: + { + struct sockaddr_in *addr = (struct sockaddr_in *)sockaddr; + + assert(socklen >= sizeof(struct sockaddr_in)); + + bh_sockaddr->port = ntohs(addr->sin_port); + bh_sockaddr->addr_bufer.ipv4 = ntohl(addr->sin_addr.s_addr); + bh_sockaddr->is_ipv4 = true; + return BHT_OK; + } + default: + errno = EAFNOSUPPORT; + return BHT_ERROR; + } +} + +int +os_socket_create(bh_socket_t *sock, bool is_ipv4, bool is_tcp) +{ + if (!sock) { + return BHT_ERROR; + } + + if (is_tcp) { + *sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + } + else { + *sock = socket(AF_INET, SOCK_DGRAM, 0); + } + + return (*sock == -1) ? BHT_ERROR : BHT_OK; +} + +int +os_socket_bind(bh_socket_t socket, const char *host, int *port) +{ + struct sockaddr_in addr; + socklen_t socklen; + int ret; + + assert(host); + assert(port); + + addr.sin_addr.s_addr = inet_addr(host); + addr.sin_port = htons(*port); + addr.sin_family = AF_INET; + + ret = bind(socket, (struct sockaddr *)&addr, sizeof(addr)); + if (ret < 0) { + goto fail; + } + + socklen = sizeof(addr); + if (getsockname(socket, (struct sockaddr *)&addr, &socklen) == -1) { + goto fail; + } + + *port = ntohs(addr.sin_port); + + return BHT_OK; + +fail: + return BHT_ERROR; +} + +int +os_socket_settimeout(bh_socket_t socket, uint64 timeout_us) +{ + struct timeval tv; + tv.tv_sec = timeout_us / 1000000UL; + tv.tv_usec = timeout_us % 1000000UL; + + if (setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (const char *)&tv, + sizeof(tv)) + != 0) { + return BHT_ERROR; + } + + return BHT_OK; +} + +int +os_socket_listen(bh_socket_t socket, int max_client) +{ + if (listen(socket, max_client) != 0) { + return BHT_ERROR; + } + + return BHT_OK; +} + +int +os_socket_accept(bh_socket_t server_sock, bh_socket_t *sock, void *addr, + unsigned int *addrlen) +{ + struct sockaddr addr_tmp; + socklen_t len = sizeof(struct sockaddr); + + *sock = accept(server_sock, (struct sockaddr *)&addr_tmp, &len); + + if (*sock < 0) { + return BHT_ERROR; + } + + return BHT_OK; +} + +int +os_socket_connect(bh_socket_t socket, const char *addr, int port) +{ + struct sockaddr_in addr_in = { 0 }; + socklen_t addr_len = sizeof(struct sockaddr_in); + int ret = 0; + + textual_addr_to_sockaddr(addr, port, &addr_in); + + ret = connect(socket, (struct sockaddr *)&addr_in, addr_len); + if (ret == -1) { + return BHT_ERROR; + } + + return BHT_OK; +} + +int +os_socket_recv(bh_socket_t socket, void *buf, unsigned int len) +{ + return recv(socket, buf, len, 0); +} + +int +os_socket_send(bh_socket_t socket, const void *buf, unsigned int len) +{ + return send(socket, buf, len, 0); +} + +int +os_socket_close(bh_socket_t socket) +{ + close(socket); + return BHT_OK; +} + +int +os_socket_shutdown(bh_socket_t socket) +{ + shutdown(socket, O_RDWR); + return BHT_OK; +} + +int +os_socket_inet_network(bool is_ipv4, const char *cp, bh_ip_addr_buffer_t *out) +{ + if (!cp) + return BHT_ERROR; + + if (is_ipv4) { + if (inet_pton(AF_INET, cp, &out->ipv4) != 1) { + return BHT_ERROR; + } + /* Note: ntohl(INADDR_NONE) == INADDR_NONE */ + out->ipv4 = ntohl(out->ipv4); + } + else { + if (inet_pton(AF_INET6, cp, out->ipv6) != 1) { + return BHT_ERROR; + } + for (int i = 0; i < 8; i++) { + out->ipv6[i] = ntohs(out->ipv6[i]); + } + } + + return BHT_OK; +} + +int +os_socket_addr_remote(bh_socket_t socket, bh_sockaddr_t *sockaddr) +{ + struct sockaddr_in addr; + socklen_t addr_len = sizeof(addr); + + if (getpeername(socket, (struct sockaddr *)&addr, &addr_len) == -1) { + return BHT_ERROR; + } + + return sockaddr_to_bh_sockaddr((struct sockaddr *)&addr, addr_len, + sockaddr); +} + +int +os_socket_addr_local(bh_socket_t socket, bh_sockaddr_t *sockaddr) +{ + struct sockaddr_in addr; + socklen_t addr_len = sizeof(addr); + + if (getsockname(socket, (struct sockaddr *)&addr, &addr_len) == -1) { + return BHT_ERROR; + } + + return sockaddr_to_bh_sockaddr((struct sockaddr *)&addr, addr_len, + sockaddr); +} diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/esp-idf/espidf_thread.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/esp-idf/espidf_thread.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/esp-idf/espidf_thread.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/esp-idf/espidf_thread.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/esp-idf/platform_internal.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/esp-idf/platform_internal.h similarity index 97% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/esp-idf/platform_internal.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/esp-idf/platform_internal.h index 7b4d35ccd75..81304ea80c6 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/esp-idf/platform_internal.h +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/esp-idf/platform_internal.h @@ -41,6 +41,8 @@ typedef pthread_cond_t korp_cond; typedef pthread_t korp_thread; typedef unsigned int korp_sem; +#define OS_THREAD_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER + #define BH_APPLET_PRESERVED_STACK_SIZE (2 * BH_KB) /* Default thread priority */ diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/esp-idf/shared_platform.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/esp-idf/shared_platform.cmake similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/esp-idf/shared_platform.cmake rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/esp-idf/shared_platform.cmake diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/linux/platform_init.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/freebsd/platform_init.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/linux/platform_init.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/freebsd/platform_init.c diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/freebsd/platform_internal.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/freebsd/platform_internal.h new file mode 100644 index 00000000000..7b4789c9922 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/freebsd/platform_internal.h @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#ifndef _PLATFORM_INTERNAL_H +#define _PLATFORM_INTERNAL_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef BH_PLATFORM_FREEBSD +#define BH_PLATFORM_FREEBSD +#endif + +#define BH_HAS_DLFCN 1 + +/* Stack size of applet threads's native part. */ +#define BH_APPLET_PRESERVED_STACK_SIZE (32 * 1024) + +/* Default thread priority */ +#define BH_THREAD_DEFAULT_PRIORITY 0 + +typedef pthread_t korp_tid; +typedef pthread_mutex_t korp_mutex; +typedef pthread_cond_t korp_cond; +typedef pthread_t korp_thread; +typedef sem_t korp_sem; + +#define OS_THREAD_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER + +#define os_thread_local_attribute __thread + +#define bh_socket_t int + +#if WASM_DISABLE_HW_BOUND_CHECK == 0 +#if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64) \ + || defined(BUILD_TARGET_AARCH64) || defined(BUILD_TARGET_RISCV64_LP64D) \ + || defined(BUILD_TARGET_RISCV64_LP64) + +#include + +#define OS_ENABLE_HW_BOUND_CHECK + +typedef jmp_buf korp_jmpbuf; + +#define os_setjmp setjmp +#define os_longjmp longjmp +#define os_alloca alloca + +#define os_getpagesize getpagesize + +typedef void (*os_signal_handler)(void *sig_addr); + +int +os_thread_signal_init(os_signal_handler handler); + +void +os_thread_signal_destroy(); + +bool +os_thread_signal_inited(); + +void +os_signal_unmask(); + +void +os_sigreturn(); +#endif /* end of BUILD_TARGET_X86_64/AMD_64/AARCH64/RISCV64 */ +#endif /* end of WASM_DISABLE_HW_BOUND_CHECK */ + +#ifdef __cplusplus +} +#endif + +#endif /* end of _PLATFORM_INTERNAL_H */ diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/freebsd/shared_platform.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/freebsd/shared_platform.cmake new file mode 100644 index 00000000000..12583fc63ad --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/freebsd/shared_platform.cmake @@ -0,0 +1,18 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +set (PLATFORM_SHARED_DIR ${CMAKE_CURRENT_LIST_DIR}) + +add_definitions(-DBH_PLATFORM_FREEBSD) + +include_directories(${PLATFORM_SHARED_DIR}) +include_directories(${PLATFORM_SHARED_DIR}/../include) + +include (${CMAKE_CURRENT_LIST_DIR}/../common/posix/platform_api_posix.cmake) + +file (GLOB_RECURSE source_all ${PLATFORM_SHARED_DIR}/*.c) + +set (PLATFORM_SHARED_SOURCE ${source_all} ${PLATFORM_COMMON_POSIX_SOURCE}) + +file (GLOB header ${PLATFORM_SHARED_DIR}/../include/*.h) +LIST (APPEND RUNTIME_LIB_HEADER_LIST ${header}) diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/include/platform_api_extension.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/include/platform_api_extension.h similarity index 92% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/include/platform_api_extension.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/include/platform_api_extension.h index c214c88faec..94fe16ea3a8 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/include/platform_api_extension.h +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/include/platform_api_extension.h @@ -92,6 +92,48 @@ int os_thread_detach(korp_tid); void os_thread_exit(void *retval); +/* Try to define os_atomic_thread_fence if it isn't defined in + platform's platform_internal.h */ +#ifndef os_atomic_thread_fence + +#if !defined(__GNUC_PREREQ) && (defined(__GNUC__) || defined(__GNUG__)) \ + && !defined(__clang__) && defined(__GNUC_MINOR__) +#define __GNUC_PREREQ(maj, min) \ + ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min)) +#endif + +/* Clang's __GNUC_PREREQ macro has a different meaning than GCC one, + so we have to handle this case specially */ +#if defined(__clang__) +/* Clang provides stdatomic.h since 3.6.0 + See https://releases.llvm.org/3.6.0/tools/clang/docs/ReleaseNotes.html */ +#if __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 6) +#define BH_HAS_STD_ATOMIC +#endif +#elif defined(__GNUC_PREREQ) +/* Even though older versions of GCC support C11, atomics were + not implemented until 4.9. See + https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58016 */ +#if __GNUC_PREREQ(4, 9) +#define BH_HAS_STD_ATOMIC +#elif __GNUC_PREREQ(4, 7) +#define os_memory_order_acquire __ATOMIC_ACQUIRE +#define os_memory_order_release __ATOMIC_RELEASE +#define os_memory_order_seq_cst __ATOMIC_SEQ_CST +#define os_atomic_thread_fence __atomic_thread_fence +#endif /* end of __GNUC_PREREQ(4, 9) */ +#endif /* end of defined(__GNUC_PREREQ) */ + +#if defined(BH_HAS_STD_ATOMIC) && !defined(__cplusplus) +#include +#define os_memory_order_acquire memory_order_acquire +#define os_memory_order_release memory_order_release +#define os_memory_order_seq_cst memory_order_seq_cst +#define os_atomic_thread_fence atomic_thread_fence +#endif + +#endif /* end of os_atomic_thread_fence */ + /** * Initialize current thread environment if current thread * is created by developer but not runtime @@ -99,19 +141,19 @@ os_thread_exit(void *retval); * @return 0 if success, -1 otherwise */ int -os_thread_env_init(); +os_thread_env_init(void); /** * Destroy current thread environment */ void -os_thread_env_destroy(); +os_thread_env_destroy(void); /** * Whether the thread environment is initialized */ bool -os_thread_env_inited(); +os_thread_env_inited(void); /** * Suspend execution of the calling thread for (at least) @@ -977,6 +1019,19 @@ os_socket_set_broadcast(bh_socket_t socket, bool is_enabled); int os_socket_get_broadcast(bh_socket_t socket, bool *is_enabled); +/** + * Dump memory information of the current process + * It may have variant implementations in different platforms + * + * @param out the output buffer. It is for sure the return content + * is a c-string which ends up with '\0' + * @param size the size of the output buffer + * + * @return 0 if success, -1 otherwise + */ +int +os_dumps_proc_mem_info(char *out, unsigned int size); + #ifdef __cplusplus } #endif diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/include/platform_api_vmcore.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/include/platform_api_vmcore.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/include/platform_api_vmcore.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/include/platform_api_vmcore.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/include/platform_common.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/include/platform_common.h similarity index 98% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/include/platform_common.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/include/platform_common.h index 9890202d19c..28001af7469 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/include/platform_common.h +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/include/platform_common.h @@ -193,6 +193,10 @@ typedef void *(*thread_start_routine_t)(void *); #define SCNxPTR __PRIPTR_PREFIX "x" #endif +#ifndef NAN +#define NAN (0.0 / 0.0) +#endif + #ifdef __cplusplus } #endif diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/linux-sgx/platform_internal.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux-sgx/platform_internal.h similarity index 82% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/linux-sgx/platform_internal.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux-sgx/platform_internal.h index 5670052cd38..d18f015ee1f 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/linux-sgx/platform_internal.h +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux-sgx/platform_internal.h @@ -52,6 +52,10 @@ typedef pthread_mutex_t korp_mutex; typedef pthread_cond_t korp_cond; typedef unsigned int korp_sem; +#ifndef SGX_DISABLE_PTHREAD +#define OS_THREAD_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER +#endif + typedef int (*os_print_function_t)(const char *message); void os_set_print_function(os_print_function_t pf); @@ -59,6 +63,11 @@ os_set_print_function(os_print_function_t pf); char * strcpy(char *dest, const char *src); +#define os_memory_order_acquire __ATOMIC_ACQUIRE +#define os_memory_order_release __ATOMIC_RELEASE +#define os_memory_order_seq_cst __ATOMIC_SEQ_CST +#define os_atomic_thread_fence __atomic_thread_fence + #ifdef __cplusplus } #endif diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/linux-sgx/sgx_file.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux-sgx/sgx_file.c similarity index 95% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/linux-sgx/sgx_file.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux-sgx/sgx_file.c index 772a8087ad3..a8ae8d2f9a4 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/linux-sgx/sgx_file.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux-sgx/sgx_file.c @@ -88,6 +88,8 @@ ocall_linkat(int *p_ret, int olddirfd, const char *oldpath, int newdirfd, int ocall_unlinkat(int *p_ret, int dirfd, const char *pathname, int flags); int +ocall_readlink(ssize_t *p_ret, const char *pathname, char *buf, size_t bufsiz); +int ocall_readlinkat(ssize_t *p_ret, int dirfd, const char *pathname, char *buf, size_t bufsiz); int @@ -190,18 +192,29 @@ openat(int dirfd, const char *pathname, int flags, ...) errno = get_errno(); #if WASM_ENABLE_SGX_IPFS != 0 - // When WAMR uses Intel SGX IPFS to enabled, it opens a second - // file descriptor to interact with the secure file. - // The first file descriptor opened earlier is used to interact - // with the metadata of the file (e.g., time, flags, etc.). - int ret; - void *file_ptr = ipfs_fopen(fd, pathname, flags); - if (file_ptr == NULL) { + struct stat sb; + int ret = fstatat(dirfd, pathname, &sb, 0); + if (ret < 0) { if (ocall_close(&ret, fd) != SGX_SUCCESS) { TRACE_OCALL_FAIL(); } return -1; } + + // Ony files are managed by SGX IPFS + if (S_ISREG(sb.st_mode)) { + // When WAMR uses Intel SGX IPFS to enabled, it opens a second + // file descriptor to interact with the secure file. + // The first file descriptor opened earlier is used to interact + // with the metadata of the file (e.g., time, flags, etc.). + void *file_ptr = ipfs_fopen(fd, flags); + if (file_ptr == NULL) { + if (ocall_close(&ret, fd) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + } + return -1; + } + } #endif return fd; @@ -699,6 +712,24 @@ unlinkat(int dirfd, const char *pathname, int flags) return ret; } +ssize_t +readlink(const char *pathname, char *buf, size_t bufsiz) +{ + ssize_t ret; + + if (buf == NULL) + return -1; + + if (ocall_readlink(&ret, pathname, buf, bufsiz) != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return -1; + } + + if (ret == -1) + errno = get_errno(); + return ret; +} + ssize_t readlinkat(int dirfd, const char *pathname, char *buf, size_t bufsiz) { diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/linux-sgx/sgx_file.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux-sgx/sgx_file.h similarity index 98% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/linux-sgx/sgx_file.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux-sgx/sgx_file.h index c35c2246996..8690e1f69c0 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/linux-sgx/sgx_file.h +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux-sgx/sgx_file.h @@ -219,6 +219,8 @@ linkat(int olddirfd, const char *oldpath, int newdirfd, const char *newpath, int unlinkat(int dirfd, const char *pathname, int flags); ssize_t +readlink(const char *pathname, char *buf, size_t bufsiz); +ssize_t readlinkat(int dirfd, const char *pathname, char *buf, size_t bufsiz); int symlinkat(const char *target, int newdirfd, const char *linkpath); diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/linux-sgx/sgx_ipfs.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux-sgx/sgx_ipfs.c similarity index 77% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/linux-sgx/sgx_ipfs.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux-sgx/sgx_ipfs.c index 76750946c11..32268898077 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/linux-sgx/sgx_ipfs.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux-sgx/sgx_ipfs.c @@ -16,6 +16,11 @@ #define SGX_ERROR_FILE_LOWEST_ERROR_ID SGX_ERROR_FILE_BAD_STATUS #define SGX_ERROR_FILE_HIGHEST_ERROR_ID SGX_ERROR_FILE_CLOSE_FAILED +// Internal buffer filled with zeroes and used when extending the size of +// protected files. +#define ZEROES_PADDING_LENGTH 32 * 1024 +char zeroes_padding[ZEROES_PADDING_LENGTH] = { 0 }; + // The mapping between file descriptors and IPFS file pointers. static HashMap *ipfs_file_list; @@ -78,6 +83,27 @@ ipfs_file_destroy(void *sgx_file) sgx_fclose(sgx_file); } +// Writes a given number of zeroes in file at the current offset. +// The return value is zero if successful; otherwise non-zero. +static int +ipfs_write_zeroes(void *sgx_file, size_t len) +{ + int min_count; + + while (len > 0) { + min_count = len < ZEROES_PADDING_LENGTH ? len : ZEROES_PADDING_LENGTH; + + if (sgx_fwrite(zeroes_padding, 1, min_count, sgx_file) == 0) { + errno = convert_sgx_errno(sgx_ferror(sgx_file)); + return -1; + } + + len -= min_count; + } + + return 0; +} + int ipfs_init() { @@ -104,7 +130,7 @@ ipfs_posix_fallocate(int fd, off_t offset, size_t len) // The wrapper for fseek takes care of extending the file if sought beyond // the end - if (ipfs_lseek(fd, offset + len, SEEK_CUR) == -1) { + if (ipfs_lseek(fd, offset + len, SEEK_SET) == -1) { return errno; } @@ -248,7 +274,7 @@ ipfs_close(int fd) } void * -ipfs_fopen(int fd, const char *filename, int flags) +ipfs_fopen(int fd, int flags) { // Mapping back the mode const char *mode; @@ -260,22 +286,27 @@ ipfs_fopen(int fd, const char *filename, int flags) bool write_only = (flags & O_ACCMODE) == O_WRONLY; bool read_write = (flags & O_ACCMODE) == O_RDWR; - // The mapping of the mode are described in the table in the official + // The mapping of the mode is similar to the table in the official // specifications: // https://pubs.opengroup.org/onlinepubs/9699919799/functions/fopen.html + // Note that POSIX has obtained a file descriptor beforehand. + // If opened with a destructive mode ("w" or "w+"), the truncate operation + // already occurred and must not be repeated because this will invalidate + // the file descriptor obtained by POSIX. Therefore, we do NOT map to the + // modes that truncate the file ("w" and "w+"). Instead, we map to a + // non-destructive mode ("r+"). + if (read_only) mode = "r"; else if (write_only && must_create && must_truncate) - mode = "w"; + // Rather than "w", we map to a non-destructive mode + mode = "r+"; else if (write_only && must_create && must_append) mode = "a"; - else if (read_write && must_create && must_truncate) - mode = "w+"; else if (read_write && must_create && must_append) mode = "a+"; - else if (read_write && must_create) - mode = "w+"; else if (read_write) + // Rather than "w+", we map to a non-destructive mode mode = "r+"; else mode = NULL; @@ -286,8 +317,29 @@ ipfs_fopen(int fd, const char *filename, int flags) return NULL; } - // Opening the file - void *sgx_file = sgx_fopen_auto_key(filename, mode); + // Determine the symbolic link of the file descriptor, because IPFS does not + // support opening a relative path to a file descriptor (i.e., openat). + // Using the symbolic link in /proc/self allows to retrieve the same path as + // opened by the initial openat and respects the chroot of WAMR. + size_t ret; + char symbolic_path[32]; + ret = + snprintf(symbolic_path, sizeof(symbolic_path), "/proc/self/fd/%d", fd); + if (ret >= sizeof(symbolic_path)) { + errno = ENAMETOOLONG; + return NULL; + } + + // Resolve the symbolic link to real absolute path, because IPFS can only + // open a file with a same file name it was initially created. Otherwise, + // IPFS throws SGX_ERROR_FILE_NAME_MISMATCH. + char real_path[PATH_MAX] = { 0 }; + ret = readlink(symbolic_path, real_path, PATH_MAX - 1); + if (ret == -1) + return NULL; + + // Opening the file using the real path + void *sgx_file = sgx_fopen_auto_key(real_path, mode); if (sgx_file == NULL) { errno = convert_sgx_errno(sgx_ferror(sgx_file)); @@ -328,7 +380,7 @@ ipfs_fflush(int fd) off_t ipfs_lseek(int fd, off_t offset, int nwhence) { - off_t new_offset; + off_t cursor_current_location; void *sgx_file = fd2file(fd); if (!sgx_file) { errno = EBADF; @@ -338,20 +390,20 @@ ipfs_lseek(int fd, off_t offset, int nwhence) // Optimization: if the offset is 0 and the whence is SEEK_CUR, // this is equivalent of a call to ftell. if (offset == 0 && nwhence == SEEK_CUR) { - int64_t ftell_result = (off_t)sgx_ftell(sgx_file); + cursor_current_location = (off_t)sgx_ftell(sgx_file); - if (ftell_result == -1) { + if (cursor_current_location == -1) { errno = convert_sgx_errno(sgx_ferror(sgx_file)); return -1; } - return ftell_result; + return cursor_current_location; } int fseek_result = sgx_fseek(sgx_file, offset, nwhence); if (fseek_result == 0) { - new_offset = (__wasi_filesize_t)sgx_ftell(sgx_file); + off_t new_offset = (off_t)sgx_ftell(sgx_file); if (new_offset == -1) { errno = convert_sgx_errno(sgx_ferror(sgx_file)); @@ -379,17 +431,39 @@ ipfs_lseek(int fd, off_t offset, int nwhence) // manually. // Assume the error is raised because the cursor is moved beyond the end - // of the file. Try to move the cursor at the end of the file. + // of the file. + + // If the whence is the current cursor location, retrieve it + if (nwhence == SEEK_CUR) { + cursor_current_location = (off_t)sgx_ftell(sgx_file); + } + + // Move the cursor at the end of the file if (sgx_fseek(sgx_file, 0, SEEK_END) == -1) { errno = convert_sgx_errno(sgx_ferror(sgx_file)); return -1; } + // Compute the number of zeroes to append. + int64_t number_of_zeroes; + switch (nwhence) { + case SEEK_SET: + number_of_zeroes = offset - sgx_ftell(sgx_file); + break; + case SEEK_END: + number_of_zeroes = offset; + break; + case SEEK_CUR: + number_of_zeroes = + cursor_current_location + offset - sgx_ftell(sgx_file); + break; + default: + errno = EINVAL; + return -1; + } + // Write the missing zeroes - char zero = 0; - int64_t number_of_zeroes = offset - sgx_ftell(sgx_file); - if (sgx_fwrite(&zero, 1, number_of_zeroes, sgx_file) == 0) { - errno = convert_sgx_errno(sgx_ferror(sgx_file)); + if (ipfs_write_zeroes(sgx_file, number_of_zeroes) != 0) { return -1; } @@ -442,9 +516,7 @@ ipfs_ftruncate(int fd, off_t len) // Increasing the size is equal to writing from the end of the file // with null bytes. - char null_byte = 0; - if (sgx_fwrite(&null_byte, 1, len - file_size, sgx_file) == 0) { - errno = convert_sgx_errno(sgx_ferror(sgx_file)); + if (ipfs_write_zeroes(sgx_file, len - file_size) != 0) { return -1; } diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/linux-sgx/sgx_ipfs.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux-sgx/sgx_ipfs.h similarity index 95% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/linux-sgx/sgx_ipfs.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux-sgx/sgx_ipfs.h index ade40bd5664..e4de90274f4 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/linux-sgx/sgx_ipfs.h +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux-sgx/sgx_ipfs.h @@ -28,7 +28,7 @@ ipfs_write(int fd, const struct iovec *iov, int iovcnt, bool has_offset, int ipfs_close(int fd); void * -ipfs_fopen(int fd, const char *filename, int flags); +ipfs_fopen(int fd, int flags); int ipfs_fflush(int fd); off_t diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/linux-sgx/sgx_platform.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux-sgx/sgx_platform.c similarity index 97% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/linux-sgx/sgx_platform.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux-sgx/sgx_platform.c index c0b423d522e..b40eaf79c43 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/linux-sgx/sgx_platform.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux-sgx/sgx_platform.c @@ -51,6 +51,12 @@ os_free(void *ptr) free(ptr); } +int +os_dumps_proc_mem_info(char *out, unsigned int size) +{ + return -1; +} + int putchar(int c) { diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/linux-sgx/sgx_pthread.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux-sgx/sgx_pthread.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/linux-sgx/sgx_pthread.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux-sgx/sgx_pthread.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/linux-sgx/sgx_pthread.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux-sgx/sgx_pthread.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/linux-sgx/sgx_pthread.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux-sgx/sgx_pthread.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/linux-sgx/sgx_rsrv_mem_mngr.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux-sgx/sgx_rsrv_mem_mngr.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/linux-sgx/sgx_rsrv_mem_mngr.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux-sgx/sgx_rsrv_mem_mngr.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/linux-sgx/sgx_signal.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux-sgx/sgx_signal.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/linux-sgx/sgx_signal.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux-sgx/sgx_signal.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/linux-sgx/sgx_signal.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux-sgx/sgx_signal.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/linux-sgx/sgx_signal.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux-sgx/sgx_signal.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/linux-sgx/sgx_socket.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux-sgx/sgx_socket.c similarity index 98% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/linux-sgx/sgx_socket.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux-sgx/sgx_socket.c index cfaaaf1bcd4..afb6d6014bf 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/linux-sgx/sgx_socket.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux-sgx/sgx_socket.c @@ -370,6 +370,24 @@ getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen) return ret; } +int +setsockopt(int sockfd, int level, int optname, const void *optval, + socklen_t optlen) +{ + int ret; + + if (ocall_setsockopt(&ret, sockfd, level, optname, (void *)optval, optlen) + != SGX_SUCCESS) { + TRACE_OCALL_FAIL(); + return -1; + } + + if (ret == -1) + errno = get_errno(); + + return ret; +} + ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags) { diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/linux-sgx/sgx_socket.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux-sgx/sgx_socket.h similarity index 99% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/linux-sgx/sgx_socket.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux-sgx/sgx_socket.h index b7a58ba0773..edf977dd6fa 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/linux-sgx/sgx_socket.h +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux-sgx/sgx_socket.h @@ -312,6 +312,10 @@ socket(int domain, int type, int protocol); int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen); +int +setsockopt(int sockfd, int level, int optname, const void *optval, + socklen_t optlen); + ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags); diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/linux-sgx/sgx_thread.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux-sgx/sgx_thread.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/linux-sgx/sgx_thread.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux-sgx/sgx_thread.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/linux-sgx/sgx_time.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux-sgx/sgx_time.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/linux-sgx/sgx_time.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux-sgx/sgx_time.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/linux-sgx/sgx_time.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux-sgx/sgx_time.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/linux-sgx/sgx_time.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux-sgx/sgx_time.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/linux-sgx/sgx_wamr.edl b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux-sgx/sgx_wamr.edl similarity index 97% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/linux-sgx/sgx_wamr.edl rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux-sgx/sgx_wamr.edl index d8b6030d778..7cb4817fda1 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/linux-sgx/sgx_wamr.edl +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux-sgx/sgx_wamr.edl @@ -48,6 +48,9 @@ enclave { int flags); int ocall_unlinkat(int dirfd, [in, string]const char *pathname, int flags); + ssize_t ocall_readlink([in, string]const char *pathname, + [out, size=bufsiz]char *buf, + size_t bufsiz); ssize_t ocall_readlinkat(int dirfd, [in, string]const char *pathname, [out, size=bufsiz]char *buf, diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/linux-sgx/shared_platform.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux-sgx/shared_platform.cmake similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/linux-sgx/shared_platform.cmake rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux-sgx/shared_platform.cmake diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/linux-sgx/untrusted/file.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux-sgx/untrusted/file.c similarity index 97% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/linux-sgx/untrusted/file.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux-sgx/untrusted/file.c index 22abe7d88d2..cb9bf6a210b 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/linux-sgx/untrusted/file.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux-sgx/untrusted/file.c @@ -186,6 +186,12 @@ ocall_unlinkat(int dirfd, const char *pathname, int flags) return unlinkat(dirfd, pathname, flags); } +ssize_t +ocall_readlink(const char *pathname, char *buf, size_t bufsiz) +{ + return readlink(pathname, buf, bufsiz); +} + ssize_t ocall_readlinkat(int dirfd, const char *pathname, char *buf, size_t bufsiz) { diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/linux-sgx/untrusted/pthread.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux-sgx/untrusted/pthread.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/linux-sgx/untrusted/pthread.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux-sgx/untrusted/pthread.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/linux-sgx/untrusted/signal.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux-sgx/untrusted/signal.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/linux-sgx/untrusted/signal.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux-sgx/untrusted/signal.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/linux-sgx/untrusted/socket.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux-sgx/untrusted/socket.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/linux-sgx/untrusted/socket.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux-sgx/untrusted/socket.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/linux-sgx/untrusted/time.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux-sgx/untrusted/time.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/linux-sgx/untrusted/time.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux-sgx/untrusted/time.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/vxworks/platform_init.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux/platform_init.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/vxworks/platform_init.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux/platform_init.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/linux/platform_internal.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux/platform_internal.h similarity index 97% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/linux/platform_internal.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux/platform_internal.h index 112691425a1..0ac63cf5e75 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/linux/platform_internal.h +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux/platform_internal.h @@ -57,6 +57,8 @@ typedef pthread_cond_t korp_cond; typedef pthread_t korp_thread; typedef sem_t korp_sem; +#define OS_THREAD_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER + #define os_thread_local_attribute __thread #define bh_socket_t int diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/linux/shared_platform.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux/shared_platform.cmake similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/linux/shared_platform.cmake rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/linux/shared_platform.cmake diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/nuttx/nuttx_platform.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/nuttx/nuttx_platform.c similarity index 53% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/nuttx/nuttx_platform.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/nuttx/nuttx_platform.c index 8b8d6d85ae4..9cb123e0172 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/nuttx/nuttx_platform.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/nuttx/nuttx_platform.c @@ -38,6 +38,12 @@ os_free(void *ptr) free(ptr); } +int +os_dumps_proc_mem_info(char *out, unsigned int size) +{ + return -1; +} + void * os_mmap(void *hint, size_t size, int prot, int flags) { @@ -139,9 +145,115 @@ utimensat(int fd, const char *path, const struct timespec ts[2], int flag) #endif /* !defined(AT_FDCWD) */ -DIR * -fdopendir(int fd) +#ifndef CONFIG_NET + +#include + +int +accept(int sockfd, FAR struct sockaddr *addr, FAR socklen_t *addrlen) { - errno = ENOSYS; - return NULL; + errno = ENOTSUP; + return -1; +} + +int +bind(int sockfd, FAR const struct sockaddr *addr, socklen_t addrlen) +{ + errno = ENOTSUP; + return -1; +} + +int +listen(int sockfd, int backlog) +{ + errno = ENOTSUP; + return -1; +} + +int +connect(int sockfd, FAR const struct sockaddr *addr, socklen_t addrlen) +{ + errno = ENOTSUP; + return -1; +} + +ssize_t +recvfrom(int sockfd, FAR void *buf, size_t len, int flags, + FAR struct sockaddr *from, FAR socklen_t *fromlen) +{ + errno = ENOTSUP; + return -1; +} + +ssize_t +send(int sockfd, FAR const void *buf, size_t len, int flags) +{ + errno = ENOTSUP; + return -1; +} + +ssize_t +sendto(int sockfd, FAR const void *buf, size_t len, int flags, + FAR const struct sockaddr *to, socklen_t tolen) +{ + errno = ENOTSUP; + return -1; } + +int +socket(int domain, int type, int protocol) +{ + errno = ENOTSUP; + return -1; +} + +int +shutdown(int sockfd, int how) +{ + errno = ENOTSUP; + return -1; +} + +int +getaddrinfo(FAR const char *nodename, FAR const char *servname, + FAR const struct addrinfo *hints, FAR struct addrinfo **res) +{ + errno = ENOTSUP; + return -1; +} + +void +freeaddrinfo(FAR struct addrinfo *ai) +{} + +int +setsockopt(int sockfd, int level, int option, FAR const void *value, + socklen_t value_len) +{ + errno = ENOTSUP; + return -1; +} + +int +getsockopt(int sockfd, int level, int option, FAR void *value, + FAR socklen_t *value_len) +{ + errno = ENOTSUP; + return -1; +} + +int +getpeername(int sockfd, FAR struct sockaddr *addr, FAR socklen_t *addrlen) +{ + errno = ENOTSUP; + return -1; +} + +int +getsockname(int sockfd, FAR struct sockaddr *addr, FAR socklen_t *addrlen) +{ + errno = ENOTSUP; + return -1; +} + +#endif diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/nuttx/platform_internal.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/nuttx/platform_internal.h similarity index 96% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/nuttx/platform_internal.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/nuttx/platform_internal.h index 41e20858448..b5bbdacd04c 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/nuttx/platform_internal.h +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/nuttx/platform_internal.h @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -42,6 +43,8 @@ typedef pthread_cond_t korp_cond; typedef pthread_t korp_thread; typedef sem_t korp_sem; +#define OS_THREAD_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER + #define BH_APPLET_PRESERVED_STACK_SIZE (2 * BH_KB) /* Default thread priority */ diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/nuttx/shared_platform.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/nuttx/shared_platform.cmake similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/nuttx/shared_platform.cmake rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/nuttx/shared_platform.cmake diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/riot/platform_internal.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/riot/platform_internal.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/riot/platform_internal.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/riot/platform_internal.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/riot/riot_platform.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/riot/riot_platform.c similarity index 93% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/riot/riot_platform.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/riot/riot_platform.c index 82a84639576..a0c38e8c94c 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/riot/riot_platform.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/riot/riot_platform.c @@ -43,6 +43,12 @@ os_free(void *ptr) free(ptr); } +int +os_dumps_proc_mem_info(char *out, unsigned int size) +{ + return -1; +} + void * os_mmap(void *hint, size_t size, int prot, int flags) { diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/riot/riot_thread.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/riot/riot_thread.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/riot/riot_thread.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/riot/riot_thread.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/riot/riot_time.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/riot/riot_time.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/riot/riot_time.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/riot/riot_time.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/riot/shared_platform.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/riot/shared_platform.cmake similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/riot/shared_platform.cmake rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/riot/shared_platform.cmake diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/rt-thread/SConscript b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/rt-thread/SConscript similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/rt-thread/SConscript rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/rt-thread/SConscript diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/rt-thread/platform_internal.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/rt-thread/platform_internal.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/rt-thread/platform_internal.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/rt-thread/platform_internal.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/rt-thread/rtt_platform.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/rt-thread/rtt_platform.c similarity index 97% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/rt-thread/rtt_platform.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/rt-thread/rtt_platform.c index 13eb4398634..4685e1ea318 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/rt-thread/rtt_platform.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/rt-thread/rtt_platform.c @@ -88,6 +88,12 @@ os_free(void *ptr) } } +int +os_dumps_proc_mem_info(char *out, unsigned int size) +{ + return -1; +} + static char wamr_vprint_buf[RT_CONSOLEBUF_SIZE * 2]; int diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/rt-thread/shared_platform.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/rt-thread/shared_platform.cmake similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/rt-thread/shared_platform.cmake rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/rt-thread/shared_platform.cmake diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/vxworks/platform_init.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/vxworks/platform_init.c new file mode 100644 index 00000000000..2aae13fa14e --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/vxworks/platform_init.c @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "platform_api_vmcore.h" + +int +bh_platform_init() +{ + return 0; +} + +void +bh_platform_destroy() +{} + +int +os_printf(const char *format, ...) +{ + int ret = 0; + va_list ap; + + va_start(ap, format); +#ifndef BH_VPRINTF + ret += vprintf(format, ap); +#else + ret += BH_VPRINTF(format, ap); +#endif + va_end(ap); + + return ret; +} + +int +os_vprintf(const char *format, va_list ap) +{ +#ifndef BH_VPRINTF + return vprintf(format, ap); +#else + return BH_VPRINTF(format, ap); +#endif +} diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/vxworks/platform_internal.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/vxworks/platform_internal.h similarity index 96% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/vxworks/platform_internal.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/vxworks/platform_internal.h index 25ea8b4adc6..f72f6032253 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/vxworks/platform_internal.h +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/vxworks/platform_internal.h @@ -56,6 +56,8 @@ typedef pthread_cond_t korp_cond; typedef pthread_t korp_thread; typedef sem_t korp_sem; +#define OS_THREAD_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER + #define os_thread_local_attribute __thread #if WASM_DISABLE_HW_BOUND_CHECK == 0 diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/vxworks/shared_platform.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/vxworks/shared_platform.cmake similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/vxworks/shared_platform.cmake rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/vxworks/shared_platform.cmake diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/windows/platform_init.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/windows/platform_init.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/windows/platform_init.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/windows/platform_init.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/windows/platform_internal.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/windows/platform_internal.h similarity index 72% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/windows/platform_internal.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/windows/platform_internal.h index 03f75ace76e..500ab200c7f 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/windows/platform_internal.h +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/windows/platform_internal.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -56,11 +57,23 @@ typedef void *korp_tid; typedef void *korp_mutex; typedef void *korp_sem; +/** + * Create the mutex when os_mutex_lock is called, and no need to + * CloseHandle() for the static lock's lifetime, since + * "The system closes the handle automatically when the process + * terminates. The mutex object is destroyed when its last + * handle has been closed." + * Refer to: + * https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-createmutexa + */ +#define OS_THREAD_MUTEX_INITIALIZER NULL + struct os_thread_wait_node; typedef struct os_thread_wait_node *os_thread_wait_list; typedef struct korp_cond { korp_mutex wait_list_lock; os_thread_wait_list thread_wait_list; + struct os_thread_wait_node *thread_wait_list_end; } korp_cond; #define bh_socket_t SOCKET @@ -104,6 +117,20 @@ os_thread_signal_inited(); #endif /* end of BUILD_TARGET_X86_64/AMD_64 */ #endif /* end of WASM_DISABLE_HW_BOUND_CHECK */ +typedef enum os_memory_order { + os_memory_order_relaxed, + os_memory_order_consume, + os_memory_order_acquire, + os_memory_order_release, + os_memory_order_acq_rel, + os_memory_order_seq_cst, +} os_memory_order; + +void +bh_atomic_thread_fence(int mem_order); + +#define os_atomic_thread_fence bh_atomic_thread_fence + #ifdef __cplusplus } #endif diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/windows/shared_platform.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/windows/shared_platform.cmake similarity index 77% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/windows/shared_platform.cmake rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/windows/shared_platform.cmake index 6ab29c89056..a68d6317767 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/windows/shared_platform.cmake +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/windows/shared_platform.cmake @@ -5,12 +5,13 @@ set (PLATFORM_SHARED_DIR ${CMAKE_CURRENT_LIST_DIR}) add_definitions(-DBH_PLATFORM_WINDOWS) add_definitions(-DHAVE_STRUCT_TIMESPEC) - +add_definitions(-D_WINSOCK_DEPRECATED_NO_WARNINGS) include_directories(${PLATFORM_SHARED_DIR}) include_directories(${PLATFORM_SHARED_DIR}/../include) -file (GLOB_RECURSE source_all ${PLATFORM_SHARED_DIR}/*.c) +file (GLOB_RECURSE source_all ${PLATFORM_SHARED_DIR}/*.c + ${PLATFORM_SHARED_DIR}/*.cpp) set (PLATFORM_SHARED_SOURCE ${source_all}) diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/windows/win_atomic.cpp b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/windows/win_atomic.cpp new file mode 100644 index 00000000000..80e8ef51841 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/windows/win_atomic.cpp @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2023 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "platform_api_vmcore.h" +#include "platform_api_extension.h" + +#if WASM_ENABLE_SHARED_MEMORY != 0 + +#include + +void +bh_atomic_thread_fence(int mem_order) +{ + std::memory_order order = + (std::memory_order)(std::memory_order::memory_order_relaxed + mem_order + - os_memory_order_relaxed); + std::atomic_thread_fence(order); +} + +#endif diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/windows/win_malloc.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/windows/win_malloc.c similarity index 82% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/windows/win_malloc.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/windows/win_malloc.c index 660d1baae6c..56aaf9c7b3c 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/windows/win_malloc.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/windows/win_malloc.c @@ -22,3 +22,9 @@ os_free(void *ptr) { free(ptr); } + +int +os_dumps_proc_mem_info(char *out, unsigned int size) +{ + return -1; +} \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/windows/win_memmap.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/windows/win_memmap.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/windows/win_memmap.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/windows/win_memmap.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/windows/win_socket.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/windows/win_socket.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/windows/win_socket.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/windows/win_socket.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/windows/win_thread.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/windows/win_thread.c similarity index 90% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/windows/win_thread.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/windows/win_thread.c index 59df9cd1542..09cf0c63f79 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/windows/win_thread.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/windows/win_thread.c @@ -37,6 +37,8 @@ typedef struct os_thread_data { korp_mutex wait_lock; /* Waiting list of other threads who are joining this thread */ os_thread_wait_list thread_wait_list; + /* End node of the waiting list */ + os_thread_wait_node *thread_wait_list_end; /* Whether the thread has exited */ bool thread_exited; /* Thread return value */ @@ -174,7 +176,8 @@ os_thread_cleanup(void *retval) os_sem_signal(&head->sem); head = next; } - thread_data->thread_wait_list = NULL; + thread_data->thread_wait_list = thread_data->thread_wait_list_end = + NULL; } /* Set thread status and thread return value */ thread_data->thread_exited = true; @@ -313,14 +316,14 @@ os_thread_join(korp_tid thread, void **p_retval) } /* Thread is running */ - if (!thread_data->thread_wait_list) - thread_data->thread_wait_list = &curr_thread_data->wait_node; - else { + if (!thread_data->thread_wait_list) { /* Waiting list is empty */ + thread_data->thread_wait_list = thread_data->thread_wait_list_end = + &curr_thread_data->wait_node; + } + else { /* Waiting list isn't empty */ /* Add to end of waiting list */ - os_thread_wait_node *p = thread_data->thread_wait_list; - while (p->next) - p = p->next; - p->next = &curr_thread_data->wait_node; + thread_data->thread_wait_list_end->next = &curr_thread_data->wait_node; + thread_data->thread_wait_list_end = &curr_thread_data->wait_node; } os_mutex_unlock(&thread_data->wait_lock); @@ -512,6 +515,21 @@ os_mutex_lock(korp_mutex *mutex) int ret; assert(mutex); + + if (*mutex == NULL) { /* static initializer? */ + HANDLE p = CreateMutex(NULL, FALSE, NULL); + + if (!p) { + return BHT_ERROR; + } + + if (InterlockedCompareExchangePointer((PVOID *)mutex, (PVOID)p, NULL) + != NULL) { + /* lock has been created by other threads */ + CloseHandle(p); + } + } + ret = WaitForSingleObject(*mutex, INFINITE); return ret != WAIT_FAILED ? BHT_OK : BHT_ERROR; } @@ -530,7 +548,7 @@ os_cond_init(korp_cond *cond) if (os_mutex_init(&cond->wait_list_lock) != BHT_OK) return BHT_ERROR; - cond->thread_wait_list = NULL; + cond->thread_wait_list = cond->thread_wait_list_end = NULL; return BHT_OK; } @@ -553,14 +571,13 @@ os_cond_wait_internal(korp_cond *cond, korp_mutex *mutex, bool timed, bh_assert(cond); bh_assert(mutex); os_mutex_lock(&cond->wait_list_lock); - if (!cond->thread_wait_list) - cond->thread_wait_list = node; - else { + if (!cond->thread_wait_list) { /* Waiting list is empty */ + cond->thread_wait_list = cond->thread_wait_list_end = node; + } + else { /* Waiting list isn't empty */ /* Add to end of wait list */ - os_thread_wait_node *p = cond->thread_wait_list; - while (p->next) - p = p->next; - p->next = node; + cond->thread_wait_list_end->next = node; + cond->thread_wait_list_end = node; } os_mutex_unlock(&cond->wait_list_lock); @@ -575,14 +592,24 @@ os_cond_wait_internal(korp_cond *cond, korp_mutex *mutex, bool timed, /* Remove wait node from wait list */ os_mutex_lock(&cond->wait_list_lock); - if (cond->thread_wait_list == node) + if (cond->thread_wait_list == node) { cond->thread_wait_list = node->next; + + if (cond->thread_wait_list_end == node) { + bh_assert(node->next == NULL); + cond->thread_wait_list_end = NULL; + } + } else { /* Remove from the wait list */ os_thread_wait_node *p = cond->thread_wait_list; while (p->next != node) p = p->next; p->next = node->next; + + if (cond->thread_wait_list_end == node) { + cond->thread_wait_list_end = p; + } } os_mutex_unlock(&cond->wait_list_lock); @@ -691,13 +718,19 @@ static os_thread_local_attribute bool thread_signal_inited = false; int os_thread_signal_init() { +#if WASM_DISABLE_STACK_HW_BOUND_CHECK == 0 ULONG StackSizeInBytes = 16 * 1024; +#endif bool ret; if (thread_signal_inited) return 0; +#if WASM_DISABLE_STACK_HW_BOUND_CHECK == 0 ret = SetThreadStackGuarantee(&StackSizeInBytes); +#else + ret = true; +#endif if (ret) thread_signal_inited = true; return ret ? 0 : -1; diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/windows/win_time.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/windows/win_time.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/windows/win_time.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/windows/win_time.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/zephyr/platform_internal.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/zephyr/platform_internal.h similarity index 80% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/zephyr/platform_internal.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/zephyr/platform_internal.h index f4683d93e31..d2a94e4ad5f 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/zephyr/platform_internal.h +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/zephyr/platform_internal.h @@ -7,14 +7,21 @@ #define _PLATFORM_INTERNAL_H #include +#include + +#if KERNEL_VERSION_NUMBER < 0x030200 /* version 3.2.0 */ #include #include -#include #if KERNEL_VERSION_NUMBER >= 0x020200 /* version 2.2.0 */ #include #else #include #endif +#else /* else of KERNEL_VERSION_NUMBER < 0x030200 */ +#include +#include +#endif /* end of KERNEL_VERSION_NUMBER < 0x030200 */ + #include #include #include @@ -24,9 +31,12 @@ #include #include #include + #ifndef CONFIG_NET_BUF_USER_DATA_SIZE #define CONFIG_NET_BUF_USER_DATA_SIZE 0 #endif + +#if KERNEL_VERSION_NUMBER < 0x030200 /* version 3.2.0 */ #include #include #include @@ -36,6 +46,17 @@ #ifdef CONFIG_ARM_MPU #include #endif +#else /* else of KERNEL_VERSION_NUMBER < 0x030200 */ +#include +#include +#include +#include +#include + +#ifdef CONFIG_ARM_MPU +#include +#endif +#endif /* end of KERNEL_VERSION_NUMBER < 0x030200 */ #ifndef BH_PLATFORM_ZEPHYR #define BH_PLATFORM_ZEPHYR @@ -96,6 +117,11 @@ double strtod(const char *nptr, char **endptr); float strtof(const char *nptr, char **endptr); /* clang-format on */ +#if KERNEL_VERSION_NUMBER >= 0x030100 /* version 3.1.0 */ +#define BH_HAS_SQRT +#define BH_HAS_SQRTF +#endif + /** * @brief Allocate executable memroy * diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/zephyr/shared_platform.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/zephyr/shared_platform.cmake similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/zephyr/shared_platform.cmake rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/zephyr/shared_platform.cmake diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/zephyr/zephyr_platform.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/zephyr/zephyr_platform.c similarity index 98% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/zephyr/zephyr_platform.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/zephyr/zephyr_platform.c index 55ad84f4209..b4f2e5ec740 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/zephyr/zephyr_platform.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/zephyr/zephyr_platform.c @@ -85,6 +85,12 @@ void os_free(void *ptr) {} +int +os_dumps_proc_mem_info(char *out, unsigned int size) +{ + return -1; +} + #if 0 struct out_context { int count; diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/zephyr/zephyr_thread.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/zephyr/zephyr_thread.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/zephyr/zephyr_thread.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/zephyr/zephyr_thread.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/zephyr/zephyr_time.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/zephyr/zephyr_time.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/platform/zephyr/zephyr_time.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/platform/zephyr/zephyr_time.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/utils/SConscript b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/utils/SConscript similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/utils/SConscript rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/utils/SConscript diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/utils/bh_assert.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/utils/bh_assert.c similarity index 87% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/utils/bh_assert.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/utils/bh_assert.c index f341df4df51..246c55d1b33 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/utils/bh_assert.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/utils/bh_assert.c @@ -6,7 +6,7 @@ #include "bh_assert.h" void -bh_assert_internal(int v, const char *file_name, int line_number, +bh_assert_internal(int64 v, const char *file_name, int line_number, const char *expr_string) { if (v) diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/utils/bh_assert.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/utils/bh_assert.h similarity index 85% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/utils/bh_assert.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/utils/bh_assert.h index 06f7f3b6cbc..b7c995af880 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/utils/bh_assert.h +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/utils/bh_assert.h @@ -14,10 +14,10 @@ extern "C" { #if BH_DEBUG != 0 void -bh_assert_internal(int v, const char *file_name, int line_number, +bh_assert_internal(int64 v, const char *file_name, int line_number, const char *expr_string); #define bh_assert(expr) \ - bh_assert_internal((int)(uintptr_t)(expr), __FILE__, __LINE__, #expr) + bh_assert_internal((int64)(uintptr_t)(expr), __FILE__, __LINE__, #expr) #else #define bh_assert(expr) (void)0 #endif /* end of BH_DEBUG */ diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/utils/bh_common.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/utils/bh_common.c similarity index 53% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/utils/bh_common.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/utils/bh_common.c index e4b2eb15c78..aeeab26bd88 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/utils/bh_common.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/utils/bh_common.c @@ -5,6 +5,73 @@ #include "bh_common.h" +static char * +align_ptr(char *src, unsigned int b) +{ + uintptr_t v = (uintptr_t)src; + uintptr_t m = b - 1; + return (char *)((v + m) & ~m); +} + +/* +Memory copy, with word alignment +*/ +int +b_memcpy_wa(void *s1, unsigned int s1max, const void *s2, unsigned int n) +{ + char *dest = (char *)s1; + char *src = (char *)s2; + + char *pa = align_ptr(src, 4); + char *pb = align_ptr((src + n), 4); + + unsigned int buff; + const char *p_byte_read; + + unsigned int *p; + char *ps; + + if (pa > src) { + pa -= 4; + } + + for (p = (unsigned int *)pa; p < (unsigned int *)pb; p++) { + buff = *(p); + p_byte_read = ((char *)&buff); + + /* read leading word */ + if ((char *)p <= src) { + for (ps = src; ps < ((char *)p + 4); ps++) { + if (ps >= src + n) { + break; + } + p_byte_read = ((char *)&buff) + (ps - (char *)p); + *dest++ = *p_byte_read; + } + } + /* read trailing word */ + else if ((char *)p >= pb - 4) { + for (ps = (char *)p; ps < src + n; ps++) { + *dest++ = *p_byte_read++; + } + } + /* read meaning word(s) */ + else { + if ((char *)p + 4 >= src + n) { + for (ps = (char *)p; ps < src + n; ps++) { + *dest++ = *p_byte_read++; + } + } + else { + *(unsigned int *)dest = buff; + dest += 4; + } + } + } + + return 0; +} + int b_memcpy_s(void *s1, unsigned int s1max, const void *s2, unsigned int n) { diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/utils/bh_common.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/utils/bh_common.h similarity index 81% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/utils/bh_common.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/utils/bh_common.h index eaeec510822..edb962eb1c7 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/utils/bh_common.h +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/utils/bh_common.h @@ -19,6 +19,13 @@ extern "C" { bh_assert(_ret == 0); \ } while (0) +#define bh_memcpy_wa(dest, dlen, src, slen) \ + do { \ + int _ret = slen == 0 ? 0 : b_memcpy_wa(dest, dlen, src, slen); \ + (void)_ret; \ + bh_assert(_ret == 0); \ + } while (0) + #define bh_memmove_s(dest, dlen, src, slen) \ do { \ int _ret = slen == 0 ? 0 : b_memmove_s(dest, dlen, src, slen); \ @@ -43,6 +50,8 @@ extern "C" { int b_memcpy_s(void *s1, unsigned int s1max, const void *s2, unsigned int n); int +b_memcpy_wa(void *s1, unsigned int s1max, const void *s2, unsigned int n); +int b_memmove_s(void *s1, unsigned int s1max, const void *s2, unsigned int n); int b_strcat_s(char *s1, unsigned int s1max, const char *s2); diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/utils/bh_hashmap.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/utils/bh_hashmap.c similarity index 99% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/utils/bh_hashmap.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/utils/bh_hashmap.c index 70119c7709d..3502239ad87 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/utils/bh_hashmap.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/utils/bh_hashmap.c @@ -33,6 +33,9 @@ bh_hash_map_create(uint32 size, bool use_lock, HashFunc hash_func, HashMap *map; uint64 total_size; + if (size < HASH_MAP_MIN_SIZE) + size = HASH_MAP_MIN_SIZE; + if (size > HASH_MAP_MAX_SIZE) { LOG_ERROR("HashMap create failed: size is too large.\n"); return NULL; diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/utils/bh_hashmap.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/utils/bh_hashmap.h similarity index 97% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/utils/bh_hashmap.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/utils/bh_hashmap.h index 018f05131cf..38aa2c66862 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/utils/bh_hashmap.h +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/utils/bh_hashmap.h @@ -12,6 +12,9 @@ extern "C" { #endif +/* Minimum initial size of hash map */ +#define HASH_MAP_MIN_SIZE 4 + /* Maximum initial size of hash map */ #define HASH_MAP_MAX_SIZE 65536 @@ -141,7 +144,7 @@ bh_hash_map_get_struct_size(HashMap *hashmap); * @return the memory space occupied by HashMapElem structure */ uint32 -bh_hash_map_get_elem_struct_size(); +bh_hash_map_get_elem_struct_size(void); /** * Traverse the hash map and call the callback function diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/utils/bh_list.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/utils/bh_list.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/utils/bh_list.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/utils/bh_list.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/utils/bh_list.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/utils/bh_list.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/utils/bh_list.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/utils/bh_list.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/utils/bh_log.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/utils/bh_log.c similarity index 76% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/utils/bh_log.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/utils/bh_log.c index 3e5e95ea96b..78c058065d9 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/utils/bh_log.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/utils/bh_log.c @@ -79,3 +79,29 @@ bh_print_time(const char *prompt) last_time_ms = curr_time_ms; } + +void +bh_print_proc_mem(const char *prompt) +{ + char buf[1024] = { 0 }; + + if (log_verbose_level < BH_LOG_LEVEL_DEBUG) + return; + + if (os_dumps_proc_mem_info(buf, sizeof(buf)) != 0) + return; + + os_printf("%s\n", prompt); + os_printf("===== memory usage =====\n"); + os_printf("%s", buf); + os_printf("==========\n"); + return; +} + +void +bh_log_proc_mem(const char *function, uint32 line) +{ + char prompt[128] = { 0 }; + snprintf(prompt, sizeof(prompt), "[MEM] %s(...) L%" PRIu32, function, line); + bh_print_proc_mem(prompt); +} diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/utils/bh_log.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/utils/bh_log.h similarity index 92% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/utils/bh_log.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/utils/bh_log.h index 1578028b7b4..e0bc61da26e 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/utils/bh_log.h +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/utils/bh_log.h @@ -73,6 +73,14 @@ bh_log(LogLevel log_level, const char *file, int line, const char *fmt, ...); void bh_print_time(const char *prompt); +void +bh_print_proc_mem(const char *prompt); + +void +bh_log_proc_mem(const char *function, uint32 line); + +#define LOG_PROC_MEM(...) bh_log_proc_mem(__FUNCTION__, __LINE__) + #ifdef __cplusplus } #endif diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/utils/bh_platform.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/utils/bh_platform.h similarity index 87% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/utils/bh_platform.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/utils/bh_platform.h index 3bbd0c82ba5..86aef839dd4 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/utils/bh_platform.h +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/utils/bh_platform.h @@ -35,9 +35,4 @@ #define WA_FREE wasm_runtime_free #endif -/* The epsilon value is from https://www.cplusplus.com/reference/cfloat/ */ - -#define WA_FLT_EPSILON 1e-5f -#define WA_DBL_EPSILON 1e-9 - #endif /* #ifndef _BH_PLATFORM_H */ diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/utils/bh_queue.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/utils/bh_queue.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/utils/bh_queue.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/utils/bh_queue.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/utils/bh_queue.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/utils/bh_queue.h similarity index 98% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/utils/bh_queue.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/utils/bh_queue.h index 394fed9e731..c15f4352668 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/utils/bh_queue.h +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/utils/bh_queue.h @@ -40,7 +40,7 @@ typedef void (*bh_queue_handle_msg_callback)(void *message, void *arg); typedef void (*bh_msg_cleaner)(void *msg); bh_queue * -bh_queue_create(); +bh_queue_create(void); void bh_queue_destroy(bh_queue *queue); diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/utils/bh_vector.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/utils/bh_vector.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/utils/bh_vector.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/utils/bh_vector.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/utils/bh_vector.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/utils/bh_vector.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/utils/bh_vector.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/utils/bh_vector.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/utils/runtime_timer.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/utils/runtime_timer.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/utils/runtime_timer.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/utils/runtime_timer.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/utils/runtime_timer.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/utils/runtime_timer.h similarity index 98% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/utils/runtime_timer.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/utils/runtime_timer.h index 00db2983420..b8d90c5ffbf 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/utils/runtime_timer.h +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/utils/runtime_timer.h @@ -13,7 +13,7 @@ extern "C" { #endif uint64 -bh_get_tick_ms(); +bh_get_tick_ms(void); uint32 bh_get_elpased_ms(uint32 *last_system_clock); diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/utils/shared_utils.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/utils/shared_utils.cmake similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/utils/shared_utils.cmake rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/utils/shared_utils.cmake diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/utils/uncommon/SConscript b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/utils/uncommon/SConscript similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/utils/uncommon/SConscript rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/utils/uncommon/SConscript diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/utils/uncommon/bh_getopt.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/utils/uncommon/bh_getopt.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/utils/uncommon/bh_getopt.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/utils/uncommon/bh_getopt.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/utils/uncommon/bh_getopt.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/utils/uncommon/bh_getopt.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/utils/uncommon/bh_getopt.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/utils/uncommon/bh_getopt.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/utils/uncommon/bh_read_file.c b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/utils/uncommon/bh_read_file.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/utils/uncommon/bh_read_file.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/utils/uncommon/bh_read_file.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/utils/uncommon/bh_read_file.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/utils/uncommon/bh_read_file.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/utils/uncommon/bh_read_file.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/utils/uncommon/bh_read_file.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/utils/uncommon/shared_uncommon.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/utils/uncommon/shared_uncommon.cmake similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/shared/utils/uncommon/shared_uncommon.cmake rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/shared/utils/uncommon/shared_uncommon.cmake diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/version.h b/lib/wasm-micro-runtime-WAMR-1.2.2/core/version.h similarity index 54% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/version.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/core/version.h index 0ab4312ae98..de24b30bc35 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/core/version.h +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/core/version.h @@ -3,12 +3,9 @@ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception */ -/* Please don't modify this header. It is automatically generated. - Any modification should be in config_common.cmake */ - #ifndef _WAMR_VERSION_H_ #define _WAMR_VERSION_H_ #define WAMR_VERSION_MAJOR 1 -#define WAMR_VERSION_MINOR 1 -#define WAMR_VERSION_PATCH 1 +#define WAMR_VERSION_MINOR 2 +#define WAMR_VERSION_PATCH 2 #endif diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/doc/build_wamr.md b/lib/wasm-micro-runtime-WAMR-1.2.2/doc/build_wamr.md new file mode 100644 index 00000000000..a66f27be0d7 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/doc/build_wamr.md @@ -0,0 +1,213 @@ + +# Build WAMR vmcore + +WAMR vmcore is a set of runtime libraries for loading and running Wasm modules. This document introduces how to build the WAMR vmcore. + +References: +- [how to build iwasm](../product-mini/README.md): building different target platforms such as Linux, Windows, Mac etc +- [Blog: Introduction to WAMR running modes](https://bytecodealliance.github.io/wamr.dev/blog/introduction-to-wamr-running-modes/) + + +## WAMR vmcore cmake building configurations + +By including the script `runtime_lib.cmake` under folder [build-scripts](../build-scripts) in CMakeList.txt, it is easy to use vmcore to build host software with cmake. + +```cmake +# add this into your CMakeList.txt +include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake) +add_library(vmlib ${WAMR_RUNTIME_LIB_SOURCE}) +``` + +The script `runtime_lib.cmake` defines a number of variables for configuring the WAMR runtime features. You can set these variables in your CMakeList.txt or pass the configurations from cmake command line. + +#### **Configure platform and architecture** + +- **WAMR_BUILD_PLATFORM**: set the target platform. It can be set to any platform name (folder name) under folder [core/shared/platform](../core/shared/platform). + +- **WAMR_BUILD_TARGET**: set the target CPU architecture. Current supported targets are: X86_64, X86_32, AARCH64, ARM, THUMB, XTENSA, ARC, RISCV32, RISCV64 and MIPS. + - For ARM and THUMB, the format is \\[\]\[_VFP], where \ is the ARM sub-architecture and the "_VFP" suffix means using VFP coprocessor registers s0-s15 (d0-d7) for passing arguments or returning results in standard procedure-call. Both \ and "_VFP" are optional, e.g. ARMV7, ARMV7_VFP, THUMBV7, THUMBV7_VFP and so on. + - For AARCH64, the format is\[\], VFP is enabled by default. \ is optional, e.g. AARCH64, AARCH64V8, AARCH64V8.1 and so on. + - For RISCV64, the format is \[_abi], where "_abi" is optional, currently the supported formats are RISCV64, RISCV64_LP64D and RISCV64_LP64: RISCV64 and RISCV64_LP64D are identical, using [LP64D](https://github.com/riscv/riscv-elf-psabi-doc/blob/master/riscv-elf.md#-named-abis) as abi (LP64 with hardware floating-point calling convention for FLEN=64). And RISCV64_LP64 uses [LP64](https://github.com/riscv/riscv-elf-psabi-doc/blob/master/riscv-elf.md#-named-abis) as abi (Integer calling-convention only, and hardware floating-point calling convention is not used). + - For RISCV32, the format is \[_abi], where "_abi" is optional, currently the supported formats are RISCV32, RISCV32_ILP32D and RISCV32_ILP32: RISCV32 and RISCV32_ILP32D are identical, using [ILP32D](https://github.com/riscv/riscv-elf-psabi-doc/blob/master/riscv-elf.md#-named-abis) as abi (ILP32 with hardware floating-point calling convention for FLEN=64). And RISCV32_ILP32 uses [ILP32](https://github.com/riscv/riscv-elf-psabi-doc/blob/master/riscv-elf.md#-named-abis) as abi (Integer calling-convention only, and hardware floating-point calling convention is not used). + +```bash +cmake -DWAMR_BUILD_PLATFORM=linux -DWAMR_BUILD_TARGET=ARM +``` + +#### **Configure interpreters** + +- **WAMR_BUILD_INTERP**=1/0: enable or disable WASM interpreter + +- **WAMR_BUILD_FAST_INTERP**=1/0: build fast (default) or classic WASM interpreter. + + NOTE: the fast interpreter runs ~2X faster than classic interpreter, but consumes about 2X memory to hold the pre-compiled code. + +#### **Configure AOT and JITs** + +- **WAMR_BUILD_AOT**=1/0, enable AOT or not, default to enable if not set +- **WAMR_BUILD_JIT**=1/0, enable LLVM JIT or not, default to disable if not set +- **WAMR_BUILD_FAST_JIT**=1/0, enable Fast JIT or not, default to disable if not set +- **WAMR_BUILD_FAST_JIT**=1 and **WAMR_BUILD_JIT**=1, enable Multi-tier JIT, default to disable if not set + +#### **Configure LIBC** + +- **WAMR_BUILD_LIBC_BUILTIN**=1/0, build the built-in libc subset for WASM app, default to enable if not set + +- **WAMR_BUILD_LIBC_WASI**=1/0, build the [WASI](https://github.com/WebAssembly/WASI) libc subset for WASM app, default to enable if not set + +- **WAMR_BUILD_LIBC_UVWASI**=1/0 (Experiment), build the [WASI](https://github.com/WebAssembly/WASI) libc subset for WASM app based on [uvwasi](https://github.com/nodejs/uvwasi) implementation, default to disable if not set + +> Note: for platform which doesn't support **WAMR_BUILD_LIBC_WASI**, e.g. Windows, developer can try using **WAMR_BUILD_LIBC_UVWASI**. + +#### **Enable Multi-Module feature** + +- **WAMR_BUILD_MULTI_MODULE**=1/0, default to disable if not set + +#### **Enable WASM mini loader** + +- **WAMR_BUILD_MINI_LOADER**=1/0, default to disable if not set + +> Note: the mini loader doesn't check the integrity of the WASM binary file, developer must ensure that the WASM file is well-formed. + +#### **Enable shared memory feature** +- **WAMR_BUILD_SHARED_MEMORY**=1/0, default to disable if not set + +#### **Enable bulk memory feature** +- **WAMR_BUILD_BULK_MEMORY**=1/0, default to disable if not set + +#### **Enable thread manager** +- **WAMR_BUILD_THREAD_MGR**=1/0, default to disable if not set + +#### **Enable lib-pthread** +- **WAMR_BUILD_LIB_PTHREAD**=1/0, default to disable if not set +> Note: The dependent feature of lib pthread such as the `shared memory` and `thread manager` will be enabled automatically. + +#### **Enable lib-pthread-semaphore** +- **WAMR_BUILD_LIB_PTHREAD_SEMAPHORE**=1/0, default to disable if not set +> Note: This feature depends on `lib-pthread`, it will be enabled automatically if this feature is enabled. + +#### **Enable lib wasi-threads** +- **WAMR_BUILD_LIB_WASI_THREADS**=1/0, default to disable if not set +> Note: The dependent feature of lib wasi-threads such as the `shared memory` and `thread manager` will be enabled automatically. + +#### **Enable lib wasi-nn** +- **WAMR_BUILD_WASI_NN**=1/0, default to disable if not set + +#### **Enable lib wasi-nn GPU mode** +- **WASI_NN_ENABLE_GPU**=1/0, default to disable if not set + +#### **Disable boundary check with hardware trap** +- **WAMR_DISABLE_HW_BOUND_CHECK**=1/0, default to enable if not set and supported by platform +> Note: by default only platform linux/darwin/android/windows/vxworks 64-bit will enable the boundary check with hardware trap feature, and the wamrc tool will generate AOT code without boundary check instructions in all 64-bit targets except SGX to improve performance. The boundary check includes linear memory access boundary and native stack access boundary, if `WAMR_DISABLE_STACK_HW_BOUND_CHECK` below isn't set. + +#### **Disable native stack boundary check with hardware trap** +- **WAMR_DISABLE_STACK_HW_BOUND_CHECK**=1/0, default to enable if not set and supported by platform, same as `WAMR_DISABLE_HW_BOUND_CHECK`. +> Note: When boundary check with hardware trap is disabled, or `WAMR_DISABLE_HW_BOUND_CHECK` is set to 1, the native stack boundary check with hardware trap will be disabled too, no matter what value is set to `WAMR_DISABLE_STACK_HW_BOUND_CHECK`. And when boundary check with hardware trap is enabled, the status of this feature is set according to the value of `WAMR_DISABLE_STACK_HW_BOUND_CHECK`. + +#### **Enable tail call feature** +- **WAMR_BUILD_TAIL_CALL**=1/0, default to disable if not set + +#### **Enable 128-bit SIMD feature** +- **WAMR_BUILD_SIMD**=1/0, default to enable if not set +> Note: only supported in AOT mode x86-64 target. + +#### **Configure Debug** + +- **WAMR_BUILD_CUSTOM_NAME_SECTION**=1/0, load the function name from custom name section, default to disable if not set + +#### **Enable dump call stack feature** +- **WAMR_BUILD_DUMP_CALL_STACK**=1/0, default to disable if not set + +> Note: if it is enabled, the call stack will be dumped when exception occurs. + +> - For interpreter mode, the function names are firstly extracted from *custom name section*, if this section doesn't exist or the feature is not enabled, then the name will be extracted from the import/export sections +> - For AOT/JIT mode, the function names are extracted from import/export section, please export as many functions as possible (for `wasi-sdk` you can use `-Wl,--export-all`) when compiling wasm module, and add `--enable-dump-call-stack` option to wamrc during compiling AOT module. + +#### **Enable memory profiling (Experiment)** +- **WAMR_BUILD_MEMORY_PROFILING**=1/0, default to disable if not set +> Note: if it is enabled, developer can use API `void wasm_runtime_dump_mem_consumption(wasm_exec_env_t exec_env)` to dump the memory consumption info. +Currently we only profile the memory consumption of module, module_instance and exec_env, the memory consumed by other components such as `wasi-ctx`, `multi-module` and `thread-manager` are not included. + +#### **Enable performance profiling (Experiment)** +- **WAMR_BUILD_PERF_PROFILING**=1/0, default to disable if not set +> Note: if it is enabled, developer can use API `void wasm_runtime_dump_perf_profiling(wasm_module_inst_t module_inst)` to dump the performance consumption info. Currently we only profile the performance consumption of each WASM function. + +> The function name searching sequence is the same with dump call stack feature. + +#### **Enable the global heap** +- **WAMR_BUILD_GLOBAL_HEAP_POOL**=1/0, default to disable if not set for all *iwasm* applications, except for the platforms Alios and Zephyr. + +> **WAMR_BUILD_GLOBAL_HEAP_POOL** is used in the *iwasm* applications provided in the directory `product-mini`. When writing your own host application using WAMR, if you want to use a global heap and allocate memory from it, you must set the initialization argument `mem_alloc_type` to `Alloc_With_Pool`. +> The global heap is defined in the documentation [Memory model and memory usage tunning](memory_tune.md). + +#### **Set the global heap size** +- **WAMR_BUILD_GLOBAL_HEAP_SIZE**=n, default to 10 MB (10485760) if not set for all *iwasm* applications, except for the platforms Alios (256 kB), Riot (256 kB) and Zephyr (128 kB). + +> **WAMR_BUILD_GLOBAL_HEAP_SIZE** is used in the *iwasm* applications provided in the directory `product-mini`. When writing your own host application using WAMR, if you want to set the amount of memory dedicated to the global heap pool, you must set the initialization argument `mem_alloc_option.pool` with the appropriate values. +> The global heap is defined in the documentation [Memory model and memory usage tunning](memory_tune.md). +> Note: if `WAMR_BUILD_GLOBAL_HEAP_SIZE` is not set and the flag `WAMR_BUILD_SPEC_TEST` is set, the global heap size is equal to 300 MB (314572800), or 100 MB (104857600) when compiled for Intel SGX (Linux). + +#### **Set maximum app thread stack size** +- **WAMR_APP_THREAD_STACK_SIZE_MAX**=n, default to 8 MB (8388608) if not set +> Note: the AOT boundary check with hardware trap mechanism might consume large stack since the OS may lazily grow the stack mapping as a guard page is hit, we may use this configuration to reduce the total stack usage, e.g. -DWAMR_APP_THREAD_STACK_SIZE_MAX=131072 (128 KB). + +#### **WAMR_BH_VPRINTF**=, default to disable if not set +> Note: if the vprintf_callback function is provided by developer, the os_printf() and os_vprintf() in Linux, Darwin, Windows and VxWorks platforms, besides WASI Libc output will call the callback function instead of libc vprintf() function to redirect the stdout output. For example, developer can define the callback function like below outside runtime lib: +> +> ```C +> int my_vprintf(const char *format, va_list ap) +> { +> /* output to pre-opened file stream */ +> FILE *my_file = ...; +> return vfprintf(my_file, format, ap); +> /* or output to pre-opened file descriptor */ +> int my_fd = ...; +> return vdprintf(my_fd, format, ap); +> /* or output to string buffer and print the string */ +> char buf[128]; +> vsnprintf(buf, sizeof(buf), format, ap); +> return my_printf("%s", buf); +> } +> ``` +> +> and then use `cmake -DWAMR_BH_VPRINTF=my_vprintf ..` to pass the callback function, or add `BH_VPRINTF=my_vprintf` macro for the compiler, e.g. add line `add_defintions(-DBH_VPRINTF=my_vprintf)` in CMakeListst.txt. + +#### **Enable reference types feature** +- **WAMR_BUILD_REF_TYPES**=1/0, default to disable if not set + +#### **Exclude WAMR application entry functions** +- **WAMR_DISABLE_APP_ENTRY**=1/0, default to disable if not set + +> Note: The WAMR application entry (`core/iwasm/common/wasm_application.c`) encapsulate some common process to instantiate, execute the wasm functions and print the results. Some platform related APIs are used in these functions, so you can enable this flag to exclude this file if your platform doesn't support those APIs. +> *Don't enable this flag if you are building `product-mini`* + +#### **Enable source debugging features** +- **WAMR_BUILD_DEBUG_INTERP**=1/0, default to 0 if not set +> Note: There are some other setup required by source debugging, please refer to [source_debugging.md](./source_debugging.md) for more details. + +#### **Enable load wasm custom sections** +- **WAMR_BUILD_LOAD_CUSTOM_SECTION**=1/0, default to disable if not set + +> Note: By default, the custom sections are ignored. If the embedder wants to get custom sections from `wasm_module_t`, then `WAMR_BUILD_LOAD_CUSTOM_SECTION` should be enabled, and then `wasm_runtime_get_custom_section` can be used to get a custom section by name. + +> Note: If `WAMR_BUILD_CUSTOM_NAME_SECTION` is enabled, then the `custom name section` will be treated as a special section and consumed by the runtime, not available to the embedder. + +> For AoT file, must use `--emit-custom-sections` to specify which sections need to be emitted into AoT file, otherwise all custom sections (except custom name section) will be ignored. + +### **Stack guard size** +- **WAMR_BUILD_STACK_GUARD_SIZE**=n, default to N/A if not set. +> Note: By default, the stack guard size is 1K (1024) or 24K (if uvwasi enabled). + +**Combination of configurations:** + +We can combine the configurations. For example, if we want to disable interpreter, enable AOT and WASI, we can run command: + +``` Bash +cmake .. -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_AOT=1 -DWAMR_BUILD_LIBC_WASI=0 -DWAMR_BUILD_PLATFORM=linux +``` + +Or if we want to enable interpreter, disable AOT and WASI, and build as X86_32, we can run command: + +``` Bash +cmake .. -DWAMR_BUILD_INTERP=1 -DWAMR_BUILD_AOT=0 -DWAMR_BUILD_LIBC_WASI=0 -DWAMR_BUILD_TARGET=X86_32 +``` diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/doc/build_wasm_app.md b/lib/wasm-micro-runtime-WAMR-1.2.2/doc/build_wasm_app.md similarity index 94% rename from lib/wasm-micro-runtime-WAMR-1.1.1/doc/build_wasm_app.md rename to lib/wasm-micro-runtime-WAMR-1.2.2/doc/build_wasm_app.md index 5039e4badaf..40f1b89dd78 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/doc/build_wasm_app.md +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/doc/build_wasm_app.md @@ -3,12 +3,12 @@ Prepare WASM building environments ================================== -For C and C++, WASI-SDK version 12.0+ is the major tool supported by WAMR to build WASM applications. Also, we can use [Emscripten SDK (EMSDK)](https://github.com/emscripten-core/emsdk), but it is not recommended. And there are some other compilers such as the standard clang compiler, which might also work [here](./other_wasm_compilers.md). +For C and C++, WASI-SDK version 19.0+ is the major tool supported by WAMR to build WASM applications. Also, we can use [Emscripten SDK (EMSDK)](https://github.com/emscripten-core/emsdk), but it is not recommended. And there are some other compilers such as the standard clang compiler, which might also work [here](./other_wasm_compilers.md). To install WASI SDK, please download the [wasi-sdk release](https://github.com/CraneStation/wasi-sdk/releases) and extract the archive to default path `/opt/wasi-sdk`. The official *wasi-sdk release* doesn't fully support *latest 128-bit SIMD spec* yet. WAMR provides a script in [build-wasi-sdk](../test-tools/build-wasi-sdk/) to generate -another wasi-sdk with *llvm-13* from source code and installs it at *../test-tools/wasi-sdk*. If you plan to build WASM applications with *latest 128-bit SIMD*, please use it instead of the official release. +another wasi-sdk with *llvm-15* from source code and installs it at *../test-tools/wasi-sdk*. If you plan to build WASM applications with *latest 128-bit SIMD*, please use it instead of the official release. And [sample workloads](../samples/workload) are using the self-compiled wasi-sdk. @@ -126,6 +126,18 @@ If we want to build the wasm app with wasi mode, we may build the wasm app with to generate a wasm binary with wasi mode, the auxiliary stack size is 8192 bytes, initial memory size is 64 KB, heap base global and data end global are exported, wasi entry function exported (_start function), and all symbols are stripped. Note that it is wasi mode, so libc-wasi should be enabled by runtime embedder or iwasm (with `cmake -DWAMR_BUILD_LIBC_WASI=1`, enabled by iwasm in Linux by default), and normally no need to export main function, by default _start function is executed by iwasm. +> Note: for the Rust project, we can set these flags by setting the `rustflags` in the Cargo configuration file, e.g. `/.cargo/config.toml` or `$CARGO_HOME/config.toml`, for example: +> ```toml +> [build] +> rustflags = [ +> "-C", "link-arg=--initial-memory=65536", +> "-C", "link-arg=-zstack-size=8192", +> "-C", "link-arg=--export=__heap_base", +> "-C", "link-arg=--export=__data_end", +> "-C", "link-arg=--strip-all", +> ] +> ``` + ## 2. How to reduce the footprint? Firstly if libc-builtin (-nostdlib) mode meets the requirements, e.g. there are no file io operations in wasm app, we should build the wasm app with -nostdlib option as possible as we can, since the compiler doesn't build the libc source code into wasm bytecodes, which greatly reduces the binary size. @@ -138,12 +150,38 @@ Firstly if libc-builtin (-nostdlib) mode meets the requirements, e.g. there are ``` If the two globals are exported, and there are no memory.grow and memory.size opcodes (normally nostdlib mode doesn't introduce these opcodes since the libc malloc function isn't built into wasm bytecode), WAMR runtime will truncate the linear memory at the place of \__heap_base and append app heap to the end, so we don't need to allocate the memory specified by `-Wl,--initial-memory=n` which must be at least 64 KB. This is helpful for some embedded devices whose memory resource might be limited. +> For the Rust project, please set the flags in the Cargo configuration file, for example: +> ```toml +> [build] +> rustflags = [ +> "-C", "link-arg=--export=__heap_base", +> "-C", "link-arg=--export=__data_end", +> "-C", "link-arg=--initial-memory=65536", +> ] +> ``` + - reduce auxiliary stack size The auxiliary stack is an area of linear memory, normally the size is 64 KB by default which might be a little large for embedded devices and partly used, we can use `-z stack-size=n` to set its size. +> For the Rust project, please set the flag in the Cargo configuration file, for example: +> ```toml +> [build] +> rustflags = [ +> "-C", "link-arg=-zstack-size=8192" +> ] +> ``` + - use -O3 and -Wl,--strip-all +> For the Rust project, please set the flag in the Cargo configuration file, for example: +> ```toml +> [build] +> rustflags = [ +> "-C", "link-arg=--strip-all" +> ] +> ``` + - reduce app heap size when running iwasm We can pass `--heap-size=n` option to set the maximum app heap size for iwasm, by default it is 16 KB. For the runtime embedder, we can set the `uint32_t heap_size` argument when calling API ` wasm_runtime_instantiate`. diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/doc/devcontainer.md b/lib/wasm-micro-runtime-WAMR-1.2.2/doc/devcontainer.md similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/doc/devcontainer.md rename to lib/wasm-micro-runtime-WAMR-1.2.2/doc/devcontainer.md diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/doc/embed_wamr.md b/lib/wasm-micro-runtime-WAMR-1.2.2/doc/embed_wamr.md similarity index 99% rename from lib/wasm-micro-runtime-WAMR-1.1.1/doc/embed_wamr.md rename to lib/wasm-micro-runtime-WAMR-1.2.2/doc/embed_wamr.md index ae3fe418136..0503840277a 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/doc/embed_wamr.md +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/doc/embed_wamr.md @@ -1,7 +1,7 @@ Embedding WAMR guideline ===================================== -**Note**: This document is about how to embed WAMR into C/C++ host applications, for other languages, please refer to: [Embed WAMR into Python](../language-bindings/go), [Embed WAMR into Go](../language-bindings/go). +**Note**: This document is about how to embed WAMR into C/C++ host applications, for other languages, please refer to: [Embed WAMR into Python](../language-bindings/python), [Embed WAMR into Go](../language-bindings/go). All the embedding APIs supported by the runtime are defined under folder [core/iwasm/include](../core/iwasm/include). The API details are available in the header files. diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/doc/export_native_api.md b/lib/wasm-micro-runtime-WAMR-1.2.2/doc/export_native_api.md similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/doc/export_native_api.md rename to lib/wasm-micro-runtime-WAMR-1.2.2/doc/export_native_api.md diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/doc/linux_sgx.md b/lib/wasm-micro-runtime-WAMR-1.2.2/doc/linux_sgx.md similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/doc/linux_sgx.md rename to lib/wasm-micro-runtime-WAMR-1.2.2/doc/linux_sgx.md diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/doc/memory_tune.md b/lib/wasm-micro-runtime-WAMR-1.2.2/doc/memory_tune.md similarity index 94% rename from lib/wasm-micro-runtime-WAMR-1.1.1/doc/memory_tune.md rename to lib/wasm-micro-runtime-WAMR-1.2.2/doc/memory_tune.md index c3703390ef9..e14a1a164d4 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/doc/memory_tune.md +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/doc/memory_tune.md @@ -1,5 +1,8 @@ -Memory model and memory usage tunning -===================================== +# Memory model and memory usage tunning + +References: +- [Blog: Understand WAMR heap](https://bytecodealliance.github.io/wamr.dev/blog/understand-the-wamr-heaps/) +- [Blog: Understand WAMR stacks](https://bytecodealliance.github.io/wamr.dev/blog/understand-the-wamr-stacks/) ## The memory model diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/doc/memory_usage.md b/lib/wasm-micro-runtime-WAMR-1.2.2/doc/memory_usage.md new file mode 100644 index 00000000000..ec0624c6fed --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/doc/memory_usage.md @@ -0,0 +1,134 @@ +Memory usage estimation for a module +==================================== + +This document aims to provide information useful to make a rough estimation +of necessary memory to execute a WASM module. + +Instead of trying to cover every possible configurations, +the following configuration is assumed in this document: + +* Module is built with `wasi-sdk` +* Module is loaded with `wasm_runtime_load` +* AOT is used +* WASI is used +* libc heap is used +* app heap is not used +* The pthread implementation in `wasi-libc`, which is based on `wasi-threads` + (`WASM_ENABLE_LIB_WASI_THREADS`) might be used +* The another pthread implementation (`WASM_ENABLE_LIB_PTHREAD`) is not used + +Module +------ + +The memory to store the module binary is allocated by the embedder and +passed to `wasm_runtime_load`. +While WAMR owns the buffer, WAMR might make in-place modifications to +its contents. + +Loaded module and its instances +------------------------------- + +Many of data structures for module and instances are allocated from +the global heap. (aka. `wasm_runtime_malloc`) + +AOT code section +---------------- + +Memory to load AOT machine code section. + +Because this memory needs to be executable, depending on platforms, +it's allocated from a separate allocator. +For example, `mmap` and `mprotect` are used on POSIX-like platforms. + +Linear memory +------------- + +A WASM linear memory is either shared or non-shared. + +A WASM linear memory has `min` and `max` sizes. +(They correspond to `wasm-ld`'s `--init-memory` and `--max-memory` options.) +They are in the number of WASM pages, each of which is of 65536 bytes. +The `max` is optional for non-shared memory. When omitted, it effectivily +means unlimited. + +If `OS_ENABLE_HW_BOUND_CHECK` is enabled, the memory is allocated via +`os_mmap` and `os_mem_commit`/`os_mprotect`. +Otherwise, it's allocated from the global heap. + +If the memory is shared and `OS_ENABLE_HW_BOUND_CHECK` is not enabled, +the `max` size of memory is allocated on instantiation. + +Otherwise, the `min` size of memory is allocated on instantiation. +It can later grow up to the `max` size via the `memory.grow` instruction. + +Libc heap +--------- + +The libc heap is the last (highest address) part of linear memory, +which might be dynamically grown with `memory.grow` instruction, when +necessary to serve memory allocations within the module. + +App heap +-------- + +Not used for the above mentioned configuration. + +You can safely disable the app heap creation by specifying `0` for +the `heap_size` argument of `wasm_runtime_instantiate`. +(It's automatically disabled if malloc/free are exported from the module.) + +WASM stack +---------- + +Operand stack is not used for AOT. + +However, a small amount of WASM stack is used for call frames when +certain features are enabled. +(`WASM_ENABLE_DUMP_CALL_STACK` or `WASM_ENABLE_PERF_PROFILING`) + +It's allocated from the global heap. + +You can specify its size with the `stack_size` argument of +`wasm_runtime_instantiate` and `wasm_runtime_create_exec_env`. +(1 is the minimum because 0 means the default.) + +AUX stack (aka. C shadow stack) +------------------------------- + +For the main thread, it's a part of the linear memory, +between `__data_end` and `__heap_base` symbols. +You can control the size of this stack with `wasm-ld`'s +`-z stack-size` option. + +For threads created by `pthread_create`, libc allocates the stack for +them dynamically from the libc heap. +The size of this stack is inherited from the main thread's one +unless overwritten with `pthread_attr_setstacksize` etc. + +WAMR tries to detect overflow/underflow when updating the stack pointer +global. For threads created by `pthread_create`, the detection mechanism +is disabled as of writing this. + +Native stack +------------ + +The stack of the host environment thread which runs WAMR. + +For threads created by `pthread_create`, WAMR automatically creates +host threads to run those WASM threads. The stack size of these host +threads are controlled by a build-time configuration. +(`APP_THREAD_STACK_SIZE_DEFAULT`) + +In some configurations, runtime overflow can be detected using hardware traps. +(`OS_ENABLE_HW_BOUND_CHECK`) + +In some configurations, explicit overflow detection logic can be emitted +into AOT modules themselves. (cf. `os_thread_get_stack_boundary`, +`check_stack_boundary`, `wamrc --stack-bounds-checks=1/0`) + +Memory profiling +================ + +You can collect and dump detailed information about memory usage +by actually running a module with the `WASM_ENABLE_MEMORY_PROFILING` +build-time option. diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/doc/multi_module.md b/lib/wasm-micro-runtime-WAMR-1.2.2/doc/multi_module.md similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/doc/multi_module.md rename to lib/wasm-micro-runtime-WAMR-1.2.2/doc/multi_module.md diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/doc/other_wasm_compilers.md b/lib/wasm-micro-runtime-WAMR-1.2.2/doc/other_wasm_compilers.md similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/doc/other_wasm_compilers.md rename to lib/wasm-micro-runtime-WAMR-1.2.2/doc/other_wasm_compilers.md diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/doc/pics/app_framework.PNG b/lib/wasm-micro-runtime-WAMR-1.2.2/doc/pics/app_framework.PNG similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/doc/pics/app_framework.PNG rename to lib/wasm-micro-runtime-WAMR-1.2.2/doc/pics/app_framework.PNG diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/doc/pics/embed.PNG b/lib/wasm-micro-runtime-WAMR-1.2.2/doc/pics/embed.PNG similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/doc/pics/embed.PNG rename to lib/wasm-micro-runtime-WAMR-1.2.2/doc/pics/embed.PNG diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/doc/pics/extend_library.PNG b/lib/wasm-micro-runtime-WAMR-1.2.2/doc/pics/extend_library.PNG similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/doc/pics/extend_library.PNG rename to lib/wasm-micro-runtime-WAMR-1.2.2/doc/pics/extend_library.PNG diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/doc/pics/multi_module_pic1.png b/lib/wasm-micro-runtime-WAMR-1.2.2/doc/pics/multi_module_pic1.png similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/doc/pics/multi_module_pic1.png rename to lib/wasm-micro-runtime-WAMR-1.2.2/doc/pics/multi_module_pic1.png diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/doc/pics/native_call_wasm.PNG b/lib/wasm-micro-runtime-WAMR-1.2.2/doc/pics/native_call_wasm.PNG similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/doc/pics/native_call_wasm.PNG rename to lib/wasm-micro-runtime-WAMR-1.2.2/doc/pics/native_call_wasm.PNG diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/doc/pics/request.PNG b/lib/wasm-micro-runtime-WAMR-1.2.2/doc/pics/request.PNG similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/doc/pics/request.PNG rename to lib/wasm-micro-runtime-WAMR-1.2.2/doc/pics/request.PNG diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/doc/pics/safe.PNG b/lib/wasm-micro-runtime-WAMR-1.2.2/doc/pics/safe.PNG similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/doc/pics/safe.PNG rename to lib/wasm-micro-runtime-WAMR-1.2.2/doc/pics/safe.PNG diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/doc/pics/sensor_callflow.PNG b/lib/wasm-micro-runtime-WAMR-1.2.2/doc/pics/sensor_callflow.PNG similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/doc/pics/sensor_callflow.PNG rename to lib/wasm-micro-runtime-WAMR-1.2.2/doc/pics/sensor_callflow.PNG diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/doc/pics/sub.PNG b/lib/wasm-micro-runtime-WAMR-1.2.2/doc/pics/sub.PNG similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/doc/pics/sub.PNG rename to lib/wasm-micro-runtime-WAMR-1.2.2/doc/pics/sub.PNG diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/doc/pics/vgl_demo.png b/lib/wasm-micro-runtime-WAMR-1.2.2/doc/pics/vgl_demo.png similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/doc/pics/vgl_demo.png rename to lib/wasm-micro-runtime-WAMR-1.2.2/doc/pics/vgl_demo.png diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/doc/pics/vgl_demo2.png b/lib/wasm-micro-runtime-WAMR-1.2.2/doc/pics/vgl_demo2.png similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/doc/pics/vgl_demo2.png rename to lib/wasm-micro-runtime-WAMR-1.2.2/doc/pics/vgl_demo2.png diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/doc/pics/vgl_demo_linux.png b/lib/wasm-micro-runtime-WAMR-1.2.2/doc/pics/vgl_demo_linux.png similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/doc/pics/vgl_demo_linux.png rename to lib/wasm-micro-runtime-WAMR-1.2.2/doc/pics/vgl_demo_linux.png diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/doc/pics/vgl_linux.PNG b/lib/wasm-micro-runtime-WAMR-1.2.2/doc/pics/vgl_linux.PNG similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/doc/pics/vgl_linux.PNG rename to lib/wasm-micro-runtime-WAMR-1.2.2/doc/pics/vgl_linux.PNG diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/doc/pics/wamr-arch.JPG b/lib/wasm-micro-runtime-WAMR-1.2.2/doc/pics/wamr-arch.JPG similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/doc/pics/wamr-arch.JPG rename to lib/wasm-micro-runtime-WAMR-1.2.2/doc/pics/wamr-arch.JPG diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/doc/pics/wamr_memory_model.png b/lib/wasm-micro-runtime-WAMR-1.2.2/doc/pics/wamr_memory_model.png similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/doc/pics/wamr_memory_model.png rename to lib/wasm-micro-runtime-WAMR-1.2.2/doc/pics/wamr_memory_model.png diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/doc/pics/wamr_menu_config.png b/lib/wasm-micro-runtime-WAMR-1.2.2/doc/pics/wamr_menu_config.png similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/doc/pics/wamr_menu_config.png rename to lib/wasm-micro-runtime-WAMR-1.2.2/doc/pics/wamr_menu_config.png diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/doc/port_wamr.md b/lib/wasm-micro-runtime-WAMR-1.2.2/doc/port_wamr.md similarity index 57% rename from lib/wasm-micro-runtime-WAMR-1.1.1/doc/port_wamr.md rename to lib/wasm-micro-runtime-WAMR-1.2.2/doc/port_wamr.md index 44ac50ece58..7899ff3186c 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/doc/port_wamr.md +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/doc/port_wamr.md @@ -10,9 +10,13 @@ This document describes how to port WAMR to a new platform "**new-os**" # Step 1: Implement platform API layer ------------------------- -Firstly create the folder **`core/shared/platform/new-os`** for platform API layer implementations. In the folder you just created, you must provide the following files: +Firstly create the folder for platform API layer implementations: +* for common platforms, create a folder in **`core/shared/platform/new-os`** in WAMR repository folder, so the implementation can be upstreamed +* for platforms that are internal and its implementation shouldn't be published, it's recommended to create a folder outside of the WAMR repository folder (e.g. have separate repository for platform API layer implementation) -- `platform_internal.h`: It can be used for any platform specific definitions such as macros, data types and internal APIs. +In the folder you just created, you must provide the following files: + +- `platform_internal.h`: It can be used for any platform-specific definitions such as macros, data types and internal APIs. - `shared_platform.cmake`: the cmake file will be included by the building script. It is recommended to add a definition for your platform: @@ -20,29 +24,29 @@ Firstly create the folder **`core/shared/platform/new-os`** for platform API lay add_definitions(-DBH_PLATFORM_YOUR_NAME) ``` -Then go to implement the APIs defined in following header files for the platform abstraction layer: +Then go to implement the APIs defined in the following header files for the platform abstraction layer: -- [`platform_api_vmcore.h`](../core/shared/platform/include/platform_api_vmcore.h): mandatory for building mini-product (vmcore only). Part of APIs are needed only for Ahead of Time compilation support. +- [`platform_api_vmcore.h`](../core/shared/platform/include/platform_api_vmcore.h): mandatory for building mini-product (vmcore only). Part of the APIs is needed only for Ahead of Time compilation support. - [`platform_api_extension.h`](../core/shared/platform/include/platform_api_extension.h): mandatory for app-mgr and app-framework. Given that the app-mgr and app-framework are not required for your target platform, you won't have to implement the API defined in the `platform_api_extension.h`. **common/posix:** -There is posix based implementation of the platform API located in the `platform/common/posix` folder. You can include it if your platform support posix API. refer to platform linux implementation. +There is posix based implementation of the platform API located in the `platform/common/posix` folder. You can include it if your platform supports posix API. refer to platform linux implementation. **common/math:** -Some platforms such as ZephyrOS don't provide math functions e.g. sqrt, fabs and isnan, then you should include source files under the folder `platform/common/math`. +Some platforms such as ZephyrOS don't provide math functions e.g. sqrt, fabs and isnan, then you should include source files under the folder `platform/common/math`. # Step 2: Create the mini product for the platform ------------------------- -You can build a mini WAMR product which is only the vmcore for you platform. Normally you need to implement the main function which loads a WASM file and run it with the WASM runtime. You don't have to do this step if there is no mini-product need for your platform porting. +You can build a mini WAMR product which is only the vmcore for your platform. Normally you need to implement the main function which loads a WASM file and run it with the WASM runtime. You don't have to do this step if there is no mini-product need for your platform porting. @@ -55,9 +59,14 @@ You should set cmake variable `WAMR_BUILD_PLATFORM` to your platform name while ``` mkdir build cd build -cmake .. -DWAMR_BUILD_PLATFORM=new-os +cmake .. -DWAMR_BUILD_PLATFORM=new-os ``` +For platform implementations that are outside of the WAMR repository (e.g. internal platforms), you also need to provide `SHARED_PLATFORM_CONFIG` path: + +``` +cmake .. -DWAMR_BUILD_PLATFORM=new-os -DSHARED_PLATFORM_CONFIG=/path/to/new-os/shared_platform.cmake +``` Refer to [build_wamr.md](./build_wamr.md) for the building configurations and parameters. diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/doc/pthread_impls.md b/lib/wasm-micro-runtime-WAMR-1.2.2/doc/pthread_impls.md new file mode 100644 index 00000000000..92b51cb4a7b --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/doc/pthread_impls.md @@ -0,0 +1,59 @@ +# Pthread implementations + +WAMR has two pthread implementations available as of writing this. + +These implementations are not ABI-compatible. You at least need to rebuild +your wasm modules when migrating from one pthread implementation to another. + +For new users, we recommend to use (or at least experiment) +the new wasi-threads based implementation. +In future, we might remove the old implementation. + +## WAMR lib-pthread (old) + + * The pthread API is directly implemented as host functions in WAMR. + (`WAMR_BUILD_LIB_PTHREAD`) + + * Only minimum API is implemented as of writing this. + (eg. no pthread barriers) + + * WAMR-specific ABI + + * [Known limitations](pthread_library.md#known-limits) + +## wasi-threads (new) + + * The pthread API is implemented in wasi-libc, based on + [wasi-threads](https://github.com/WebAssembly/wasi-threads) + and [WASM threads](https://github.com/WebAssembly/threads) proposals. + + * It requires a recent-enough version of wasi-libc. The experimental support + is included in + [wasi-sdk 20.0](https://github.com/WebAssembly/wasi-sdk/releases/tag/wasi-sdk-20) + or later. + To build your application, cmake users can use the + [cmake toolchain file](https://github.com/WebAssembly/wasi-sdk/blob/main/wasi-sdk-pthread.cmake) + provided by wasi-sdk. + + * wasi-threads is implemented as a host function in WAMR. + (`WAMR_BUILD_LIB_WASI_THREADS`) + + * The ABI is specified in wasi-threads proposal. + You can run the same wasm modules on other runtimes which implement + the proposal. (wasmtime, toywasm, ...) + + * Basically more feature-rich and complete than WAMR lib-pthread. + + **EXCEPTION**: `pthread_exit` is not available as of writing this. + If `pthread_exit` is important for your use cases, please speak up in + the [GitHub issue](https://github.com/WebAssembly/wasi-threads/issues/7). + + **EXCEPTION**: For threads created by `pthread_create`, the AUX stack + (aka C shadow stack) overflow detection mechanism is disabled as of + writing this. + If it's important for your use cases, please speak up in the + [GitHub issue](https://github.com/WebAssembly/wasi-threads/issues/12). + +# References + +* https://github.com/bytecodealliance/wasm-micro-runtime/issues/1790 diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/doc/pthread_library.md b/lib/wasm-micro-runtime-WAMR-1.2.2/doc/pthread_library.md similarity index 98% rename from lib/wasm-micro-runtime-WAMR-1.1.1/doc/pthread_library.md rename to lib/wasm-micro-runtime-WAMR-1.2.2/doc/pthread_library.md index cd188670dde..ba43ee1c04e 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/doc/pthread_library.md +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/doc/pthread_library.md @@ -1,5 +1,8 @@ # WAMR pthread library +**Note**: This document describes the old pthread implementation. +See [Pthread implementations](pthread_impls.md). + WAMR provides a built-in library to support pthread APIs. You can call pthread APIs in your application source code. ## Build and run diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/doc/ref_types.md b/lib/wasm-micro-runtime-WAMR-1.2.2/doc/ref_types.md similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/doc/ref_types.md rename to lib/wasm-micro-runtime-WAMR-1.2.2/doc/ref_types.md diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/doc/release_ack.md b/lib/wasm-micro-runtime-WAMR-1.2.2/doc/release_ack.md similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/doc/release_ack.md rename to lib/wasm-micro-runtime-WAMR-1.2.2/doc/release_ack.md diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/doc/roadmap.md b/lib/wasm-micro-runtime-WAMR-1.2.2/doc/roadmap.md similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/doc/roadmap.md rename to lib/wasm-micro-runtime-WAMR-1.2.2/doc/roadmap.md diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/doc/semantic_version.md b/lib/wasm-micro-runtime-WAMR-1.2.2/doc/semantic_version.md similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/doc/semantic_version.md rename to lib/wasm-micro-runtime-WAMR-1.2.2/doc/semantic_version.md diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/doc/socket_api.md b/lib/wasm-micro-runtime-WAMR-1.2.2/doc/socket_api.md similarity index 87% rename from lib/wasm-micro-runtime-WAMR-1.1.1/doc/socket_api.md rename to lib/wasm-micro-runtime-WAMR-1.2.2/doc/socket_api.md index cdf7494c088..9e65d33cd5e 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/doc/socket_api.md +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/doc/socket_api.md @@ -4,11 +4,11 @@ sockets. A socket is an abstract representation of the local endpoint of a network communication path. -Currently, WAMR supports a limit set of all well-known functions: -`accept()`, `bind()`, `connect()`, `listen()`, `recv()`, `send()`, `shutdown()` -and `socket()`. Users can call those functions in WebAssembly code directly. -Those WebAssembly socket calls will be dispatched to the imported -functions and eventually will be implemented by host socket APIs. +Currently, WAMR supports some Socket API features: +- Support TCP and UDP +- Support IPv4 and IPv6 +- Support get/set socket options +- Support access control This document introduces a way to support the _Berkeley/POSIX Socket API_ in WebAssembly code. @@ -86,4 +86,4 @@ Similarly to running _iwasm_ outside of an enclave, the allowed address ranges a $ iwasm --addr-pool=1.2.3.4/15,2.3.4.6/16 socket_example.wasm ``` -Refer to [socket api sample](../samples/socket-api) for the compilation of the Wasm applications and [_iwasm_ for Intel SGX](../product-mini/platforms/linux-sgx) for the Wasm runtime. \ No newline at end of file +Refer to [socket api sample](../samples/socket-api) for the compilation of the Wasm applications and [_iwasm_ for Intel SGX](../product-mini/platforms/linux-sgx) for the Wasm runtime. diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/doc/source_debugging.md b/lib/wasm-micro-runtime-WAMR-1.2.2/doc/source_debugging.md similarity index 82% rename from lib/wasm-micro-runtime-WAMR-1.1.1/doc/source_debugging.md rename to lib/wasm-micro-runtime-WAMR-1.2.2/doc/source_debugging.md index a07cebc43b8..a9fa0930713 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/doc/source_debugging.md +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/doc/source_debugging.md @@ -1,5 +1,9 @@ # WAMR source debugging +References: +- [Blog: WAMR source debugging basic](https://bytecodealliance.github.io/wamr.dev/blog/wamr-source-debugging-basic/) +- [Blog: Debugging wasm with VSCode](https://bytecodealliance.github.io/wamr.dev/blog/debugging-wasm-with-vscode/) + WAMR supports source level debugging based on DWARF (normally used in C/C++/Rust), source map (normally used in AssemblyScript) is not supported. **The lldb's ability to debug wasm application is based on the patch [Add class WasmProcess for WebAssembly debugging](https://reviews.llvm.org/D78801). Thanks very much to the author @paolosev for such a great work!** @@ -28,6 +32,7 @@ mkdir build && cd build cmake .. -DWAMR_BUILD_DEBUG_INTERP=1 make ``` +> Note: On MacOS M1 environment, pass the additional `-DWAMR_DISABLE_HW_BOUND_CHECK=1` cmake configuration. 3. Execute iwasm with debug engine enabled ``` bash @@ -35,14 +40,28 @@ iwasm -g=127.0.0.1:1234 test.wasm # Use port = 0 to allow a random assigned debug port ``` -4. Build customized lldb (assume you have already cloned llvm) +4. Build customized lldb ``` bash -cd ${WAMR_ROOT}/core/deps/llvm -git apply ../../../build-scripts/lldb-wasm.patch -mkdir build-lldb && cd build-lldb -cmake -DCMAKE_BUILD_TYPE:STRING="Release" -DLLVM_ENABLE_PROJECTS="clang;lldb" -DLLVM_TARGETS_TO_BUILD:STRING="X86;WebAssembly" -DLLVM_ENABLE_LIBXML2:BOOL=ON ../llvm -make -j $(nproc) +git clone --branch release/13.x --depth=1 https://github.com/llvm/llvm-project +cd llvm-project +git apply ${WAMR_ROOT}/build-scripts/lldb-wasm.patch +mkdir build-lldb +cmake -S ./llvm -B build-lldb \ + -G Ninja \ + -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_PROJECTS="clang;lldb" \ + -DLLVM_TARGETS_TO_BUILD:STRING="X86;WebAssembly" \ + -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DLLVM_BUILD_BENCHMARKS:BOOL=OFF \ + -DLLVM_BUILD_DOCS:BOOL=OFF -DLLVM_BUILD_EXAMPLES:BOOL=OFF \ + -DLLVM_BUILD_LLVM_DYLIB:BOOL=OFF -DLLVM_BUILD_TESTS:BOOL=OFF \ + -DLLVM_ENABLE_BINDINGS:BOOL=OFF -DLLVM_INCLUDE_BENCHMARKS:BOOL=OFF \ + -DLLVM_INCLUDE_DOCS:BOOL=OFF -DLLVM_INCLUDE_EXAMPLES:BOOL=OFF \ + -DLLVM_INCLUDE_TESTS:BOOL=OFF -DLLVM_ENABLE_LIBXML2:BOOL=ON +cmake --build build-lldb --target lldb --parallel $(nproc) +# The lldb is generated under build-lldb/bin/lldb ``` +> Note: If using `CommandLineTools` on MacOS, make sure only one SDK is present in `/Library/Developer/CommandLineTools/SDKs`. + +> You can download pre-built `wamr-lldb` binaries from [here](https://github.com/bytecodealliance/wasm-micro-runtime/releases). 5. Launch customized lldb and connect to iwasm ``` bash @@ -51,8 +70,6 @@ lldb ``` Then you can use lldb commands to debug your applications. Please refer to [lldb document](https://lldb.llvm.org/use/tutorial.html) for command usage. -> Known issue: `step over` on some function may be treated as `step in`, it will be fixed later. - ## Debugging with AOT > Note: AOT debugging is experimental and only a few debugging capabilities are supported. diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/doc/wamr_api.md b/lib/wasm-micro-runtime-WAMR-1.2.2/doc/wamr_api.md similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/doc/wamr_api.md rename to lib/wasm-micro-runtime-WAMR-1.2.2/doc/wamr_api.md diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/doc/wasm_c_api.md b/lib/wasm-micro-runtime-WAMR-1.2.2/doc/wasm_c_api.md similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/doc/wasm_c_api.md rename to lib/wasm-micro-runtime-WAMR-1.2.2/doc/wasm_c_api.md diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/doc/xip.md b/lib/wasm-micro-runtime-WAMR-1.2.2/doc/xip.md similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/doc/xip.md rename to lib/wasm-micro-runtime-WAMR-1.2.2/doc/xip.md diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/go/README.md b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/go/README.md similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/go/README.md rename to lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/go/README.md diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/go/build.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/go/build.sh similarity index 74% rename from lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/go/build.sh rename to lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/go/build.sh index 1540c66409f..fe46a9a838d 100755 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/go/build.sh +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/go/build.sh @@ -7,6 +7,12 @@ PLATFORM=$(uname -s | tr A-Z a-z) CUR_DIR=$PWD WAMR_DIR=$PWD/../.. WAMR_GO_DIR=$PWD/wamr +ARCH=$(uname -m) +if [ ${ARCH} = "arm64" ]; then + ARCH="aarch64" +elif [ ${ARCH} = "x86_64" ]; then + ARCH="amd64" +fi cp -a ${WAMR_DIR}/core/iwasm/include/*.h ${WAMR_GO_DIR}/packaged/include @@ -15,7 +21,7 @@ cmake ${WAMR_DIR}/product-mini/platforms/${PLATFORM} \ -DWAMR_BUILD_LIB_PTHREAD=1 -DWAMR_BUILD_DUMP_CALL_STACK=1 \ -DWAMR_BUILD_MEMORY_PROFILING=1 make -j ${nproc} -cp -a libvmlib.a ${WAMR_GO_DIR}/packaged/lib/${PLATFORM}-amd64 +cp -a libvmlib.a ${WAMR_GO_DIR}/packaged/lib/${PLATFORM}-${ARCH} cd ${WAMR_GO_DIR} go test diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/go/go.mod b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/go/go.mod similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/go/go.mod rename to lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/go/go.mod diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/go/go.sum b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/go/go.sum similarity index 90% rename from lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/go/go.sum rename to lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/go/go.sum index b380ae44575..acb88a48f68 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/go/go.sum +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/go/go.sum @@ -5,6 +5,7 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/go/samples/build.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/go/samples/build.sh similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/go/samples/build.sh rename to lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/go/samples/build.sh diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/go/samples/run.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/go/samples/run.sh similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/go/samples/run.sh rename to lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/go/samples/run.sh diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/go/samples/test.go b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/go/samples/test.go similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/go/samples/test.go rename to lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/go/samples/test.go diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/go/samples/wasm-app/build.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/go/samples/wasm-app/build.sh similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/go/samples/wasm-app/build.sh rename to lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/go/samples/wasm-app/build.sh diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/go/samples/wasm-app/main.c b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/go/samples/wasm-app/main.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/go/samples/wasm-app/main.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/go/samples/wasm-app/main.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/go/wamr/cgo.go b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/go/wamr/cgo.go similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/go/wamr/cgo.go rename to lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/go/wamr/cgo.go diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/go/wamr/instance.go b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/go/wamr/instance.go similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/go/wamr/instance.go rename to lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/go/wamr/instance.go diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/go/wamr/instance_test.go b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/go/wamr/instance_test.go similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/go/wamr/instance_test.go rename to lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/go/wamr/instance_test.go diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/go/wamr/module.go b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/go/wamr/module.go similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/go/wamr/module.go rename to lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/go/wamr/module.go diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/go/wamr/module_test.go b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/go/wamr/module_test.go similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/go/wamr/module_test.go rename to lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/go/wamr/module_test.go diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/go/wamr/packaged/include/dummy.go b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/go/wamr/packaged/include/dummy.go similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/go/wamr/packaged/include/dummy.go rename to lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/go/wamr/packaged/include/dummy.go diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/go/wamr/packaged/lib/darwin-aarch64/dummy.go b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/go/wamr/packaged/lib/darwin-aarch64/dummy.go new file mode 100644 index 00000000000..35f3c705fc0 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/go/wamr/packaged/lib/darwin-aarch64/dummy.go @@ -0,0 +1,6 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +package darwin_aarch64 diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/go/wamr/packaged/lib/darwin-amd64/dummy.go b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/go/wamr/packaged/lib/darwin-amd64/dummy.go similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/go/wamr/packaged/lib/darwin-amd64/dummy.go rename to lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/go/wamr/packaged/lib/darwin-amd64/dummy.go diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/go/wamr/packaged/lib/dummy.go b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/go/wamr/packaged/lib/dummy.go similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/go/wamr/packaged/lib/dummy.go rename to lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/go/wamr/packaged/lib/dummy.go diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/go/wamr/packaged/lib/linux-amd64/dummy.go b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/go/wamr/packaged/lib/linux-amd64/dummy.go similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/go/wamr/packaged/lib/linux-amd64/dummy.go rename to lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/go/wamr/packaged/lib/linux-amd64/dummy.go diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/go/wamr/runtime.go b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/go/wamr/runtime.go similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/go/wamr/runtime.go rename to lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/go/wamr/runtime.go diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/go/wamr/runtime_test.go b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/go/wamr/runtime_test.go similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/go/wamr/runtime_test.go rename to lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/go/wamr/runtime_test.go diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/python/.gitignore b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/.gitignore similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/python/.gitignore rename to lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/.gitignore diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/python/LICENSE b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/LICENSE similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/python/LICENSE rename to lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/LICENSE diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/MANIFEST.in b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/MANIFEST.in new file mode 100644 index 00000000000..9b0c0893f9f --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/MANIFEST.in @@ -0,0 +1 @@ +include src/wamr/libs/* diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/README.md b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/README.md new file mode 100644 index 00000000000..ec82ee191c6 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/README.md @@ -0,0 +1,34 @@ +# wamr-python + +The WAMR Python package contains a set of high-level bindings for WAMR API and WASM-C-API. + +## Installation + +To Install from local source tree in _development mode_ run the following command, + +```bash +python -m pip install -e . +``` + +In this mode the package appears to be installed but still is editable from the source tree. + +## Usage + +From the same package you can use two set of APIs. + +To use the WAMR API you can import the symbols as follows, + +```py +from wamr.wamrapi.wamr import Engine, Module, Instance, ExecEnv +``` + +In the order hand, to use the WASM-C-API, + +```py +import wamr.wasmcapi.ffi as ffi +``` + +For more information: + +* [WAMR API](./wamr-api) +* [WASM-C-API](./wasm-c-api) diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/python/pyproject.toml b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/pyproject.toml similarity index 52% rename from lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/python/pyproject.toml rename to lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/pyproject.toml index b0f076532a0..a480ac67186 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/python/pyproject.toml +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/pyproject.toml @@ -1,3 +1,3 @@ [build-system] -requires = ["setuptools>=42"] +requires = ["setuptools>=42", "ctypesgen==1.1.1"] build-backend = "setuptools.build_meta" diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/setup.py b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/setup.py new file mode 100755 index 00000000000..fb7993e683a --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/setup.py @@ -0,0 +1,65 @@ +# -*- coding: utf-8 -*- +#!/usr/bin/env python3 +# +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# +# pylint: disable=missing-class-docstring +# pylint: disable=missing-function-docstring +# pylint: disable=missing-module-docstring + +import pathlib +from setuptools import setup, find_packages +from setuptools.command.develop import develop +from setuptools.command.install import install +from setuptools.command.egg_info import egg_info +from subprocess import check_call + + +def build_library(): + cur_path = pathlib.Path(__file__).parent + check_call(f"{cur_path}/utils/create_lib.sh".split()) + + +class PreDevelopCommand(develop): + def run(self): + build_library() + develop.run(self) + + +class PreInstallCommand(install): + def run(self): + build_library() + install.run(self) + + +class PreEggInfoCommand(egg_info): + def run(self): + build_library() + egg_info.run(self) + + +with open("README.md") as f: + readme = f.read() + +with open("LICENSE") as f: + license = f.read() + +setup( + name="wamr-python", + version="0.1.0", + description="A WebAssembly runtime powered by WAMR", + long_description=readme, + packages=find_packages(where="src"), + package_dir={"": "src"}, + author="The WAMR Project Developers", + author_email="hello@bytecodealliance.org", + url="https://github.com/bytecodealliance/wasm-micro-runtime", + license=license, + include_package_data=True, + cmdclass={ + 'develop': PreDevelopCommand, + 'install': PreInstallCommand, + 'egg_info': PreEggInfoCommand, + }, +) diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/devices/__init__.py b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/src/wamr/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/devices/__init__.py rename to lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/src/wamr/__init__.py diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/debug/linux/.placeholder b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/src/wamr/libs/.placeholder similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/debug/linux/.placeholder rename to lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/src/wamr/libs/.placeholder diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/devices/migrations/__init__.py b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/src/wamr/wamrapi/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/devices/migrations/__init__.py rename to lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/src/wamr/wamrapi/__init__.py diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/src/wamr/wamrapi/wamr.py b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/src/wamr/wamrapi/wamr.py new file mode 100644 index 00000000000..abbd23227c4 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/src/wamr/wamrapi/wamr.py @@ -0,0 +1,149 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +from ctypes import Array +from ctypes import c_char +from ctypes import c_uint +from ctypes import c_uint8 +from ctypes import c_void_p +from ctypes import cast +from ctypes import create_string_buffer +from ctypes import POINTER +from ctypes import pointer +from wamr.wamrapi.iwasm import String +from wamr.wamrapi.iwasm import Alloc_With_Pool +from wamr.wamrapi.iwasm import RuntimeInitArgs +from wamr.wamrapi.iwasm import wasm_exec_env_t +from wamr.wamrapi.iwasm import wasm_function_inst_t +from wamr.wamrapi.iwasm import wasm_module_inst_t +from wamr.wamrapi.iwasm import wasm_module_t +from wamr.wamrapi.iwasm import wasm_runtime_call_wasm +from wamr.wamrapi.iwasm import wasm_runtime_create_exec_env +from wamr.wamrapi.iwasm import wasm_runtime_deinstantiate +from wamr.wamrapi.iwasm import wasm_runtime_destroy +from wamr.wamrapi.iwasm import wasm_runtime_destroy_exec_env +from wamr.wamrapi.iwasm import wasm_runtime_full_init +from wamr.wamrapi.iwasm import wasm_runtime_instantiate +from wamr.wamrapi.iwasm import wasm_runtime_load +from wamr.wamrapi.iwasm import wasm_runtime_lookup_function +from wamr.wamrapi.iwasm import wasm_runtime_unload +from wamr.wamrapi.iwasm import wasm_runtime_module_malloc +from wamr.wamrapi.iwasm import wasm_runtime_module_free +from wamr.wamrapi.iwasm import wasm_runtime_register_natives +from wamr.wamrapi.iwasm import NativeSymbol + + +class Engine: + def __init__(self): + self._native_symbols = dict() + self.init_args = self._get_init_args() + wasm_runtime_full_init(pointer(self.init_args)) + + def __del__(self): + print("deleting Engine") + wasm_runtime_destroy() + + def _get_init_args(self, heap_size: int = 1024 * 512) -> RuntimeInitArgs: + init_args = RuntimeInitArgs() + init_args.mem_alloc_type = Alloc_With_Pool + init_args.mem_alloc_option.pool.heap_buf = cast( + (c_char * heap_size)(), c_void_p + ) + init_args.mem_alloc_option.pool.heap_size = heap_size + return init_args + + def register_natives(self, module_name: str, native_symbols: list[NativeSymbol]) -> None: + module_name = String.from_param(module_name) + # WAMR does not copy the symbols. We must store them. + for native in native_symbols: + self._native_symbols[str(native.symbol)] = (module_name, native) + + if not wasm_runtime_register_natives( + module_name, + cast( + (NativeSymbol * len(native_symbols))(*native_symbols), + POINTER(NativeSymbol) + ), + len(native_symbols) + ): + raise Exception("Error while registering symbols") + +class Module: + __create_key = object() + + @classmethod + def from_file(cls, engine: Engine, fp: str) -> "Module": + return Module(cls.__create_key, engine, fp) + + def __init__(self, create_key: object, engine: Engine, fp: str) -> None: + assert ( + create_key == Module.__create_key + ), "Module objects must be created using Module.from_file" + self.engine = engine + self.module, self.file_data = self._create_module(fp) + + def __del__(self): + print("deleting Module") + wasm_runtime_unload(self.module) + + def _create_module(self, fp: str) -> tuple[wasm_module_t, Array[c_uint]]: + with open(fp, "rb") as f: + data = f.read() + data = (c_uint8 * len(data))(*data) + + error_buf = create_string_buffer(128) + module = wasm_runtime_load(data, len(data), error_buf, len(error_buf)) + if not module: + raise Exception("Error while creating module") + return module, data + + +class Instance: + def __init__(self, module: Module, stack_size: int = 65536, heap_size: int = 16384): + self.module = module + self.module_inst = self._create_module_inst(module, stack_size, heap_size) + + def __del__(self): + print("deleting Instance") + wasm_runtime_deinstantiate(self.module_inst) + + def malloc(self, nbytes: int, native_handler) -> c_uint: + return wasm_runtime_module_malloc(self.module_inst, nbytes, native_handler) + + def free(self, wasm_handler) -> None: + wasm_runtime_module_free(self.module_inst, wasm_handler) + + def lookup_function(self, name: str) -> wasm_function_inst_t: + func = wasm_runtime_lookup_function(self.module_inst, name, None) + if not func: + raise Exception("Error while looking-up function") + return func + + def _create_module_inst(self, module: Module, stack_size: int, heap_size: int) -> wasm_module_inst_t: + error_buf = create_string_buffer(128) + module_inst = wasm_runtime_instantiate( + module.module, stack_size, heap_size, error_buf, len(error_buf) + ) + if not module_inst: + raise Exception("Error while creating module instance") + return module_inst + + +class ExecEnv: + def __init__(self, module_inst: Instance, stack_size: int = 65536): + self.module_inst = module_inst + self.exec_env = self._create_exec_env(module_inst, stack_size) + + def __del__(self): + print("deleting ExecEnv") + wasm_runtime_destroy_exec_env(self.exec_env) + + def call(self, func: wasm_function_inst_t, argc: int, argv: "POINTER[c_uint]"): + if not wasm_runtime_call_wasm(self.exec_env, func, argc, argv): + raise Exception("Error while calling function") + + def _create_exec_env(self, module_inst: Instance, stack_size: int) -> wasm_exec_env_t: + exec_env = wasm_runtime_create_exec_env(module_inst.module_inst, stack_size) + if not exec_env: + raise Exception("Error while creating execution environment") + return exec_env diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/python/wamr/__init__.py b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/src/wamr/wasmcapi/__init__.py similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/python/wamr/__init__.py rename to lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/src/wamr/wasmcapi/__init__.py diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/python/wamr/binding.py b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/src/wamr/wasmcapi/binding.py similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/python/wamr/binding.py rename to lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/src/wamr/wasmcapi/binding.py diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/python/wamr/ffi.py b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/src/wamr/wasmcapi/ffi.py similarity index 99% rename from lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/python/wamr/ffi.py rename to lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/src/wamr/wasmcapi/ffi.py index a29b607c149..18b6bc90c0d 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/python/wamr/ffi.py +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/src/wamr/wasmcapi/ffi.py @@ -36,8 +36,8 @@ if current_file.is_symlink(): current_file = Path(os.readlink(current_file)) current_dir = current_file.parent.resolve() -root_dir = current_dir.parent.parent.parent.parent.resolve() -wamr_dir = root_dir.joinpath("wasm-micro-runtime").resolve() +root_dir = current_dir.parents[4].resolve() +wamr_dir = root_dir.resolve() if not wamr_dir.exists(): raise RuntimeError(f"not found the repo of wasm-micro-runtime under {root_dir}") diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/utils/create_lib.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/utils/create_lib.sh new file mode 100755 index 00000000000..b7e10d3ee53 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/utils/create_lib.sh @@ -0,0 +1,32 @@ +#!/bin/sh + +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +CUR_DIR=$(cd $(dirname $0) && pwd -P) +ROOT_DIR=${CUR_DIR}/../../.. + +UNAME=$(uname -s|tr A-Z a-z) +WAMR_BUILD_PLATFORM=${WAMR_BUILD_PLATFORM:-${UNAME}} + +cd ${ROOT_DIR}/product-mini/platforms/${WAMR_BUILD_PLATFORM} + +mkdir -p build && cd build +cmake .. +make -j + +case ${UNAME} in +darwin) + LIBNAME=libiwasm.dylib + ;; +*) + LIBNAME=libiwasm.so + ;; +esac +cp ${LIBNAME} ${CUR_DIR}/../src/wamr/libs + +cd ${ROOT_DIR}/language-bindings/python/src/wamr/wamrapi +ctypesgen \ +${ROOT_DIR}/core/iwasm/include/wasm_export.h \ +-l ../libs/${LIBNAME} \ +-o iwasm.py diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wamr-api/README.md b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wamr-api/README.md new file mode 100644 index 00000000000..5ee672e29b7 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wamr-api/README.md @@ -0,0 +1,29 @@ +# WARM API + +## Setup + +### Pre-requisites + +Install requirements, + +``` +pip install -r requirements.txt +``` + +### Build native lib and update bindings + +The following command builds the iwasm library and generates the Python bindings, + +```sh +bash language-bindings/python/utils/create_lib.sh +``` + +This will build and copy libiwasm into the package. + +## Examples + +There is a [simple example](./samples/main.py) to show how to use bindings. + +``` +python samples/main.py +``` diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wamr-api/requirements.txt b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wamr-api/requirements.txt new file mode 100644 index 00000000000..923575a4470 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wamr-api/requirements.txt @@ -0,0 +1 @@ +ctypesgen==1.1.1 \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wamr-api/samples/compile.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wamr-api/samples/compile.sh new file mode 100644 index 00000000000..4745ef1e845 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wamr-api/samples/compile.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +/opt/wasi-sdk/bin/clang \ + -O0 -z stack-size=4096 -Wl,--initial-memory=65536 \ + -Wl,--strip-all,--no-entry -nostdlib \ + -Wl,--export=sum\ + -Wl,--allow-undefined \ + -o sum.wasm sum.c diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wamr-api/samples/main.py b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wamr-api/samples/main.py new file mode 100644 index 00000000000..525aab81061 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wamr-api/samples/main.py @@ -0,0 +1,22 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +from wamr.wamrapi.wamr import Engine, Module, Instance, ExecEnv +from ctypes import c_uint +import pathlib + +def main(): + engine = Engine() + module = Module.from_file(engine, pathlib.Path(__file__).parent / "sum.wasm") + module_inst = Instance(module) + exec_env = ExecEnv(module_inst) + + func = module_inst.lookup_function("sum") + + argv = (c_uint * 2)(*[10, 11]) + exec_env.call(func, len(argv), argv) + print(argv[0]) + + +if __name__ == "__main__": + main() diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wamr-api/samples/sum.c b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wamr-api/samples/sum.c new file mode 100644 index 00000000000..586c5bc6a58 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wamr-api/samples/sum.c @@ -0,0 +1,12 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include + +int +sum(int a, int b) +{ + return a + b; +} diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wasm-c-api/README.md b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wasm-c-api/README.md new file mode 100644 index 00000000000..1684afa5c14 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wasm-c-api/README.md @@ -0,0 +1,7 @@ +# WASM-C-API + +## Examples + +There is a [simple example](./samples/hello_procedural.py) to show how to use bindings. Actually, the python binding follows C-APIs. There it should be easy if be familiar with _programming with wasm-c-api_. + +Unit test cases under _./tests_ could be another but more complete references. diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/python/docs/design.md b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wasm-c-api/docs/design.md similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/python/docs/design.md rename to lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wasm-c-api/docs/design.md diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/python/docs/images/python_package_life_cycle.png b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wasm-c-api/docs/images/python_package_life_cycle.png similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/python/docs/images/python_package_life_cycle.png rename to lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wasm-c-api/docs/images/python_package_life_cycle.png diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/python/docs/setup_dev_env.md b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wasm-c-api/docs/setup_dev_env.md similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/python/docs/setup_dev_env.md rename to lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wasm-c-api/docs/setup_dev_env.md diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/python/requirements.txt b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wasm-c-api/requirements.txt similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/python/requirements.txt rename to lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wasm-c-api/requirements.txt diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/python/samples/hello.wat b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wasm-c-api/samples/hello.wat similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/python/samples/hello.wat rename to lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wasm-c-api/samples/hello.wat diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/python/samples/hello_oop.py b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wasm-c-api/samples/hello_oop.py similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/python/samples/hello_oop.py rename to lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wasm-c-api/samples/hello_oop.py diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/python/samples/hello_procedural.py b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wasm-c-api/samples/hello_procedural.py similarity index 98% rename from lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/python/samples/hello_procedural.py rename to lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wasm-c-api/samples/hello_procedural.py index ed3002d5b5b..5924423bd63 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/python/samples/hello_procedural.py +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wasm-c-api/samples/hello_procedural.py @@ -5,7 +5,7 @@ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception # import ctypes -import wamr.ffi as ffi +import wamr.wasmcapi.ffi as ffi WAMS_BINARY_CONTENT = ( b"\x00asm\x01\x00\x00\x00\x01\x84\x80\x80\x80\x00\x01`\x00\x00\x02\x8a\x80" diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/python/tests/__init__.py b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wasm-c-api/tests/__init__.py similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/python/tests/__init__.py rename to lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wasm-c-api/tests/__init__.py diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/python/tests/context.py b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wasm-c-api/tests/context.py similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/python/tests/context.py rename to lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wasm-c-api/tests/context.py diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/python/tests/test_advanced.py b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wasm-c-api/tests/test_advanced.py similarity index 99% rename from lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/python/tests/test_advanced.py rename to lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wasm-c-api/tests/test_advanced.py index ad074f2b3a2..2e1c285eabc 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/python/tests/test_advanced.py +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wasm-c-api/tests/test_advanced.py @@ -12,7 +12,7 @@ import math import unittest -import wamr.ffi as ffi +import wamr.wasmcapi.ffi as ffi # It is a module likes: diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/python/tests/test_basic.py b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wasm-c-api/tests/test_basic.py similarity index 99% rename from lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/python/tests/test_basic.py rename to lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wasm-c-api/tests/test_basic.py index 556162bdeb2..a2d3f2850bf 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/python/tests/test_basic.py +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wasm-c-api/tests/test_basic.py @@ -12,7 +12,7 @@ import unittest from venv import create -from wamr.ffi import * +from wamr.wasmcapi.ffi import * # It is a module likes: # (module @@ -1183,9 +1183,10 @@ def test_wasm_instance_new_pos_empty_imports(self): self._wasm_store, module, imports, create_null_pointer(wasm_trap_t) ) - wasm_instance_delete(instance) wasm_module_delete(module) + self.assertIsNullPointer(instance) + def test_wasm_instance_new_pos(self): binary = load_module_file(MODULE_BINARY) module = wasm_module_new(self._wasm_store, binary) @@ -1227,9 +1228,10 @@ def test_wasm_instance_new_neg_null_imports(self): create_null_pointer(wasm_trap_t), ) - wasm_instance_delete(instance) wasm_module_delete(module) + self.assertIsNullPointer(instance) + # test those APIs in advanced: # wasm_instance_delete # wasm_instance_exports diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/python/utils/bindgen.py b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wasm-c-api/utils/bindgen.py similarity index 98% rename from lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/python/utils/bindgen.py rename to lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wasm-c-api/utils/bindgen.py index 6371ca6576e..a505404d589 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/language-bindings/python/utils/bindgen.py +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wasm-c-api/utils/bindgen.py @@ -21,7 +21,7 @@ from pycparser import c_ast, parse_file WASM_C_API_HEADER = "core/iwasm/include/wasm_c_api.h" -BINDING_PATH = "wamr/binding.py" +BINDING_PATH = "language-bindings/python/wamr/wasmcapi/binding.py" # 4 spaces as default indent INDENT = " " @@ -314,7 +314,7 @@ def visit_Enum(self, node): def preflight_check(workspace): - wamr_repo = workspace.joinpath("wasm-micro-runtime") + wamr_repo = workspace file_check_list = [ wamr_repo.exists(), wamr_repo.joinpath(WASM_C_API_HEADER).exists(), @@ -369,12 +369,12 @@ def main(): current_file = pathlib.Path(os.readlink(current_file)) current_dir = current_file.parent.resolve() - root_dir = current_dir.joinpath("..").resolve() + root_dir = current_dir.joinpath("../../../..").resolve() if not preflight_check(root_dir): return False - wamr_repo = root_dir.joinpath("wasm-micro-runtime") + wamr_repo = root_dir binding_file_path = root_dir.joinpath(BINDING_PATH) with open(binding_file_path, "wt", encoding="utf-8") as binding_file: binding_file.write(do_parse(wamr_repo)) diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/README.md b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/README.md new file mode 100644 index 00000000000..5847b246853 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/README.md @@ -0,0 +1,455 @@ +# Build iwasm + +iwasm is the executable binary built with WAMR VMcore supports WASI and command line interface. Refer to [**how to build wamr vmcore**](../doc/build_wamr.md) for all the supported CMAKE compilation variables. + +If you are building for ARM architecture on a X86 development machine, you can use the `CMAKE_TOOLCHAIN_FILE` to set the toolchain file for cross compling. + +``` +cmake .. -DCMAKE_TOOLCHAIN_FILE=$TOOL_CHAIN_FILE \ + -DWAMR_BUILD_PLATFORM=linux \ + -DWAMR_BUILD_TARGET=ARM +``` + +Refer to toolchain sample file [`samples/simple/profiles/arm-interp/toolchain.cmake`](../samples/simple/profiles/arm-interp/toolchain.cmake) for how to build mini product for ARM target architecture. + +If you compile for ESP-IDF, make sure to set the right toolchain file for the chip you're using (e.g. `$IDF_PATH/tools/cmake/toolchain-esp32c3.cmake`). +Note that all ESP-IDF toolchain files live under `$IDF_PATH/tools/cmake/`. + +## Linux + +First of all please install the dependent packages. +Run command below in Ubuntu-22.04: +``` Bash +sudo apt install build-essential cmake g++-multilib libgcc-11-dev lib32gcc-11-dev ccache +``` +Or in Ubuntu-20.04 +``` Bash +sudo apt install build-essential cmake g++-multilib libgcc-9-dev lib32gcc-9-dev ccache +``` +Or in Ubuntu-18.04: +``` Bash +sudo apt install build-essential cmake g++-multilib libgcc-8-dev lib32gcc-8-dev ccache +``` +Or in Fedora: +``` Bash +sudo dnf install glibc-devel.i686 +``` + +After installing dependencies, build the source code: +``` Bash +cd product-mini/platforms/linux/ +mkdir build && cd build +cmake .. +make +# iwasm is generated under current directory +``` + +By default in Linux, the `fast interpreter`, `AOT` and `Libc WASI` are enabled, and JIT is disabled. +And the build target is set to X86_64 or X86_32 depending on the platform's bitwidth. + +There are total 6 running modes supported: fast interpreter, classi interpreter, AOT, LLVM JIT, Fast JIT and Multi-tier JIT. + +(1) To run a wasm file with `fast interpreter` mode - build iwasm with default build and then: +```Bash +iwasm +``` +Or +```Bash +mkdir build && cd build +cmake .. -DWAMR_BUILD_INTERP=1 +make +``` + +(2) To disable `fast interpreter` and enable `classic interpreter` instead: +``` Bash +mkdir build && cd build +cmake .. -DWAMR_BUILD_FAST_INTERP=0 +make +``` + +(3) To run an AOT file, firstly please refer to [Build wamrc AOT compiler](../wamr-compiler/README.md) to build wamrc, and then: +```Bash +wamrc -o +iwasm +``` + +(4) To enable the `LLVM JIT` mode, firstly we should build the LLVM library: +``` Bash +cd product-mini/platforms/linux/ +./build_llvm.sh (The llvm source code is cloned under /core/deps/llvm and auto built) +``` + +Then pass argument `-DWAMR_BUILD_JIT=1` to cmake to enable LLVM JIT: +``` Bash +mkdir build && cd build +cmake .. -DWAMR_BUILD_JIT=1 +make +``` + +Note: +By default, the LLVM Orc JIT with Lazy compilation is enabled to speedup the lanuching process and reduce +the JIT compilation time by creating backend threads to compile the WASM functions parallely, and for the +main thread, the functions in the module will not be compiled until they are firstly called and haven't been +compiled by the compilation threads. + +If developer wants to disable the Lazy compilation, we can: +``` Bash +mkdir build && cd build +cmake .. -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=0 +make +``` +In which all the WASM functions will be previously compiled before main thread starts to run the wasm module. + +(5) To enable the `Fast JIT` mode: +``` Bash +mkdir build && cd build +cmake .. -DWAMR_BUILD_FAST_JIT=1 +make +``` +The Fast JIT is a lightweight JIT engine with quick startup, small footprint and good portability, and gains ~50% performance of AOT. + +(6) To enable the `Multi-tier JIT` mode: +``` Bash +mkdir build && cd build +cmake .. -DWAMR_BUILD_FAST_JTI=1 -DWAMR_BUILD_JIT=1 +make +``` +The Multi-tier JIT is a two level JIT tier-up engine, which launchs Fast JIT to run the wasm module as soon as possible and creates backend threads to compile the LLVM JIT functions at the same time, and when the LLVM JIT functions are compiled, the runtime will switch the extecution from the Fast JIT jitted code to LLVM JIT jitted code gradually, so as to gain the best performance. + +## Linux SGX (Intel Software Guard Extension) + + +Please see [Build and Port WAMR vmcore for Linux SGX](../doc/linux_sgx.md) for the details. + +## MacOS + + +Make sure to install Xcode from App Store firstly, and install cmake. + +If you use Homebrew, install cmake from the command line: +``` Bash +brew install cmake +``` + +Then build the source codes: +``` Bash +cd product-mini/platforms/darwin/ +mkdir build +cd build +cmake .. +make +# iwasm is generated under current directory +``` +By default in MacOS, the `fast interpreter`, `AOT` and `Libc WASI` are enabled, and JIT is disabled. +And the build target is set to X86_64 or X86_32 depending on the platform's bitwidth. + +To run a wasm file with interpreter mode: +```Bash +iwasm +``` +To run an AOT file, firstly please refer to [Build wamrc AOT compiler](../wamr-compiler/README.md) to build wamrc, and then: +```Bash +wamrc -o +iwasm +``` +Note: +For how to build the `JIT` mode and `classic interpreter` mode, please refer to [Build iwasm on Linux](../doc/build_wamr.md#linux). + +WAMR provides some features which can be easily configured by passing options to cmake, please see [WAMR vmcore cmake building configurations](../doc/build_wamr.md#wamr-vmcore-cmake-building-configurations) for details. Currently in MacOS, interpreter, AOT, and builtin libc are enabled by default. + +## Windows + + +Make sure `MSVC` and `cmake` are installed and available in the command line environment + +Then build the source codes: +``` Bash +cd product-mini/platforms/windows/ +mkdir build +cd build +cmake .. +cmake --build . --config Release +# ./Release/iwasm.exe is generated +``` + +By default in Windows, the `fast interpreter`, `AOT` and `Libc WASI` are enabled, and JIT is disabled. + +To run a wasm file with interpreter mode: +```Bash +iwasm.exe +``` +To run an AOT file, firstly please refer to [Build wamrc AOT compiler](../wamr-compiler/README.md) to build wamrc, and then: +```Bash +wamrc.exe -o +iwasm.exe +``` +Note: +For how to build the `JIT` mode and `classic interpreter` mode, please refer to [Build iwasm on Linux](../doc/build_wamr.md#linux). + +WAMR provides some features which can be easily configured by passing options to cmake, please see [WAMR vmcore cmake building configurations](../doc/build_wamr.md#wamr-vmcore-cmake-building-configurations) for details. Currently in Windows, interpreter, AOT, and builtin libc are enabled by default. + +## MinGW + + +First make sure the correct CMake package is installed; the following commands +are valid for the MSYS2 build environment: + +```Bash +pacman -R cmake +pacman -S mingw-w64-x86_64-cmake +pacman -S mingw-w64-x86_64-gcc +pacman -S make git +``` + +Then follow the build instructions for Windows above, and add the following +arguments for cmake: + +```Bash +cmake .. -G"Unix Makefiles" \ + -DWAMR_DISABLE_HW_BOUND_CHECK=1 +```` + +Note that WASI will be disabled until further work is done towards full MinGW support. + +- Since memory access boundary check with hardware trap feature is disabled, when generating the AOT file with `wamrc`, the `--bounds-checks=1` flag should be added to generate the memory access boundary check instructions to ensure the sandbox security: +```bash +wamrc --bounds-checks=1 -o +``` +- Compiler complaining about missing `UnwindInfoAddress` field in `RUNTIME_FUNCTION` +struct (winnt.h). + + +## VxWorks + +VxWorks 7 SR0620 release is validated. + +First you need to build a VSB. Make sure *UTILS_UNIX* layer is added in the VSB. +After the VSB is built, export the VxWorks toolchain path by: +```bash +export /host/vx-compiler/bin:$PATH +``` +Now switch to iwasm source tree to build the source code: +```bash +cd product-mini/platforms/vxworks/ +mkdir build +cd build +cmake .. +make +``` +Create a VIP based on the VSB. Make sure the following components are added: +* INCLUDE_POSIX_PTHREADS +* INCLUDE_POSIX_PTHREAD_SCHEDULER +* INCLUDE_SHARED_DATA +* INCLUDE_SHL + +Copy the generated iwasm executable, the test WASM binary as well as the needed +shared libraries (libc.so.1, libllvm.so.1 or libgnu.so.1 depending on the VSB, +libunix.so.1) to a supported file system (eg: romfs). + +Note: +WAMR provides some features which can be easily configured by passing options to cmake, please see [WAMR vmcore cmake building configurations](../doc/build_wamr.md#wamr-vmcore-cmake-building-configurations) for details. Currently in VxWorks, interpreter and builtin libc are enabled by default. + +## Zephyr + +You need to prepare Zephyr first as described [here](https://docs.zephyrproject.org/latest/getting_started/index.html#get-zephyr-and-install-python-dependencies). + +After that you need to point the `ZEPHYR_BASE` variable to e.g. `~/zephyrproject/zephyr`. Also, it is important that you have `west` available for subsequent actions. + +``` Bash +cd /product-mini/platforms/zephyr/simple +# Execute the ./build_and_run.sh script with board name as parameter. Here take x86 as example: +./build_and_run.sh x86 +``` + +The [Zephyr SDK](https://github.com/zephyrproject-rtos/sdk-ng) provides toolchains for all supported targets. Follow the instructions in the [documentation](https://docs.zephyrproject.org/latest/develop/getting_started/index.html#install-zephyr-sdk) to ensure it is installed and configured correctly. + +Note: +WAMR provides some features which can be easily configured by passing options to cmake, please see [WAMR vmcore cmake building configurations](../doc/build_wamr.md#wamr-vmcore-cmake-building-configurations) for details. Currently in Zephyr, interpreter, AOT and builtin libc are enabled by default. + + +## RT-Thread + + +1. Get rt-thread [system codes](https://github.com/RT-Thread/rt-thread). + +2. Enable WAMR software package with menuconfig tool which provided by RT-Thread. + + * Environment in Linux, run command below: + + ```bash + scons --menuconfig + ``` + + * Environment in Windows ConEmu, run command below: + + ```bash + menuconfig + ``` + + Select and enable `WAMR` in: + + * RT-Thread online packages + * tools packages + * WebAssembly Micro Runtime (WAMR) + +3. Configure `WAMR` with menuconfig tool. + + you can choice features of iwasm below: + + * Enable testing parameters of iwasm + * Enable interpreter Mode / Fast interpreter Mode + * Use built-libc + * Enable AOT + +4. Exit menuconfig tool and save configure, update and download package. + + ```bash + pkgs --update + ``` + +5. build project and download the binary to boards. + + ```bash + scons + ``` + + or build project with 8-thread by using command below: + + ```bash + scons -j8 + ``` + + after project building, you can got an binary file named `rtthread.bin`, then you can download this file to the MCU board. + +## Android + +able to generate a shared library support Android platform. +- need an [android SDK](https://developer.android.com/studio). Go and get the "Command line tools only" +- look for a command named *sdkmanager* and download below components. version numbers might need to check and pick others + - "build-tools;29.0.3" + - "cmake;3.10.2.4988404" + - "ndk;latest" + - "patcher;v4" + - "platform-tools" + - "platforms;android-29" +- add bin/ of the downloaded cmake to $PATH +- export ANDROID_HOME=/the/path/of/downloaded/sdk/ +- export ANDROID_NDK_LATEST_HOME=/the/path/of/downloaded/sdk/ndk/2x.xxx/ +- ready to go + +Use such commands, you are able to compile with default configurations. Any compiling requirement should be satisfied by modifying product-mini/platforms/android/CMakeList.txt. For example, chaning ${WAMR_BUILD_TARGET} in CMakeList could get different libraries support different ABIs. + +``` shell +$ cd product-mini/platforms/android/ +$ mkdir build +$ cd build +$ cmake .. +$ make +$ # check output in distribution/wasm +$ # include/ includes all necesary head files +$ # lib includes libiwasm.so +``` + +## NuttX + +WAMR is intergrated with NuttX, just enable the WAMR in Kconfig option (Application Configuration/Interpreters). + +## ESP-IDF + +WAMR integrates with ESP-IDF both for the XTENSA and RISC-V chips (esp32x and esp32c3 respectively). + +In order to use this, you need at least version 4.3.1 of ESP-IDF. +If you don't have it installed, follow the instructions [here](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/#get-started-get-prerequisites). +ESP-IDF also installs the toolchains needed for compiling WAMR and ESP-IDF. +A small demonstration of how to use WAMR and ESP-IDF can be found under [product_mini](./platforms/esp-idf). +The demo builds WAMR for ESP-IDF and runs a small wasm program. +In order to run it for your specific Espressif chip, edit the [build_and_run.sh](./platforms/esp-idf/build_and_run.sh) file and put the correct toolchain file (see #Cross-compilation) and `IDF_TARGET`. +Before compiling it is also necessary to call ESP-IDF's `export.sh` script to bring all compile time relevant information in scope. + +## Docker + +[Docker](https://www.docker.com/) will download all the dependencies and build WAMR Core on your behalf. + +Make sure you have Docker installed on your machine: [macOS](https://docs.docker.com/docker-for-mac/install/), [Windows](https://docs.docker.com/docker-for-windows/install/) or [Linux](https://docs.docker.com/install/linux/docker-ce/ubuntu/). + +Build *iwasm* with the Docker image: + +``` Bash +$ cd ci +$ ./build_wamr.sh +$ ls ../build_out/ +``` + +*build_wamr.sh* will generate *linux* compatible libraries ( libiwasm.so and +libvmlib.a ) and an executable binary (*iwasm*) and copy *iwasm* to +*build_out*. All original generated files are still under +*product-mini/platforms/linux/build*. + +## FreeBSD + +First, install the dependent packages: +```shell +sudo pkg install gcc cmake wget +``` + +Then you can run the following commands to build iwasm with default configurations: +```shell +cd product-mini/platforms/freebsd +mkdir build && cd build +cmake .. +make +``` + + +## AliOS-Things + +1. a developerkit board id needed for testing +2. download the AliOS-Things code + ``` Bash + git clone https://github.com/alibaba/AliOS-Things.git + ``` +3. copy /product-mini/platforms/alios-things directory to AliOS-Things/middleware, and rename it as iwasm + ``` Bash + cp -a /product-mini/platforms/alios-things middleware/iwasm + ``` +4. create a link to in middleware/iwasm/ and rename it to wamr + ``` Bash + ln -s middleware/iwasm/wamr + ``` +5. modify file app/example/helloworld/helloworld.c, patch as: + ``` C + #include + #include + extern bool iwasm_init(); + int application_start(int argc, char *argv[]) + { + int count = 0; + iwasm_init(); + ... + } + ``` +6. modify file app/example/helloworld/aos.mk + ``` C + $(NAME)_COMPONENTS := osal_aos iwasm + ``` +7. build source code and run + For linux host: + + ``` Bash + aos make helloworld@linuxhost -c config + aos make + ./out/helloworld@linuxhost/binary/helloworld@linuxhost.elf + ``` + + For developerkit: + Modify file middleware/iwasm/aos.mk, patch as: + + ``` C + WAMR_BUILD_TARGET := THUMBV7M + ``` + + ``` Bash + aos make helloworld@developerkit -c config + aos make + ``` + download the binary to developerkit board, check the output from serial port diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/app-samples/hello-world-cmake/CMakeLists.txt b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/app-samples/hello-world-cmake/CMakeLists.txt similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/app-samples/hello-world-cmake/CMakeLists.txt rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/app-samples/hello-world-cmake/CMakeLists.txt diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/app-samples/hello-world-cmake/build.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/app-samples/hello-world-cmake/build.sh similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/app-samples/hello-world-cmake/build.sh rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/app-samples/hello-world-cmake/build.sh diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/app-samples/hello-world-cmake/main.c b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/app-samples/hello-world-cmake/main.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/app-samples/hello-world-cmake/main.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/app-samples/hello-world-cmake/main.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/app-samples/hello-world-cmake/print.c b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/app-samples/hello-world-cmake/print.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/app-samples/hello-world-cmake/print.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/app-samples/hello-world-cmake/print.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/app-samples/hello-world/build.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/app-samples/hello-world/build.sh similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/app-samples/hello-world/build.sh rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/app-samples/hello-world/build.sh diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/app-samples/hello-world/main.c b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/app-samples/hello-world/main.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/app-samples/hello-world/main.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/app-samples/hello-world/main.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/alios-things/aos.mk b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/alios-things/aos.mk similarity index 91% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/alios-things/aos.mk rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/alios-things/aos.mk index 68c433664d9..383e0b23970 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/alios-things/aos.mk +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/alios-things/aos.mk @@ -50,6 +50,18 @@ WAMR_BUILD_INTERP = 1 # Enable AOT by default. WAMR_BUILD_AOT = 1 +# Override the global heap usage +ifndef WAMR_BUILD_GLOBAL_HEAP_POOL +WAMR_BUILD_GLOBAL_HEAP_POOL=1 +endif +GLOBAL_DEFINES += WASM_ENABLE_GLOBAL_HEAP_POOL=${WAMR_BUILD_GLOBAL_HEAP_POOL} + +# Override the global heap size for small devices +ifndef WAMR_BUILD_GLOBAL_HEAP_SIZE +WAMR_BUILD_GLOBAL_HEAP_SIZE = 262144 # 256 kB +endif +GLOBAL_DEFINES += WASM_GLOBAL_HEAP_SIZE=${WAMR_BUILD_GLOBAL_HEAP_SIZE} + ifeq (${WAMR_BUILD_INTERP}, 1) GLOBAL_DEFINES += WASM_ENABLE_INTERP=1 endif diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/alios-things/src/main.c b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/alios-things/src/main.c similarity index 92% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/alios-things/src/main.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/alios-things/src/main.c index 6393e2e4a2a..f2c6f85c165 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/alios-things/src/main.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/alios-things/src/main.c @@ -38,7 +38,9 @@ app_instance_main(wasm_module_inst_t module_inst) return NULL; } -static char global_heap_buf[256 * 1024] = { 0 }; +#if WASM_ENABLE_GLOBAL_HEAP_POOL != 0 +static char global_heap_buf[WASM_GLOBAL_HEAP_SIZE] = { 0 }; +#endif void iwasm_main(void *arg1) @@ -57,9 +59,13 @@ iwasm_main(void *arg1) memset(&init_args, 0, sizeof(RuntimeInitArgs)); +#if WASM_ENABLE_GLOBAL_HEAP_POOL != 0 init_args.mem_alloc_type = Alloc_With_Pool; init_args.mem_alloc_option.pool.heap_buf = global_heap_buf; init_args.mem_alloc_option.pool.heap_size = sizeof(global_heap_buf); +#else +#error Another memory allocation scheme than global heap pool is not implemented yet for Alios. +#endif /* initialize runtime environment */ if (!wasm_runtime_full_init(&init_args)) { diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/alios-things/src/test_wasm.h b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/alios-things/src/test_wasm.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/alios-things/src/test_wasm.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/alios-things/src/test_wasm.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/android/CMakeLists.txt b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/android/CMakeLists.txt similarity index 98% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/android/CMakeLists.txt rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/android/CMakeLists.txt index a65b180898f..638b6ab0dfe 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/android/CMakeLists.txt +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/android/CMakeLists.txt @@ -23,7 +23,8 @@ set (WAMR_BUILD_PLATFORM "android") set (WAMR_BUILD_TARGET "X86_32") set (WAMR_BUILD_TYPE Release) set (WAMR_BUILD_INTERP 1) -set (WAMR_BUILD_AOT 0) +set (WAMR_BUILD_AOT 1) +set (WAMR_BUILD_JIT 0) set (WAMR_BUILD_LIBC_BUILTIN 1) set (WAMR_BUILD_LIBC_WASI 1) diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/android/build_jit.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/android/build_jit.sh similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/android/build_jit.sh rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/android/build_jit.sh diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/android/build_llvm.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/android/build_llvm.sh similarity index 71% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/android/build_llvm.sh rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/android/build_llvm.sh index 3ef343f9829..145e2dbaa02 100755 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/android/build_llvm.sh +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/android/build_llvm.sh @@ -3,4 +3,5 @@ # Copyright (C) 2020 Intel Corporation. All rights reserved. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +/usr/bin/env python3 -m pip install --user -r ../../../build-scripts/requirements.txt /usr/bin/env python3 ../../../build-scripts/build_llvm.py --platform android "$@" diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/android/wasm-jni.cpp b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/android/wasm-jni.cpp similarity index 97% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/android/wasm-jni.cpp rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/android/wasm-jni.cpp index 48ce6186f9f..c2eff3a8bfb 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/android/wasm-jni.cpp +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/android/wasm-jni.cpp @@ -70,10 +70,14 @@ Java_com_intel_wasm_api_Runtime_run(JNIEnv *env, jclass thiz) memset(&init_args, 0, sizeof(RuntimeInitArgs)); +#if WASM_ENABLE_GLOBAL_HEAP_POOL == 0 init_args.mem_alloc_type = Alloc_With_Allocator; init_args.mem_alloc_option.allocator.malloc_func = (void *)malloc; init_args.mem_alloc_option.allocator.realloc_func = (void *)realloc; init_args.mem_alloc_option.allocator.free_func = (void *)free; +#else +#error The usage of a global heap pool is not implemented yet for Android. +#endif LOGI("wasm_runtime_full_init"); /* initialize runtime environment */ diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/darwin/CMakeLists.txt b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/darwin/CMakeLists.txt similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/darwin/CMakeLists.txt rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/darwin/CMakeLists.txt diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/darwin/build_jit.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/darwin/build_jit.sh similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/darwin/build_jit.sh rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/darwin/build_jit.sh diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/darwin/build_llvm.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/darwin/build_llvm.sh similarity index 71% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/darwin/build_llvm.sh rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/darwin/build_llvm.sh index 1cb00425a14..b8a9761f85e 100755 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/darwin/build_llvm.sh +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/darwin/build_llvm.sh @@ -3,4 +3,5 @@ # Copyright (C) 2020 Intel Corporation. All rights reserved. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +/usr/bin/env python3 -m pip install --user -r ../../../build-scripts/requirements.txt /usr/bin/env python3 ../../../build-scripts/build_llvm.py --platform darwin "$@" diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/darwin/main.c b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/darwin/main.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/darwin/main.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/darwin/main.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/esp-idf/.gitignore b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/esp-idf/.gitignore similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/esp-idf/.gitignore rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/esp-idf/.gitignore diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/esp-idf/CMakeLists.txt b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/esp-idf/CMakeLists.txt similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/esp-idf/CMakeLists.txt rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/esp-idf/CMakeLists.txt diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/esp-idf/build_and_run.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/esp-idf/build_and_run.sh similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/esp-idf/build_and_run.sh rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/esp-idf/build_and_run.sh diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/esp-idf/main/CMakeLists.txt b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/esp-idf/main/CMakeLists.txt similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/esp-idf/main/CMakeLists.txt rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/esp-idf/main/CMakeLists.txt diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/esp-idf/main/main.c b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/esp-idf/main/main.c similarity index 97% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/esp-idf/main/main.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/esp-idf/main/main.c index d13295d8346..417fad561bf 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/esp-idf/main/main.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/esp-idf/main/main.c @@ -40,10 +40,14 @@ iwasm_main(void *arg) /* configure memory allocation */ memset(&init_args, 0, sizeof(RuntimeInitArgs)); +#if WASM_ENABLE_GLOBAL_HEAP_POOL == 0 init_args.mem_alloc_type = Alloc_With_Allocator; init_args.mem_alloc_option.allocator.malloc_func = (void *)os_malloc; init_args.mem_alloc_option.allocator.realloc_func = (void *)os_realloc; init_args.mem_alloc_option.allocator.free_func = (void *)os_free; +#else +#error The usage of a global heap pool is not implemented yet for esp-idf. +#endif ESP_LOGI(LOG_TAG, "Initialize WASM runtime"); /* initialize runtime environment */ diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/esp-idf/main/test_wasm.h b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/esp-idf/main/test_wasm.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/esp-idf/main/test_wasm.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/esp-idf/main/test_wasm.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/esp-idf/sdkconfig.defaults b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/esp-idf/sdkconfig.defaults similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/esp-idf/sdkconfig.defaults rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/esp-idf/sdkconfig.defaults diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/esp-idf/sdkconfig.defaults.esp32 b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/esp-idf/sdkconfig.defaults.esp32 similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/esp-idf/sdkconfig.defaults.esp32 rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/esp-idf/sdkconfig.defaults.esp32 diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/esp-idf/sdkconfig.defaults.esp32c3 b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/esp-idf/sdkconfig.defaults.esp32c3 similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/esp-idf/sdkconfig.defaults.esp32c3 rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/esp-idf/sdkconfig.defaults.esp32c3 diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/freebsd/CMakeLists.txt b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/freebsd/CMakeLists.txt new file mode 100644 index 00000000000..fee2934c017 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/freebsd/CMakeLists.txt @@ -0,0 +1,132 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required (VERSION 2.9) + +project (iwasm) + +set (WAMR_BUILD_PLATFORM "freebsd") + +# Reset default linker flags +set (CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") +set (CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") + +# Set WAMR_BUILD_TARGET, currently values supported: +# "X86_64", "AMD_64", "X86_32", "AARCH64[sub]", "ARM[sub]", "THUMB[sub]", +# "MIPS", "XTENSA", "RISCV64[sub]", "RISCV32[sub]" +if (NOT DEFINED WAMR_BUILD_TARGET) + if (CMAKE_SYSTEM_PROCESSOR MATCHES "^(arm64|aarch64)") + set (WAMR_BUILD_TARGET "AARCH64") + elseif (CMAKE_SYSTEM_PROCESSOR STREQUAL "riscv64") + set (WAMR_BUILD_TARGET "RISCV64") + elseif (CMAKE_SIZEOF_VOID_P EQUAL 8) + # Build as X86_64 by default in 64-bit platform + set (WAMR_BUILD_TARGET "X86_64") + elseif (CMAKE_SIZEOF_VOID_P EQUAL 4) + # Build as X86_32 by default in 32-bit platform + set (WAMR_BUILD_TARGET "X86_32") + else () + message(SEND_ERROR "Unsupported build target platform!") + endif () +endif () + +if (NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Release) +endif () + +set(CMAKE_CXX_STANDARD 14) + +if (NOT DEFINED WAMR_BUILD_INTERP) + # Enable Interpreter by default + set (WAMR_BUILD_INTERP 1) +endif () + +if (NOT DEFINED WAMR_BUILD_AOT) + # Enable AOT by default. + set (WAMR_BUILD_AOT 1) +endif () + +if (NOT DEFINED WAMR_BUILD_JIT) + # Disable JIT by default. + set (WAMR_BUILD_JIT 0) +endif () + +if (NOT DEFINED WAMR_BUILD_FAST_JIT) + # Disable Fast JIT by default + set (WAMR_BUILD_FAST_JIT 0) +endif () + +if (NOT DEFINED WAMR_BUILD_LIBC_BUILTIN) + # Enable libc builtin support by default + set (WAMR_BUILD_LIBC_BUILTIN 1) +endif () + +if (NOT DEFINED WAMR_BUILD_LIBC_WASI) + # Enable libc wasi support by default + set (WAMR_BUILD_LIBC_WASI 1) +endif () + +if (NOT DEFINED WAMR_BUILD_FAST_INTERP) + # Enable fast interpreter + set (WAMR_BUILD_FAST_INTERP 1) +endif () + +if (NOT DEFINED WAMR_BUILD_MULTI_MODULE) + # Disable multiple module by default + set (WAMR_BUILD_MULTI_MODULE 0) +endif () + +if (NOT DEFINED WAMR_BUILD_LIB_PTHREAD) + # Disable pthread library by default + set (WAMR_BUILD_LIB_PTHREAD 0) +endif () + +if (NOT DEFINED WAMR_BUILD_MINI_LOADER) + # Disable wasm mini loader by default + set (WAMR_BUILD_MINI_LOADER 0) +endif () + +if (NOT DEFINED WAMR_BUILD_SIMD) + # Enable SIMD by default + set (WAMR_BUILD_SIMD 1) +endif () + +if (NOT DEFINED WAMR_BUILD_DEBUG_INTERP) + # Disable Debug feature by default + set (WAMR_BUILD_DEBUG_INTERP 0) +endif () + +if (WAMR_BUILD_DEBUG_INTERP EQUAL 1) + set (WAMR_BUILD_FAST_INTERP 0) + set (WAMR_BUILD_MINI_LOADER 0) + set (WAMR_BUILD_SIMD 0) +endif () + +set (WAMR_DISABLE_HW_BOUND_CHECK 1) + +set (CMAKE_SHARED_LINKER_FLAGS "-Wl") +set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}") + +set (CMAKE_MACOSX_RPATH True) + +set (WAMR_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../..) + +include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake) +add_library(vmlib ${WAMR_RUNTIME_LIB_SOURCE}) + +include (${SHARED_DIR}/utils/uncommon/shared_uncommon.cmake) + +add_executable (iwasm main.c ${UNCOMMON_SHARED_SOURCE}) + +install (TARGETS iwasm DESTINATION bin) + +target_link_libraries (iwasm vmlib ${LLVM_AVAILABLE_LIBS} ${UV_A_LIBS} -lm -ldl -lpthread) + +add_library (libiwasm SHARED ${WAMR_RUNTIME_LIB_SOURCE}) + +install (TARGETS libiwasm DESTINATION lib) + +set_target_properties (libiwasm PROPERTIES OUTPUT_NAME iwasm) + +target_link_libraries (libiwasm ${LLVM_AVAILABLE_LIBS} ${UV_A_LIBS} -lm -ldl -lpthread) + diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/freebsd/build_jit.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/freebsd/build_jit.sh new file mode 100755 index 00000000000..e6bee753c21 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/freebsd/build_jit.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +rm -fr build && mkdir build +cd build +cmake .. -DWAMR_BUILD_JIT=1 +nproc=$(sysctl -n hw.ncpu) +make -j ${nproc} +cd .. diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/linux/build_llvm.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/freebsd/build_llvm.sh similarity index 69% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/linux/build_llvm.sh rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/freebsd/build_llvm.sh index 47387a3c325..c5666b7f5d4 100755 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/linux/build_llvm.sh +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/freebsd/build_llvm.sh @@ -3,4 +3,5 @@ # Copyright (C) 2020 Intel Corporation. All rights reserved. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +/usr/bin/env python3 -m pip install --user -r ../../../build-scripts/requirements.txt /usr/bin/env python3 ../../../build-scripts/build_llvm.py "$@" diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/linux/main.c b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/freebsd/main.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/linux/main.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/freebsd/main.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/ios/CMakeLists.txt b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/ios/CMakeLists.txt similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/ios/CMakeLists.txt rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/ios/CMakeLists.txt diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/ios/generate_xcodeproj.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/ios/generate_xcodeproj.sh similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/ios/generate_xcodeproj.sh rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/ios/generate_xcodeproj.sh diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/linux-sgx/CMakeLists.txt b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/linux-sgx/CMakeLists.txt similarity index 65% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/linux-sgx/CMakeLists.txt rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/linux-sgx/CMakeLists.txt index a0ca1abe047..e1cbe2cc794 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/linux-sgx/CMakeLists.txt +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/linux-sgx/CMakeLists.txt @@ -89,10 +89,6 @@ if (NOT DEFINED WAMR_BUILD_SGX_IPFS) set (WAMR_BUILD_SGX_IPFS 0) endif () -if (COLLECT_CODE_COVERAGE EQUAL 1) - set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage") -endif () - set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu11 -ffunction-sections -fdata-sections \ -Wall -Wno-unused-parameter -Wno-pedantic \ @@ -111,34 +107,43 @@ add_custom_command ( add_custom_target (vmlib_untrusted ALL DEPENDS libvmlib_untrusted.a) +if (DEFINED WAMR_BUILD_GLOBAL_HEAP_POOL) + execute_process( + COMMAND bash -c "sed -i -E 's/^WAMR_BUILD_GLOBAL_HEAP_POOL = .*/WAMR_BUILD_GLOBAL_HEAP_POOL = ${WAMR_BUILD_GLOBAL_HEAP_POOL}/g' ${CMAKE_CURRENT_SOURCE_DIR}/enclave-sample/Makefile" + OUTPUT_VARIABLE cmdOutput + ) + if (DEFINED WAMR_BUILD_GLOBAL_HEAP_SIZE) + execute_process( + COMMAND bash -c "sed -i -E 's/^WAMR_BUILD_GLOBAL_HEAP_SIZE = .*/WAMR_BUILD_GLOBAL_HEAP_SIZE = ${WAMR_BUILD_GLOBAL_HEAP_SIZE}/g' ${CMAKE_CURRENT_SOURCE_DIR}/enclave-sample/Makefile" + OUTPUT_VARIABLE cmdOutput + ) + endif() +endif() + if (WAMR_BUILD_LIB_RATS EQUAL 1) execute_process( - COMMAND bash -c "sed -i -E 's/^#define LIB_RATS 0 /#define LIB_RATS 1/g' ${CMAKE_CURRENT_SOURCE_DIR}/enclave-sample/Enclave/Enclave.edl" + COMMAND bash -c "sed -i -E 's/^#define WASM_ENABLE_LIB_RATS 0/#define WASM_ENABLE_LIB_RATS 1/g' ${CMAKE_CURRENT_SOURCE_DIR}/enclave-sample/Enclave/Enclave.edl" + COMMAND bash -c "sed -i -E 's/^WAMR_BUILD_LIB_RATS = 0/WAMR_BUILD_LIB_RATS = 1/g' ${CMAKE_CURRENT_SOURCE_DIR}/enclave-sample/Makefile" OUTPUT_VARIABLE cmdOutput ) else() execute_process( - COMMAND bash -c "sed -i -E 's/^#define LIB_RATS 1/#define LIB_RATS 0/g' ${CMAKE_CURRENT_SOURCE_DIR}/enclave-sample/Enclave/Enclave.edl" + COMMAND bash -c "sed -i -E 's/^#define WASM_ENABLE_LIB_RATS 1/#define WASM_ENABLE_LIB_RATS 0/g' ${CMAKE_CURRENT_SOURCE_DIR}/enclave-sample/Enclave/Enclave.edl" + COMMAND bash -c "sed -i -E 's/^WAMR_BUILD_LIB_RATS = 1/WAMR_BUILD_LIB_RATS = 0/g' ${CMAKE_CURRENT_SOURCE_DIR}/enclave-sample/Makefile" OUTPUT_VARIABLE cmdOutput ) endif() if (WAMR_BUILD_SGX_IPFS EQUAL 1) execute_process( - COMMAND bash -c "sed -i -E 's/^#define SGX_IPFS 0/#define SGX_IPFS 1/g' ${CMAKE_CURRENT_SOURCE_DIR}/enclave-sample/Enclave/Enclave.edl" - OUTPUT_VARIABLE cmdOutput - ) - execute_process( - COMMAND bash -c "sed -i -E 's/^SGX_IPFS = 0/SGX_IPFS = 1/g' ${CMAKE_CURRENT_SOURCE_DIR}/enclave-sample/Makefile" + COMMAND bash -c "sed -i -E 's/^#define WASM_ENABLE_SGX_IPFS 0/#define WASM_ENABLE_SGX_IPFS 1/g' ${CMAKE_CURRENT_SOURCE_DIR}/enclave-sample/Enclave/Enclave.edl" + COMMAND bash -c "sed -i -E 's/^WAMR_BUILD_SGX_IPFS = 0/WAMR_BUILD_SGX_IPFS = 1/g' ${CMAKE_CURRENT_SOURCE_DIR}/enclave-sample/Makefile" OUTPUT_VARIABLE cmdOutput ) else() execute_process( - COMMAND bash -c "sed -i -E 's/^#define SGX_IPFS 1/#define SGX_IPFS 0/g' ${CMAKE_CURRENT_SOURCE_DIR}/enclave-sample/Enclave/Enclave.edl" - OUTPUT_VARIABLE cmdOutput - ) - execute_process( - COMMAND bash -c "sed -i -E 's/^SGX_IPFS = 1/SGX_IPFS = 0/g' ${CMAKE_CURRENT_SOURCE_DIR}/enclave-sample/Makefile" + COMMAND bash -c "sed -i -E 's/^#define WASM_ENABLE_SGX_IPFS 1/#define WASM_ENABLE_SGX_IPFS 0/g' ${CMAKE_CURRENT_SOURCE_DIR}/enclave-sample/Enclave/Enclave.edl" + COMMAND bash -c "sed -i -E 's/^WAMR_BUILD_SGX_IPFS = 1/WAMR_BUILD_SGX_IPFS = 0/g' ${CMAKE_CURRENT_SOURCE_DIR}/enclave-sample/Makefile" OUTPUT_VARIABLE cmdOutput ) endif() diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/linux-sgx/CMakeLists_minimal.txt b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/linux-sgx/CMakeLists_minimal.txt similarity index 95% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/linux-sgx/CMakeLists_minimal.txt rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/linux-sgx/CMakeLists_minimal.txt index b79565f192e..aa3de6dacbb 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/linux-sgx/CMakeLists_minimal.txt +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/linux-sgx/CMakeLists_minimal.txt @@ -69,10 +69,6 @@ if (NOT DEFINED WAMR_BUILD_LIB_PTHREAD) set (WAMR_BUILD_LIB_PTHREAD 0) endif () -if (COLLECT_CODE_COVERAGE EQUAL 1) - set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage") -endif () - set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99 -ffunction-sections -fdata-sections \ -Wall -Wno-unused-parameter -Wno-pedantic \ diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/linux-sgx/enclave-sample/Makefile b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/linux-sgx/enclave-sample/Makefile similarity index 83% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/linux-sgx/enclave-sample/Makefile rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/linux-sgx/enclave-sample/Makefile index bb7cfd19a9a..b598aad5494 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/linux-sgx/enclave-sample/Makefile +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/linux-sgx/enclave-sample/Makefile @@ -4,18 +4,20 @@ ######## SGX SDK Settings ######## SGX_SDK ?= /opt/intel/sgxsdk +SGX_SSL ?= /opt/intel/sgxssl SGX_MODE ?= SIM SGX_ARCH ?= x64 SGX_DEBUG ?= 0 SPEC_TEST ?= 0 -# This variable is automatically set by CMakeLists.txt -SGX_IPFS = 0 +# These variables are automatically set by CMakeLists.txt +WAMR_BUILD_SGX_IPFS = 0 +WAMR_BUILD_LIB_RATS = 0 +WAMR_BUILD_GLOBAL_HEAP_POOL = 0 +WAMR_BUILD_GLOBAL_HEAP_SIZE = 10485760 VMLIB_BUILD_DIR ?= $(CURDIR)/../build LIB_RATS_SRC ?= $(VMLIB_BUILD_DIR)/_deps/librats-build -LIB_RATS := $(shell if [ -d $(LIB_RATS_SRC) ]; then echo 1; else echo 0; fi) - LIB_RATS_INSTALL_DIR := $(VMLIB_BUILD_DIR)/librats/lib/librats LIB_RATS_INCLUDE_DIR := $(VMLIB_BUILD_DIR)/librats/include @@ -59,7 +61,7 @@ endif App_Cpp_Files := App/App.cpp App_Include_Paths := -IApp -I$(SGX_SDK)/include -ifeq ($(LIB_RATS), 1) +ifeq ($(WAMR_BUILD_LIB_RATS), 1) App_Include_Paths += -I$(LIB_RATS_INCLUDE_DIR) endif @@ -92,8 +94,8 @@ else App_Link_Flags += -lsgx_uae_service endif -ifeq ($(LIB_RATS), 1) - App_Link_Flags += -L$(LIB_RATS_INSTALL_DIR) -lrats_u -lsgx_dcap_ql -lsgx_dcap_quoteverify -lsgx_ukey_exchange +ifeq ($(WAMR_BUILD_LIB_RATS), 1) + App_Link_Flags += -L$(LIB_RATS_INSTALL_DIR) -L$(SGX_SSL)/lib64 -lrats_u -lsgx_dcap_ql -lsgx_dcap_quoteverify -lsgx_ukey_exchange -lsgx_usgxssl endif App_Cpp_Objects := $(App_Cpp_Files:.cpp=.o) @@ -110,7 +112,7 @@ else Service_Library_Name := sgx_tservice endif -ifeq ($(SGX_IPFS), 1) +ifeq ($(WAMR_BUILD_SGX_IPFS), 1) Intel_Ipfs_Trusted_Flag = -lsgx_tprotected_fs App_Link_Flags += -lsgx_uprotected_fs endif @@ -128,28 +130,29 @@ Enclave_Include_Paths := -IEnclave -I$(WAMR_ROOT)/core/iwasm/include \ -I$(SGX_SDK)/include/tlibc \ -I$(SGX_SDK)/include/stlport -ifeq ($(LIB_RATS), 1) - Enclave_Include_Paths += -I$(LIB_RATS_INCLUDE_DIR) +ifeq ($(WAMR_BUILD_LIB_RATS), 1) + Enclave_Include_Paths += -I$(LIB_RATS_INCLUDE_DIR) -I$(SGX_SSL)/include endif -Enclave_C_Flags := $(SGX_COMMON_CFLAGS) -nostdinc -fvisibility=hidden -fpie -fstack-protector $(Enclave_Include_Paths) +Enclave_C_Flags := $(SGX_COMMON_CFLAGS) -nostdinc -fvisibility=hidden -fpie -fstack-protector $(Enclave_Include_Paths) -DWASM_GLOBAL_HEAP_SIZE=$(WAMR_BUILD_GLOBAL_HEAP_SIZE) -DWASM_ENABLE_GLOBAL_HEAP_POOL=$(WAMR_BUILD_GLOBAL_HEAP_POOL) -DWASM_ENABLE_LIB_RATS=$(WAMR_BUILD_LIB_RATS) ifeq ($(SPEC_TEST), 1) Enclave_C_Flags += -DWASM_ENABLE_SPEC_TEST=1 else Enclave_C_Flags += -DWASM_ENABLE_SPEC_TEST=0 endif -ifeq ($(LIB_RATS), 1) - Rats_Lib_Link_Dirs := -L$(LIB_RATS_INSTALL_DIR) -L$(LIB_RATS_INSTALL_DIR)/attesters -L$(LIB_RATS_INSTALL_DIR)/verifiers - Rats_Lib_Link_libs := -lattester_nullattester -lattester_sgx_ecdsa -lattester_sgx_la \ +ifeq ($(WAMR_BUILD_LIB_RATS), 1) + Rats_Lib_Link_Dirs := -L$(LIB_RATS_INSTALL_DIR) -L$(LIB_RATS_INSTALL_DIR)/attesters -L$(LIB_RATS_INSTALL_DIR)/verifiers -L$(SGX_SSL)/lib64 + Rats_Lib_W_Link_libs := -lattester_nullattester -lattester_sgx_ecdsa -lattester_sgx_la \ -lverifier_nullverifier -lverifier_sgx_ecdsa -lverifier_sgx_la -lverifier_sgx_ecdsa_qve \ - -lrats_lib + -lrats_lib -lsgx_tsgxssl + Rats_Lib_NW_Link_libs := -lsgx_dcap_tvl -lsgx_tsgxssl_crypto endif Enclave_Cpp_Flags := $(Enclave_C_Flags) -std=c++11 -nostdinc++ Enclave_Link_Flags := $(SGX_COMMON_CFLAGS) -Wl,--no-undefined -nostdlib -nodefaultlibs -nostartfiles -L$(SGX_LIBRARY_PATH) ${Rats_Lib_Link_Dirs} \ - -Wl,--whole-archive -l$(Trts_Library_Name) ${Rats_Lib_Link_libs} $(Intel_Ipfs_Trusted_Flag) -Wl,--no-whole-archive \ - -Wl,--start-group -lsgx_tstdc -lsgx_tcxx -lsgx_pthread -lsgx_tkey_exchange -l$(Crypto_Library_Name) -l$(Service_Library_Name) -lsgx_dcap_tvl -Wl,--end-group \ + -Wl,--whole-archive -l$(Trts_Library_Name) ${Rats_Lib_W_Link_libs} $(Intel_Ipfs_Trusted_Flag) -Wl,--no-whole-archive \ + -Wl,--start-group -lsgx_tstdc -lsgx_tcxx -lsgx_pthread -lsgx_tkey_exchange -l$(Crypto_Library_Name) -l$(Service_Library_Name) $(Rats_Lib_NW_Link_libs) -Wl,--end-group \ -Wl,-Bstatic -Wl,-Bsymbolic -Wl,--no-undefined \ -Wl,-pie,-eenclave_entry -Wl,--export-dynamic \ -Wl,--defsym,__ImageBase=0 @@ -157,8 +160,8 @@ Enclave_Link_Flags := $(SGX_COMMON_CFLAGS) -Wl,--no-undefined -nostdlib -nodefau Enclave_Edl_Search_Path = --search-path ../Enclave \ --search-path $(SGX_SDK)/include \ --search-path $(WAMR_ROOT)/core/shared/platform/linux-sgx -ifeq ($(LIB_RATS), 1) - Enclave_Edl_Search_Path += --search-path $(LIB_RATS_INCLUDE_DIR)/librats/edl +ifeq ($(WAMR_BUILD_LIB_RATS), 1) + Enclave_Edl_Search_Path += --search-path $(LIB_RATS_INCLUDE_DIR)/librats/edl --search-path $(SGX_SSL)/include endif @@ -199,7 +202,7 @@ endif ######## App Objects ######## librats: -ifeq ($(LIB_RATS), 1) +ifeq ($(WAMR_BUILD_LIB_RATS), 1) @cd $(LIB_RATS_SRC) && make install @echo "librats build success" endif diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/linux-sgx/enclave-sample/Makefile_minimal b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/linux-sgx/enclave-sample/Makefile_minimal similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/linux-sgx/enclave-sample/Makefile_minimal rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/linux-sgx/enclave-sample/Makefile_minimal diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/linux/CMakeLists.txt b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/linux/CMakeLists.txt similarity index 94% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/linux/CMakeLists.txt rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/linux/CMakeLists.txt index 5e064bb7ca7..4c6af78ea94 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/linux/CMakeLists.txt +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/linux/CMakeLists.txt @@ -1,7 +1,9 @@ # Copyright (C) 2019 Intel Corporation. All rights reserved. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -cmake_minimum_required (VERSION 2.9) +cmake_minimum_required (VERSION 3.14) + +include(CheckPIESupported) project (iwasm) @@ -14,6 +16,7 @@ set (CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") set (CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") set (CMAKE_C_STANDARD 99) +set (CMAKE_CXX_STANDARD 14) # Set WAMR_BUILD_TARGET, currently values supported: # "X86_64", "AMD_64", "X86_32", "AARCH64[sub]", "ARM[sub]", "THUMB[sub]", @@ -83,6 +86,12 @@ if (NOT DEFINED WAMR_BUILD_LIB_PTHREAD) set (WAMR_BUILD_LIB_PTHREAD 0) endif () +if (NOT DEFINED WAMR_BUILD_LIB_WASI_THREADS) + # Disable wasi threads library by default + set (WAMR_BUILD_LIB_WASI_THREADS 0) +endif() + + if (NOT DEFINED WAMR_BUILD_MINI_LOADER) # Disable wasm mini loader by default set (WAMR_BUILD_MINI_LOADER 0) @@ -109,17 +118,12 @@ if (WAMR_BUILD_DEBUG_INTERP EQUAL 1) set (WAMR_BUILD_SIMD 0) endif () -if (COLLECT_CODE_COVERAGE EQUAL 1) - set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage") - set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage") -endif () - set (WAMR_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../..) include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake) add_library(vmlib ${WAMR_RUNTIME_LIB_SOURCE}) -set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections -pie -fPIE") +set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wformat -Wformat-security -Wshadow") # set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wconversion -Wsign-conversion") @@ -164,6 +168,9 @@ include (${SHARED_DIR}/utils/uncommon/shared_uncommon.cmake) add_executable (iwasm main.c ${UNCOMMON_SHARED_SOURCE}) +check_pie_supported() +set_target_properties (iwasm PROPERTIES POSITION_INDEPENDENT_CODE ON) + install (TARGETS iwasm DESTINATION bin) target_link_libraries (iwasm vmlib ${LLVM_AVAILABLE_LIBS} ${UV_A_LIBS} -lm -ldl -lpthread) diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/linux/build_jit.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/linux/build_jit.sh similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/linux/build_jit.sh rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/linux/build_jit.sh diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/linux/build_llvm.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/linux/build_llvm.sh new file mode 100755 index 00000000000..c5666b7f5d4 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/linux/build_llvm.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +# Copyright (C) 2020 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +/usr/bin/env python3 -m pip install --user -r ../../../build-scripts/requirements.txt +/usr/bin/env python3 ../../../build-scripts/build_llvm.py "$@" diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/nuttx/main.c b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/linux/main.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/nuttx/main.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/linux/main.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/vxworks/main.c b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/nuttx/main.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/vxworks/main.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/nuttx/main.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/nuttx/wamr.mk b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/nuttx/wamr.mk similarity index 89% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/nuttx/wamr.mk rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/nuttx/wamr.mk index bebd5f2ad05..78cf3eea1d7 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/nuttx/wamr.mk +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/nuttx/wamr.mk @@ -8,7 +8,7 @@ SHARED_ROOT := wamr/core/shared ifeq ($(CONFIG_ARCH_ARMV6M),y) WAMR_BUILD_TARGET := THUMBV6M else ifeq ($(CONFIG_ARCH_ARMV7A),y) -WAMR_BUILD_TARGET := THUMBV7A +WAMR_BUILD_TARGET := THUMBV7 else ifeq ($(CONFIG_ARCH_ARMV7M),y) WAMR_BUILD_TARGET := THUMBV7EM else ifeq ($(CONFIG_ARCH_ARMV8M),y) @@ -32,6 +32,12 @@ WAMR_BUILD_TARGET := RISCV32 else ifeq ($(CONFIG_ARCH_SIM),y) ifeq ($(CONFIG_SIM_M32),y) WAMR_BUILD_TARGET := X86_32 +else ifeq ($(CONFIG_HOST_X86),y) +WAMR_BUILD_TARGET := X86_32 +else ifeq ($(CONFIG_HOST_ARM),y) +WAMR_BUILD_TARGET := ARM +else ifeq ($(CONFIG_HOST_ARM64),y) +WAMR_BUILD_TARGET := AARCH64 else WAMR_BUILD_TARGET := X86_64 endif @@ -54,6 +60,11 @@ else ifeq ($(WAMR_BUILD_TARGET), X86_64) CFLAGS += -DBUILD_TARGET_X86_64 INVOKE_NATIVE := invokeNative_em64.s AOT_RELOC := aot_reloc_x86_64.c +else ifeq ($(WAMR_BUILD_TARGET), AARCH64) + CFLAGS += -DBUILD_TARGET_AARCH64 + CFLAGS += -DBUILD_TARGET=\"$(WAMR_BUILD_TARGET)\" + INVOKE_NATIVE := invokeNative_aarch64.s + AOT_RELOC := aot_reloc_aarch64.c else ifeq ($(findstring ARM,$(WAMR_BUILD_TARGET)), ARM) CFLAGS += -DBUILD_TARGET_ARM CFLAGS += -DBUILD_TARGET=\"$(WAMR_BUILD_TARGET)\" @@ -124,6 +135,12 @@ else CFLAGS += -DWASM_ENABLE_AOT=0 endif +ifeq ($(CONFIG_INTERPRETERS_WAMR_AOT_WORD_ALIGN_READ),y) +CFLAGS += -DWASM_ENABLE_WORD_ALIGN_READ=1 +else +CFLAGS += -DWASM_ENABLE_WORD_ALIGN_READ=0 +endif + ifeq ($(CONFIG_INTERPRETERS_WAMR_FAST), y) CFLAGS += -DWASM_ENABLE_FAST_INTERP=1 CFLAGS += -DWASM_ENABLE_INTERP=1 @@ -199,6 +216,12 @@ else CFLAGS += -DWASM_ENABLE_MEMORY_TRACING=0 endif +ifeq ($(CONFIG_INTERPRETERS_WAMR_DUMP_CALL_STACK),y) +CFLAGS += -DWASM_ENABLE_DUMP_CALL_STACK=1 +else +CFLAGS += -DWASM_ENABLE_DUMP_CALL_STACK=0 +endif + ifeq ($(CONFIG_INTERPRETERS_WAMR_LIBC_BUILTIN),y) CFLAGS += -DWASM_ENABLE_LIBC_BUILTIN=1 CSRCS += libc_builtin_wrapper.c @@ -251,8 +274,10 @@ endif ifeq ($(CONFIG_INTERPRETERS_WAMR_DISABLE_HW_BOUND_CHECK),y) CFLAGS += -DWASM_DISABLE_HW_BOUND_CHECK=1 +CFLAGS += -DWASM_DISABLE_STACK_HW_BOUND_CHECK=1 else CFLAGS += -DWASM_DISABLE_HW_BOUND_CHECK=0 +CFLAGS += -DWASM_DISABLE_STACK_HW_BOUND_CHECK=0 endif ifeq ($(CONFIG_INTERPRETERS_WAMR_CUSTOM_NAME_SECTIONS),y) @@ -268,6 +293,18 @@ else CFLAGS += -DWASM_ENABLE_GLOBAL_HEAP_POOL=0 endif +ifeq ($(CONFIG_INTERPRETERS_WAMR_ENABLE_SPEC_TEST),y) +CFLAGS += -DWASM_ENABLE_SPEC_TEST=1 +else +CFLAGS += -DWASM_ENABLE_SPEC_TEST=0 +endif + +ifeq ($(CONFIG_INTERPRETERS_WAMR_REF_TYPES),y) +CFLAGS += -DWASM_ENABLE_REF_TYPES=1 +else +CFLAGS += -DWASM_ENABLE_REF_TYPES=0 +endif + CFLAGS += -Wno-strict-prototypes -Wno-shadow -Wno-unused-variable CFLAGS += -Wno-int-conversion -Wno-implicit-function-declaration diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/posix/main.c b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/posix/main.c similarity index 78% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/posix/main.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/posix/main.c index 4834fd50852..2e96ccddd6c 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/posix/main.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/posix/main.c @@ -6,6 +6,7 @@ #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif +#include #include #include @@ -32,11 +33,27 @@ print_help() printf(" -v=n Set log verbose level (0 to 5, default is 2) larger\n" " level with more log\n"); #endif - printf(" --stack-size=n Set maximum stack size in bytes, default is 16 KB\n"); +#if WASM_ENABLE_INTERP != 0 + printf(" --interp Run the wasm app with interpreter mode\n"); +#endif +#if WASM_ENABLE_FAST_JIT != 0 + printf(" --fast-jit Run the wasm app with fast jit mode\n"); +#endif +#if WASM_ENABLE_JIT != 0 + printf(" --llvm-jit Run the wasm app with llvm jit mode\n"); +#endif +#if WASM_ENABLE_JIT != 0 && WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_LAZY_JIT != 0 + printf(" --multi-tier-jit Run the wasm app with multi-tier jit mode\n"); +#endif + printf(" --stack-size=n Set maximum stack size in bytes, default is 64 KB\n"); printf(" --heap-size=n Set maximum heap size in bytes, default is 16 KB\n"); #if WASM_ENABLE_FAST_JIT != 0 printf(" --jit-codecache-size=n Set fast jit maximum code cache size in bytes,\n"); printf(" default is %u KB\n", FAST_JIT_DEFAULT_CODE_CACHE_SIZE / 1024); +#endif +#if WASM_ENABLE_JIT != 0 + printf(" --llvm-jit-size-level=n Set LLVM JIT size level, default is 3\n"); + printf(" --llvm-jit-opt-level=n Set LLVM JIT optimization level, default is 3\n"); #endif printf(" --repl Start a very simple REPL (read-eval-print-loop) mode\n" " that runs commands in the form of \"FUNC ARG...\"\n"); @@ -66,7 +83,7 @@ print_help() printf(" --module-path= Indicate a module search path. default is current\n" " directory('./')\n"); #endif -#if WASM_ENABLE_LIB_PTHREAD != 0 +#if WASM_ENABLE_LIB_PTHREAD != 0 || WASM_ENABLE_LIB_WASI_THREADS != 0 printf(" --max-threads=n Set maximum thread number per cluster, default is 4\n"); #endif #if WASM_ENABLE_DEBUG_INTERP != 0 @@ -78,7 +95,7 @@ print_help() } /* clang-format on */ -static void * +static const void * app_instance_main(wasm_module_inst_t module_inst) { const char *exception; @@ -86,17 +103,17 @@ app_instance_main(wasm_module_inst_t module_inst) wasm_application_execute_main(module_inst, app_argc, app_argv); if ((exception = wasm_runtime_get_exception(module_inst))) printf("%s\n", exception); - return NULL; + return exception; } -static void * +static const void * app_instance_func(wasm_module_inst_t module_inst, const char *func_name) { wasm_application_execute_func(module_inst, func_name, app_argc - 1, app_argv + 1); /* The result of wasm function or exception info was output inside wasm_application_execute_func(), here we don't output them again. */ - return NULL; + return wasm_runtime_get_exception(module_inst); } /** @@ -149,7 +166,9 @@ app_instance_repl(wasm_module_inst_t module_inst) size_t len = 0; ssize_t n; - while ((printf("webassembly> "), n = getline(&cmd, &len, stdin)) != -1) { + while ((printf("webassembly> "), fflush(stdout), + n = getline(&cmd, &len, stdin)) + != -1) { bh_assert(n > 0); if (cmd[n - 1] == '\n') { if (n == 1) @@ -245,6 +264,46 @@ load_and_register_native_libs(const char **native_lib_list, return native_handle_count; } + +static void +unregister_and_unload_native_libs(uint32 native_lib_count, + void **native_handle_list) +{ + uint32 i, n_native_symbols; + NativeSymbol *native_symbols; + char *module_name; + void *handle; + + for (i = 0; i < native_lib_count; i++) { + handle = native_handle_list[i]; + + /* lookup get_native_lib func */ + get_native_lib_func get_native_lib = dlsym(handle, "get_native_lib"); + if (!get_native_lib) { + LOG_WARNING("warning: failed to lookup `get_native_lib` function " + "from native lib %p", + handle); + continue; + } + + n_native_symbols = get_native_lib(&module_name, &native_symbols); + if (n_native_symbols == 0 || module_name == NULL + || native_symbols == NULL) { + LOG_WARNING("warning: get_native_lib returned different values for " + "native lib %p", + handle); + continue; + } + + /* unregister native symbols */ + if (!wasm_runtime_unregister_natives(module_name, native_symbols)) { + LOG_WARNING("warning: failed to unregister native lib %p", handle); + continue; + } + + dlclose(handle); + } +} #endif /* BH_HAS_DLFCN */ #if WASM_ENABLE_MULTI_MODULE != 0 @@ -301,12 +360,17 @@ main(int argc, char *argv[]) const char *func_name = NULL; uint8 *wasm_file_buf = NULL; uint32 wasm_file_size; - uint32 stack_size = 16 * 1024, heap_size = 16 * 1024; + uint32 stack_size = 64 * 1024, heap_size = 16 * 1024; #if WASM_ENABLE_FAST_JIT != 0 uint32 jit_code_cache_size = FAST_JIT_DEFAULT_CODE_CACHE_SIZE; +#endif +#if WASM_ENABLE_JIT != 0 + uint32 llvm_jit_size_level = 3; + uint32 llvm_jit_opt_level = 3; #endif wasm_module_t wasm_module = NULL; wasm_module_inst_t wasm_module_inst = NULL; + RunningMode running_mode = 0; RuntimeInitArgs init_args; char error_buf[128] = { 0 }; #if WASM_ENABLE_LOG != 0 @@ -328,7 +392,7 @@ main(int argc, char *argv[]) const char *native_lib_list[8] = { NULL }; uint32 native_lib_count = 0; void *native_handle_list[8] = { NULL }; - uint32 native_handle_count = 0, native_handle_idx; + uint32 native_handle_count = 0; #endif #if WASM_ENABLE_DEBUG_INTERP != 0 char *ip_addr = NULL; @@ -344,6 +408,27 @@ main(int argc, char *argv[]) } func_name = argv[0]; } +#if WASM_ENABLE_INTERP != 0 + else if (!strcmp(argv[0], "--interp")) { + running_mode = Mode_Interp; + } +#endif +#if WASM_ENABLE_FAST_JIT != 0 + else if (!strcmp(argv[0], "--fast-jit")) { + running_mode = Mode_Fast_JIT; + } +#endif +#if WASM_ENABLE_JIT != 0 + else if (!strcmp(argv[0], "--llvm-jit")) { + running_mode = Mode_LLVM_JIT; + } +#endif +#if WASM_ENABLE_JIT != 0 && WASM_ENABLE_FAST_JIT != 0 \ + && WASM_ENABLE_LAZY_JIT != 0 + else if (!strcmp(argv[0], "--multi-tier-jit")) { + running_mode = Mode_Multi_Tier_JIT; + } +#endif #if WASM_ENABLE_LOG != 0 else if (!strncmp(argv[0], "-v=", 3)) { log_verbose_level = atoi(argv[0] + 3); @@ -371,6 +456,38 @@ main(int argc, char *argv[]) jit_code_cache_size = atoi(argv[0] + 21); } #endif +#if WASM_ENABLE_JIT != 0 + else if (!strncmp(argv[0], "--llvm-jit-size-level=", 22)) { + if (argv[0][22] == '\0') + return print_help(); + llvm_jit_size_level = atoi(argv[0] + 22); + if (llvm_jit_size_level < 1) { + printf("LLVM JIT size level shouldn't be smaller than 1, " + "setting it to 1\n"); + llvm_jit_size_level = 1; + } + else if (llvm_jit_size_level > 3) { + printf("LLVM JIT size level shouldn't be greater than 3, " + "setting it to 3\n"); + llvm_jit_size_level = 3; + } + } + else if (!strncmp(argv[0], "--llvm-jit-opt-level=", 21)) { + if (argv[0][21] == '\0') + return print_help(); + llvm_jit_opt_level = atoi(argv[0] + 21); + if (llvm_jit_opt_level < 1) { + printf("LLVM JIT opt level shouldn't be smaller than 1, " + "setting it to 1\n"); + llvm_jit_opt_level = 1; + } + else if (llvm_jit_opt_level > 3) { + printf("LLVM JIT opt level shouldn't be greater than 3, " + "setting it to 3\n"); + llvm_jit_opt_level = 3; + } + } +#endif #if WASM_ENABLE_LIBC_WASI != 0 else if (!strncmp(argv[0], "--dir=", 6)) { if (argv[0][6] == '\0') @@ -456,7 +573,7 @@ main(int argc, char *argv[]) } } #endif -#if WASM_ENABLE_LIB_PTHREAD != 0 +#if WASM_ENABLE_LIB_PTHREAD != 0 || WASM_ENABLE_LIB_WASI_THREADS != 0 else if (!strncmp(argv[0], "--max-threads=", 14)) { if (argv[0][14] == '\0') return print_help(); @@ -496,6 +613,7 @@ main(int argc, char *argv[]) memset(&init_args, 0, sizeof(RuntimeInitArgs)); + init_args.running_mode = running_mode; #if WASM_ENABLE_GLOBAL_HEAP_POOL != 0 init_args.mem_alloc_type = Alloc_With_Pool; init_args.mem_alloc_option.pool.heap_buf = global_heap_buf; @@ -511,6 +629,11 @@ main(int argc, char *argv[]) init_args.fast_jit_code_cache_size = jit_code_cache_size; #endif +#if WASM_ENABLE_JIT != 0 + init_args.llvm_jit_size_level = llvm_jit_size_level; + init_args.llvm_jit_opt_level = llvm_jit_opt_level; +#endif + #if WASM_ENABLE_DEBUG_INTERP != 0 init_args.instance_port = instance_port; if (ip_addr) @@ -603,14 +726,33 @@ main(int argc, char *argv[]) } #endif - if (is_repl_mode) + ret = 0; + if (is_repl_mode) { app_instance_repl(wasm_module_inst); - else if (func_name) - app_instance_func(wasm_module_inst, func_name); - else - app_instance_main(wasm_module_inst); + } + else if (func_name) { + if (app_instance_func(wasm_module_inst, func_name)) { + /* got an exception */ + ret = 1; + } + } + else { + if (app_instance_main(wasm_module_inst)) { + /* got an exception */ + ret = 1; + } + } - ret = 0; +#if WASM_ENABLE_LIBC_WASI != 0 + if (ret == 0) { + /* wait for threads to finish and propagate wasi exit code. */ + ret = wasm_runtime_get_wasi_exit_code(wasm_module_inst); + if (wasm_runtime_get_exception(wasm_module_inst)) { + /* got an exception in spawned thread */ + ret = 1; + } + } +#endif #if WASM_ENABLE_DEBUG_INTERP != 0 fail4: @@ -632,18 +774,11 @@ main(int argc, char *argv[]) fail1: #if BH_HAS_DLFCN /* unload the native libraries */ - for (native_handle_idx = 0; native_handle_idx < native_handle_count; - native_handle_idx++) - dlclose(native_handle_list[native_handle_idx]); + unregister_and_unload_native_libs(native_handle_count, native_handle_list); #endif /* destroy runtime environment */ wasm_runtime_destroy(); -#if WASM_ENABLE_SPEC_TEST != 0 - (void)ret; - return 0; -#else return ret; -#endif } diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/riot/CMakeLists.txt b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/riot/CMakeLists.txt similarity index 90% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/riot/CMakeLists.txt rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/riot/CMakeLists.txt index 9b8b2229c00..00328326274 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/riot/CMakeLists.txt +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/riot/CMakeLists.txt @@ -45,6 +45,11 @@ if (NOT DEFINED WAMR_ROOT_DIR) set (WAMR_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}) endif () +# Override the global heap size for small devices +if (NOT DEFINED WAMR_BUILD_GLOBAL_HEAP_SIZE) + add_definitions (-DWASM_GLOBAL_HEAP_SIZE=262144) # 256 kB +endif () + include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake) diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/riot/Makefile b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/riot/Makefile similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/riot/Makefile rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/riot/Makefile diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/riot/iwasmt.c b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/riot/iwasmt.c similarity index 94% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/riot/iwasmt.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/riot/iwasmt.c index 955a15941d4..633b2b405d9 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/riot/iwasmt.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/riot/iwasmt.c @@ -55,9 +55,8 @@ iwasm_t(void *arg1) return NULL; } -/* choose allocator */ +/* enable FUNC_ALLOC to use custom memory allocation functions */ #define FUNC_ALLOC -/* #define POOL_ALLOC */ void * iwasm_main(void *arg1) @@ -71,17 +70,17 @@ iwasm_main(void *arg1) RuntimeInitArgs init_args; memset(&init_args, 0, sizeof(RuntimeInitArgs)); -#ifdef POOL_ALLOC - static char global_heap_buf[256 * 1024] = { 0 }; /* 256 kB */ - - init_args.mem_alloc_type = Alloc_With_Pool; - init_args.mem_alloc_option.pool.heap_buf = global_heap_buf; - init_args.mem_alloc_option.pool.heap_size = sizeof(global_heap_buf); -#elif defined(FUNC_ALLOC) +#if defined(FUNC_ALLOC) && WASM_ENABLE_GLOBAL_HEAP_POOL == 0 init_args.mem_alloc_type = Alloc_With_Allocator; init_args.mem_alloc_option.allocator.malloc_func = malloc; init_args.mem_alloc_option.allocator.realloc_func = realloc; init_args.mem_alloc_option.allocator.free_func = free; +#elif WASM_ENABLE_GLOBAL_HEAP_POOL != 0 + static char global_heap_buf[WASM_GLOBAL_HEAP_SIZE] = { 0 }; + + init_args.mem_alloc_type = Alloc_With_Pool; + init_args.mem_alloc_option.pool.heap_buf = global_heap_buf; + init_args.mem_alloc_option.pool.heap_size = sizeof(global_heap_buf); #else init_args.mem_alloc_type = Alloc_With_System_Allocator; #endif diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/riot/test_wasm.h b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/riot/test_wasm.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/riot/test_wasm.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/riot/test_wasm.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/rt-thread/SConscript b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/rt-thread/SConscript similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/rt-thread/SConscript rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/rt-thread/SConscript diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/rt-thread/iwasm.c b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/rt-thread/iwasm.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/rt-thread/iwasm.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/rt-thread/iwasm.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/rt-thread/iwasm.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/rt-thread/iwasm.cmake similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/rt-thread/iwasm.cmake rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/rt-thread/iwasm.cmake diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/vxworks/CMakeLists.txt b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/vxworks/CMakeLists.txt similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/vxworks/CMakeLists.txt rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/vxworks/CMakeLists.txt diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/vxworks/main.c b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/vxworks/main.c new file mode 100644 index 00000000000..8f0e84a97f0 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/vxworks/main.c @@ -0,0 +1,6 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include "../posix/main.c" diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/windows/CMakeLists.txt b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/windows/CMakeLists.txt similarity index 95% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/windows/CMakeLists.txt rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/windows/CMakeLists.txt index 58e5f384efa..db88f42bc15 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/windows/CMakeLists.txt +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/windows/CMakeLists.txt @@ -96,17 +96,12 @@ if (WAMR_BUILD_DEBUG_INTERP EQUAL 1) set (WAMR_BUILD_SIMD 0) endif () -if (COLLECT_CODE_COVERAGE EQUAL 1) - set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage") -endif () - set (WAMR_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../..) include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake) add_library(vmlib ${WAMR_RUNTIME_LIB_SOURCE}) #set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWIN32_LEAN_AND_MEAN") -set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_WINSOCK_DEPRECATED_NO_WARNINGS") if (NOT MINGW) set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SAFESEH:NO") set (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /SAFESEH:NO") diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/windows/build_llvm.py b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/windows/build_llvm.py similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/windows/build_llvm.py rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/windows/build_llvm.py diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/windows/main.c b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/windows/main.c similarity index 77% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/windows/main.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/windows/main.c index 73319083ac8..26fa7dcc968 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/windows/main.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/windows/main.c @@ -27,8 +27,24 @@ print_help() printf(" -v=n Set log verbose level (0 to 5, default is 2) larger\n" " level with more log\n"); #endif - printf(" --stack-size=n Set maximum stack size in bytes, default is 16 KB\n"); +#if WASM_ENABLE_INTERP != 0 + printf(" --interp Run the wasm app with interpreter mode\n"); +#endif +#if WASM_ENABLE_FAST_JIT != 0 + printf(" --fast-jit Run the wasm app with fast jit mode\n"); +#endif +#if WASM_ENABLE_JIT != 0 + printf(" --llvm-jit Run the wasm app with llvm jit mode\n"); +#endif +#if WASM_ENABLE_JIT != 0 && WASM_ENABLE_FAST_JIT != 0 && WASM_ENABLE_LAZY_JIT != 0 + printf(" --multi-tier-jit Run the wasm app with multi-tier jit mode\n"); +#endif + printf(" --stack-size=n Set maximum stack size in bytes, default is 64 KB\n"); printf(" --heap-size=n Set maximum heap size in bytes, default is 16 KB\n"); +#if WASM_ENABLE_JIT != 0 + printf(" --llvm-jit-size-level=n Set LLVM JIT size level, default is 3\n"); + printf(" --llvm-jit-opt-level=n Set LLVM JIT optimization level, default is 3\n"); +#endif printf(" --repl Start a very simple REPL (read-eval-print-loop) mode\n" " that runs commands in the form of `FUNC ARG...`\n"); #if WASM_ENABLE_LIBC_WASI != 0 @@ -43,7 +59,7 @@ print_help() printf(" --module-path= Indicate a module search path. default is current\n" " directory('./')\n"); #endif -#if WASM_ENABLE_LIB_PTHREAD != 0 +#if WASM_ENABLE_LIB_PTHREAD != 0 || WASM_ENABLE_LIB_WASI_THREADS != 0 printf(" --max-threads=n Set maximum thread number per cluster, default is 4\n"); #endif #if WASM_ENABLE_DEBUG_INTERP != 0 @@ -55,7 +71,7 @@ print_help() } /* clang-format on */ -static void * +static const void * app_instance_main(wasm_module_inst_t module_inst) { const char *exception; @@ -63,17 +79,17 @@ app_instance_main(wasm_module_inst_t module_inst) wasm_application_execute_main(module_inst, app_argc, app_argv); if ((exception = wasm_runtime_get_exception(module_inst))) printf("%s\n", exception); - return NULL; + return exception; } -static void * +static const void * app_instance_func(wasm_module_inst_t module_inst, const char *func_name) { wasm_application_execute_func(module_inst, func_name, app_argc - 1, app_argv + 1); /* The result of wasm function or exception info was output inside wasm_application_execute_func(), here we don't output them again. */ - return NULL; + return wasm_runtime_get_exception(module_inst); } /** @@ -174,10 +190,8 @@ validate_env_str(char *env) } #endif -#define USE_GLOBAL_HEAP_BUF 0 - -#if USE_GLOBAL_HEAP_BUF != 0 -static char global_heap_buf[10 * 1024 * 1024] = { 0 }; +#if WASM_ENABLE_GLOBAL_HEAP_POOL != 0 +static char global_heap_buf[WASM_GLOBAL_HEAP_SIZE] = { 0 }; #endif #if WASM_ENABLE_MULTI_MODULE != 0 @@ -229,9 +243,14 @@ main(int argc, char *argv[]) const char *func_name = NULL; uint8 *wasm_file_buf = NULL; uint32 wasm_file_size; - uint32 stack_size = 16 * 1024, heap_size = 16 * 1024; + uint32 stack_size = 64 * 1024, heap_size = 16 * 1024; +#if WASM_ENABLE_JIT != 0 + uint32 llvm_jit_size_level = 3; + uint32 llvm_jit_opt_level = 3; +#endif wasm_module_t wasm_module = NULL; wasm_module_inst_t wasm_module_inst = NULL; + RunningMode running_mode = 0; RuntimeInitArgs init_args; char error_buf[128] = { 0 }; #if WASM_ENABLE_LOG != 0 @@ -259,6 +278,26 @@ main(int argc, char *argv[]) } func_name = argv[0]; } +#if WASM_ENABLE_INTERP != 0 + else if (!strcmp(argv[0], "--interp")) { + running_mode = Mode_Interp; + } +#endif +#if WASM_ENABLE_FAST_JIT != 0 + else if (!strcmp(argv[0], "--fast-jit")) { + running_mode = Mode_Fast_JIT; + } +#endif +#if WASM_ENABLE_JIT != 0 + else if (!strcmp(argv[0], "--llvm-jit")) { + running_mode = Mode_LLVM_JIT; + } +#endif +#if WASM_ENABLE_JIT != 0 && WASM_ENABLE_FAST_JIT != 0 + else if (!strcmp(argv[0], "--multi-tier-jit")) { + running_mode = Mode_Multi_Tier_JIT; + } +#endif #if WASM_ENABLE_LOG != 0 else if (!strncmp(argv[0], "-v=", 3)) { log_verbose_level = atoi(argv[0] + 3); @@ -279,6 +318,38 @@ main(int argc, char *argv[]) return print_help(); heap_size = atoi(argv[0] + 12); } +#if WASM_ENABLE_JIT != 0 + else if (!strncmp(argv[0], "--llvm-jit-size-level=", 22)) { + if (argv[0][22] == '\0') + return print_help(); + llvm_jit_size_level = atoi(argv[0] + 22); + if (llvm_jit_size_level < 1) { + printf("LLVM JIT size level shouldn't be smaller than 1, " + "setting it to 1\n"); + llvm_jit_size_level = 1; + } + else if (llvm_jit_size_level > 3) { + printf("LLVM JIT size level shouldn't be greater than 3, " + "setting it to 3\n"); + llvm_jit_size_level = 3; + } + } + else if (!strncmp(argv[0], "--llvm-jit-opt-level=", 21)) { + if (argv[0][21] == '\0') + return print_help(); + llvm_jit_opt_level = atoi(argv[0] + 21); + if (llvm_jit_opt_level < 1) { + printf("LLVM JIT opt level shouldn't be smaller than 1, " + "setting it to 1\n"); + llvm_jit_opt_level = 1; + } + else if (llvm_jit_opt_level > 3) { + printf("LLVM JIT opt level shouldn't be greater than 3, " + "setting it to 3\n"); + llvm_jit_opt_level = 3; + } + } +#endif #if WASM_ENABLE_LIBC_WASI != 0 else if (!strncmp(argv[0], "--dir=", 6)) { if (argv[0][6] == '\0') @@ -319,7 +390,7 @@ main(int argc, char *argv[]) } } #endif -#if WASM_ENABLE_LIB_PTHREAD != 0 +#if WASM_ENABLE_LIB_PTHREAD != 0 || WASM_ENABLE_LIB_WASI_THREADS != 0 else if (!strncmp(argv[0], "--max-threads=", 14)) { if (argv[0][14] == '\0') return print_help(); @@ -359,7 +430,8 @@ main(int argc, char *argv[]) memset(&init_args, 0, sizeof(RuntimeInitArgs)); -#if USE_GLOBAL_HEAP_BUF != 0 + init_args.running_mode = running_mode; +#if WASM_ENABLE_GLOBAL_HEAP_POOL != 0 init_args.mem_alloc_type = Alloc_With_Pool; init_args.mem_alloc_option.pool.heap_buf = global_heap_buf; init_args.mem_alloc_option.pool.heap_size = sizeof(global_heap_buf); @@ -370,6 +442,11 @@ main(int argc, char *argv[]) init_args.mem_alloc_option.allocator.free_func = free; #endif +#if WASM_ENABLE_JIT != 0 + init_args.llvm_jit_size_level = llvm_jit_size_level; + init_args.llvm_jit_opt_level = llvm_jit_opt_level; +#endif + #if WASM_ENABLE_DEBUG_INTERP != 0 init_args.instance_port = instance_port; if (ip_addr) @@ -453,14 +530,33 @@ main(int argc, char *argv[]) } #endif - if (is_repl_mode) + ret = 0; + if (is_repl_mode) { app_instance_repl(wasm_module_inst); - else if (func_name) - app_instance_func(wasm_module_inst, func_name); - else - app_instance_main(wasm_module_inst); + } + else if (func_name) { + if (app_instance_func(wasm_module_inst, func_name)) { + /* got an exception */ + ret = 1; + } + } + else { + if (app_instance_main(wasm_module_inst)) { + /* got an exception */ + ret = 1; + } + } - ret = 0; +#if WASM_ENABLE_LIBC_WASI != 0 + if (ret == 0) { + /* wait for threads to finish and propagate wasi exit code. */ + ret = wasm_runtime_get_wasi_exit_code(wasm_module_inst); + if (wasm_runtime_get_exception(wasm_module_inst)) { + /* got an exception in spawned thread */ + ret = 1; + } + } +#endif #if WASM_ENABLE_DEBUG_INTERP != 0 fail4: @@ -483,10 +579,5 @@ main(int argc, char *argv[]) /* destroy runtime environment */ wasm_runtime_destroy(); -#if WASM_ENABLE_SPEC_TEST != 0 - (void)ret; - return 0; -#else return ret; -#endif } diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/zephyr/simple/CMakeLists.txt b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/zephyr/simple/CMakeLists.txt similarity index 82% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/zephyr/simple/CMakeLists.txt rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/zephyr/simple/CMakeLists.txt index 148876af7a4..8b2af15eb78 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/zephyr/simple/CMakeLists.txt +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/zephyr/simple/CMakeLists.txt @@ -40,6 +40,16 @@ if (WAMR_BUILD_TARGET STREQUAL "RISCV64_LP64" OR WAMR_BUILD_TARGET STREQUAL "RIS set (WAMR_BUILD_FAST_INTERP 1) endif () +# Override the global heap usage +if (NOT DEFINED WAMR_BUILD_GLOBAL_HEAP_POOL) + set (WAMR_BUILD_GLOBAL_HEAP_POOL 1) +endif () + +# Override the global heap size for small devices +if (NOT DEFINED WAMR_BUILD_GLOBAL_HEAP_SIZE) + set (WAMR_BUILD_GLOBAL_HEAP_SIZE 131072) # 128 KB +endif () + set (WAMR_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../../..) include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake) diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/zephyr/simple/README_docker.md b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/zephyr/simple/README_docker.md similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/zephyr/simple/README_docker.md rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/zephyr/simple/README_docker.md diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/zephyr/simple/boards/esp32.conf b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/zephyr/simple/boards/esp32.conf similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/zephyr/simple/boards/esp32.conf rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/zephyr/simple/boards/esp32.conf diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/zephyr/simple/boards/nucleo767zi.conf b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/zephyr/simple/boards/nucleo767zi.conf similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/zephyr/simple/boards/nucleo767zi.conf rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/zephyr/simple/boards/nucleo767zi.conf diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/zephyr/simple/boards/qemu_arc.conf b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/zephyr/simple/boards/qemu_arc.conf similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/zephyr/simple/boards/qemu_arc.conf rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/zephyr/simple/boards/qemu_arc.conf diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/zephyr/simple/boards/qemu_cortex_a53.conf b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/zephyr/simple/boards/qemu_cortex_a53.conf similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/zephyr/simple/boards/qemu_cortex_a53.conf rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/zephyr/simple/boards/qemu_cortex_a53.conf diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/zephyr/simple/boards/qemu_riscv32.conf b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/zephyr/simple/boards/qemu_riscv32.conf similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/zephyr/simple/boards/qemu_riscv32.conf rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/zephyr/simple/boards/qemu_riscv32.conf diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/zephyr/simple/boards/qemu_riscv64.conf b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/zephyr/simple/boards/qemu_riscv64.conf similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/zephyr/simple/boards/qemu_riscv64.conf rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/zephyr/simple/boards/qemu_riscv64.conf diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/zephyr/simple/boards/qemu_x86_nommu.conf b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/zephyr/simple/boards/qemu_x86_nommu.conf similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/zephyr/simple/boards/qemu_x86_nommu.conf rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/zephyr/simple/boards/qemu_x86_nommu.conf diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/zephyr/simple/boards/qemu_xtensa.conf b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/zephyr/simple/boards/qemu_xtensa.conf similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/zephyr/simple/boards/qemu_xtensa.conf rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/zephyr/simple/boards/qemu_xtensa.conf diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/zephyr/simple/build_and_run.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/zephyr/simple/build_and_run.sh similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/zephyr/simple/build_and_run.sh rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/zephyr/simple/build_and_run.sh diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/zephyr/simple/esp32_custom_linker.ld b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/zephyr/simple/esp32_custom_linker.ld similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/zephyr/simple/esp32_custom_linker.ld rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/zephyr/simple/esp32_custom_linker.ld diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/zephyr/simple/src/main.c b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/zephyr/simple/src/main.c similarity index 96% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/zephyr/simple/src/main.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/zephyr/simple/src/main.c index 27ce7cb950c..8799e737a07 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/zephyr/simple/src/main.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/zephyr/simple/src/main.c @@ -15,9 +15,6 @@ #include "test_wasm.h" #endif /* end of BUILD_TARGET_RISCV64_LP64 || BUILD_TARGET_RISCV32_ILP32 */ -#include -#include - #if defined(BUILD_TARGET_RISCV64_LP64) || defined(BUILD_TARGET_RISCV32_ILP32) #if defined(BUILD_TARGET_RISCV64_LP64) #define CONFIG_GLOBAL_HEAP_BUF_SIZE 4360 @@ -31,7 +28,7 @@ #define CONFIG_APP_HEAP_SIZE 256 #else /* else of BUILD_TARGET_RISCV64_LP64 || BUILD_TARGET_RISCV32_ILP32 */ -#define CONFIG_GLOBAL_HEAP_BUF_SIZE 131072 +#define CONFIG_GLOBAL_HEAP_BUF_SIZE WASM_GLOBAL_HEAP_SIZE #define CONFIG_APP_STACK_SIZE 8192 #define CONFIG_APP_HEAP_SIZE 8192 @@ -103,7 +100,9 @@ app_instance_main(wasm_module_inst_t module_inst) return NULL; } +#if WASM_ENABLE_GLOBAL_HEAP_POOL != 0 static char global_heap_buf[CONFIG_GLOBAL_HEAP_BUF_SIZE] = { 0 }; +#endif #ifdef CONFIG_BOARD_ESP32 #include "mem_alloc.h" @@ -176,9 +175,13 @@ iwasm_main(void *arg1, void *arg2, void *arg3) memset(&init_args, 0, sizeof(RuntimeInitArgs)); +#if WASM_ENABLE_GLOBAL_HEAP_POOL != 0 init_args.mem_alloc_type = Alloc_With_Pool; init_args.mem_alloc_option.pool.heap_buf = global_heap_buf; init_args.mem_alloc_option.pool.heap_size = sizeof(global_heap_buf); +#else +#error Another memory allocation scheme than global heap pool is not implemented yet for Zephyr. +#endif /* initialize runtime environment */ if (!wasm_runtime_full_init(&init_args)) { diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/zephyr/simple/src/test_wasm.h b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/zephyr/simple/src/test_wasm.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/zephyr/simple/src/test_wasm.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/zephyr/simple/src/test_wasm.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/zephyr/simple/src/test_wasm_riscv64.h b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/zephyr/simple/src/test_wasm_riscv64.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/zephyr/simple/src/test_wasm_riscv64.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/zephyr/simple/src/test_wasm_riscv64.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/zephyr/simple/src/wasm-app-riscv64/build.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/zephyr/simple/src/wasm-app-riscv64/build.sh similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/zephyr/simple/src/wasm-app-riscv64/build.sh rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/zephyr/simple/src/wasm-app-riscv64/build.sh diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/zephyr/simple/src/wasm-app-riscv64/main.c b/lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/zephyr/simple/src/wasm-app-riscv64/main.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/product-mini/platforms/zephyr/simple/src/wasm-app-riscv64/main.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/product-mini/platforms/zephyr/simple/src/wasm-app-riscv64/main.c diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/samples/README.md b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/README.md new file mode 100644 index 00000000000..21a735268e0 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/README.md @@ -0,0 +1,17 @@ + +# Samples +- [**basic**](./basic): Demonstrating how to use runtime exposed API's to call WASM functions, how to register native functions and call them, and how to call WASM function from native function. +- **[simple](./simple/README.md)**: The runtime is integrated with most of the WAMR APP libraries, and a few WASM applications are provided for testing the WAMR APP API set. It uses **built-in libc** and executes apps in **interpreter** mode by default. +- **[file](./file/README.md)**: Demonstrating the supported file interaction API of WASI. This sample can also demonstrate the SGX IPFS (Intel Protected File System), enabling an enclave to seal and unseal data at rest. +- **[littlevgl](./littlevgl/README.md)**: Demonstrating the graphic user interface application usage on WAMR. The whole [LVGL](https://github.com/lvgl/lvgl) 2D user graphic library and the UI application are built into WASM application. It uses **WASI libc** and executes apps in **AOT mode** by default. +- **[gui](./gui/README.md)**: Move the [LVGL](https://github.com/lvgl/lvgl) library into the runtime and define a WASM application interface by wrapping the littlevgl API. It uses **WASI libc** and executes apps in **interpreter** mode by default. +- **[multi-thread](./multi-thread/)**: Demonstrating how to run wasm application which creates multiple threads to execute wasm functions concurrently, and uses mutex/cond by calling pthread related API's. +- **[spawn-thread](./spawn-thread)**: Demonstrating how to execute wasm functions of the same wasm application concurrently, in threads created by host embedder or runtime, but not the wasm application itself. +- **[wasi-threads](./wasi-threads/README.md)**: Demonstrating how to run wasm application which creates multiple threads to execute wasm functions concurrently based on lib wasi-threads. +- **[multi-module](./multi-module)**: Demonstrating the [multiple modules as dependencies](./doc/multi_module.md) feature which implements the [load-time dynamic linking](https://webassembly.org/docs/dynamic-linking/). +- **[ref-types](./ref-types)**: Demonstrating how to call wasm functions with argument of externref type introduced by [reference types proposal](https://github.com/WebAssembly/reference-types). +- **[wasm-c-api](./wasm-c-api/README.md)**: Demonstrating how to run some samples from [wasm-c-api proposal](https://github.com/WebAssembly/wasm-c-api) and showing the supported API's. +- **[socket-api](./socket-api/README.md)**: Demonstrating how to run wasm tcp server and tcp client applications, and how they communicate with each other. +- **[native-lib](./native-lib/README.md)**: Demonstrating how to write required interfaces in native library, build it into a shared library and register the shared library to iwasm. +- **[sgx-ra](./sgx-ra/README.md)**: Demonstrating how to execute Remote Attestation on SGX with [librats](https://github.com/inclavare-containers/librats), which enables mutual attestation with other runtimes or other entities that support librats to ensure that each is running within the TEE. +- **[workload](./workload/README.md)**: Demonstrating how to build and run some complex workloads, e.g. tensorflow-lite, XNNPACK, wasm-av1, meshoptimizer and bwa. diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/basic/.gitignore b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/basic/.gitignore similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/basic/.gitignore rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/basic/.gitignore diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/basic/CMakeLists.txt b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/basic/CMakeLists.txt similarity index 94% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/basic/CMakeLists.txt rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/basic/CMakeLists.txt index 8273e572a49..4191ad15d1c 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/basic/CMakeLists.txt +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/basic/CMakeLists.txt @@ -1,7 +1,9 @@ # Copyright (C) 2019 Intel Corporation. All rights reserved. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -cmake_minimum_required (VERSION 2.9) +cmake_minimum_required (VERSION 3.14) + +include(CheckPIESupported) if (NOT WAMR_BUILD_PLATFORM STREQUAL "windows") project (basic) @@ -56,7 +58,6 @@ endif () if (NOT MSVC) # linker flags - set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pie -fPIE") if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang")) set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") endif () @@ -80,6 +81,9 @@ include (${SHARED_DIR}/utils/uncommon/shared_uncommon.cmake) add_executable (basic src/main.c src/native_impl.c ${UNCOMMON_SHARED_SOURCE}) +check_pie_supported() +set_target_properties (basic PROPERTIES POSITION_INDEPENDENT_CODE ON) + if (APPLE) target_link_libraries (basic vmlib -lm -ldl -lpthread) else () diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/basic/README.md b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/basic/README.md similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/basic/README.md rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/basic/README.md diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/basic/build.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/basic/build.sh similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/basic/build.sh rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/basic/build.sh diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/basic/run.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/basic/run.sh similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/basic/run.sh rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/basic/run.sh diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/basic/src/main.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/basic/src/main.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/basic/src/main.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/basic/src/main.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/basic/src/native_impl.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/basic/src/native_impl.c similarity index 93% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/basic/src/native_impl.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/basic/src/native_impl.c index c85400d1234..1374c8dd89f 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/basic/src/native_impl.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/basic/src/native_impl.c @@ -7,10 +7,6 @@ #include "wasm_export.h" #include "math.h" -extern bool -wasm_runtime_call_indirect(wasm_exec_env_t exec_env, uint32_t element_indices, - uint32_t argc, uint32_t argv[]); - // The first parameter is not exec_env because it is invoked by native funtions void reverse(char *str, int len) diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/basic/wasm-apps/testapp.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/basic/wasm-apps/testapp.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/basic/wasm-apps/testapp.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/basic/wasm-apps/testapp.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/file/CMakeLists.txt b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/file/CMakeLists.txt similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/file/CMakeLists.txt rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/file/CMakeLists.txt diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/file/README.md b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/file/README.md similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/file/README.md rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/file/README.md diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/file/src/CMakeLists.txt b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/file/src/CMakeLists.txt similarity index 94% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/file/src/CMakeLists.txt rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/file/src/CMakeLists.txt index 43936bb0862..2bc3bec6415 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/file/src/CMakeLists.txt +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/file/src/CMakeLists.txt @@ -1,7 +1,9 @@ # Copyright (C) 2022 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) + +include(CheckPIESupported) if (NOT WAMR_BUILD_PLATFORM STREQUAL "windows") project (iwasm) @@ -56,7 +58,6 @@ endif () if (NOT MSVC) # linker flags - set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pie -fPIE") if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang")) set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") endif () @@ -80,6 +81,9 @@ include (${SHARED_DIR}/utils/uncommon/shared_uncommon.cmake) add_executable (iwasm main.c ${UNCOMMON_SHARED_SOURCE}) +check_pie_supported() +set_target_properties (iwasm PROPERTIES POSITION_INDEPENDENT_CODE ON) + if (APPLE) target_link_libraries (iwasm vmlib -lm -ldl -lpthread) else () diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/file/src/main.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/file/src/main.c similarity index 92% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/file/src/main.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/file/src/main.c index de5eb291844..3675ee0574f 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/file/src/main.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/file/src/main.c @@ -20,13 +20,12 @@ main(int argc, char *argv_main[]) static char global_heap_buf[512 * 1024]; char *buffer, error_buf[128]; const char *wasm_path = NULL, *wasi_dir = NULL; - int opt; + int opt, main_result = 1; wasm_module_t module = NULL; wasm_module_inst_t module_inst = NULL; wasm_exec_env_t exec_env = NULL; uint32 buf_size, stack_size = 8092, heap_size = 8092; - uint32_t wasm_buffer = 0; RuntimeInitArgs init_args; memset(&init_args, 0, sizeof(RuntimeInitArgs)); @@ -92,7 +91,7 @@ main(int argc, char *argv_main[]) } if (wasm_application_execute_main(module_inst, 0, NULL)) { - printf("Main wasm function successfully finished.\n"); + main_result = wasm_runtime_get_wasi_exit_code(module_inst); } else { printf("call wasm function main failed. error: %s\n", @@ -103,15 +102,12 @@ main(int argc, char *argv_main[]) fail: if (exec_env) wasm_runtime_destroy_exec_env(exec_env); - if (module_inst) { - if (wasm_buffer) - wasm_runtime_module_free(module_inst, wasm_buffer); + if (module_inst) wasm_runtime_deinstantiate(module_inst); - } if (module) wasm_runtime_unload(module); if (buffer) BH_FREE(buffer); wasm_runtime_destroy(); - return 0; + return main_result; } diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/file/wasm-app/CMakeLists.txt b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/file/wasm-app/CMakeLists.txt similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/file/wasm-app/CMakeLists.txt rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/file/wasm-app/CMakeLists.txt diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/file/wasm-app/main.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/file/wasm-app/main.c similarity index 62% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/file/wasm-app/main.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/file/wasm-app/main.c index 7726b814848..6e6204cca20 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/file/wasm-app/main.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/file/wasm-app/main.c @@ -12,12 +12,13 @@ #include #include -#define PATH_TEST_FILE "test.txt" +#define PATH_TEST_FOLDER "./test" +#define PATH_TEST_FILE (PATH_TEST_FOLDER "/test.txt") #define FILE_TEXT "Hello, world!" #define WORLD_OFFSET 7 #define NAME_REPLACMENT "James" #define NAME_REPLACMENT_LEN (sizeof(NAME_REPLACMENT) - 1) -#define ADDITIONAL_SPACE 10 +#define ADDITIONAL_SPACE 1 * 1024 * 1024 int main(int argc, char **argv) @@ -26,6 +27,11 @@ main(int argc, char **argv) const char *text = FILE_TEXT; char buffer[1000]; int ret; + long long stat_size; + + // Test: Create a folder to store the file, if it does not exist yet + ret = mkdir(PATH_TEST_FOLDER, 777); + assert(ret == 0 || (ret == -1 && errno == EEXIST)); // Test: File opening (fopen) printf("Opening a file..\n"); @@ -93,8 +99,32 @@ main(int argc, char **argv) assert(ftell(file) == strlen(FILE_TEXT)); printf("[Test] Reading at specified offset passed.\n"); + // Test: moving at the start of the file (fseek) + printf("Move at the start of the file (fseek)..\n"); + printf("File current offset: %ld\n", ftell(file)); + fseek(file, 0, SEEK_SET); + printf("File current offset: %ld\n", ftell(file)); + assert(ftell(file) == 0); + + // Test: moving at the end of the file (fseek) + printf("Move at the end of the file (fseek)..\n"); + printf("File current offset: %ld\n", ftell(file)); + fseek(file, 0, SEEK_END); + printf("File current offset: %ld\n", ftell(file)); + assert(ftell(file) == strlen(FILE_TEXT)); + int end_position = ftell(file) / 2; + + // Test: moving at the middle of the file (fseek) + printf("Move at the middle of the file (fseek)..\n"); + printf("File current offset: %ld\n", ftell(file)); + fseek(file, 0, SEEK_SET); + fseek(file, end_position, SEEK_CUR); + printf("File current offset: %ld\n", ftell(file)); + assert(ftell(file) == end_position); + // Test: allocate more space to the file (posix_fallocate) - printf("Allocate more space to the file..\n"); + printf("Allocate more space to the file (posix_fallocate)..\n"); + fseek(file, 0, SEEK_END); posix_fallocate(fileno(file), ftell(file), ADDITIONAL_SPACE); printf("File current offset: %ld\n", ftell(file)); printf("Moving to the end..\n"); @@ -104,8 +134,8 @@ main(int argc, char **argv) printf("[Test] Allocation or more space passed.\n"); // Test: allocate more space to the file (ftruncate) - printf("Extend the file size of 10 bytes using ftruncate..\n"); - ftruncate(fileno(file), ftell(file) + 10); + printf("Allocate more space to the file (ftruncate)..\n"); + ftruncate(fileno(file), ftell(file) + ADDITIONAL_SPACE); assert(ftell(file) == strlen(text) + ADDITIONAL_SPACE); printf("File current offset: %ld\n", ftell(file)); printf("Moving to the end..\n"); @@ -114,17 +144,42 @@ main(int argc, char **argv) assert(ftell(file) == strlen(text) + 2 * ADDITIONAL_SPACE); printf("[Test] Extension of the file size passed.\n"); - // Test: closing the file (fclose) - printf("Closing from the file..\n"); - ret = fclose(file); - assert(ret == 0); - printf("[Test] Closing file passed.\n"); + // Test: allocate more space to the file (fseek, from the start) + printf("Allocate more space to the file (fseek) from the start..\n"); + printf("File current offset: %ld\n", ftell(file)); + fseek(file, 3 * ADDITIONAL_SPACE, SEEK_SET); + printf("File current offset: %ld\n", ftell(file)); + assert(ftell(file) == 3 * ADDITIONAL_SPACE); + printf("[Test] Extension of the file size passed.\n"); + + // Test: allocate more space to the file (fseek, from the middle) + printf("Allocate more space to the file (fseek) from the middle..\n"); + fseek(file, 3 * ADDITIONAL_SPACE, SEEK_SET); + printf("File current offset: %ld\n", ftell(file)); + fseek(file, 2 * ADDITIONAL_SPACE, SEEK_CUR); + printf("File current offset: %ld\n", ftell(file)); + assert(ftell(file) == 5 * ADDITIONAL_SPACE); + printf("[Test] Extension of the file size passed.\n"); // Display some debug information printf("Getting the size of the file on disk..\n"); struct stat st; stat(PATH_TEST_FILE, &st); - printf("The file size is %lld.\n", st.st_size); + stat_size = st.st_size; + assert(stat_size != 0); + + // Compare with the size from fstat + fstat(fileno(file), &st); + printf("The file size is: %lld (stat), %lld (fstat).\n", stat_size, + st.st_size); + assert(stat_size != 0); + assert(stat_size == st.st_size); + + // Test: closing the file (fclose) + printf("Closing from the file..\n"); + ret = fclose(file); + assert(ret == 0); + printf("[Test] Closing file passed.\n"); printf("All the tests passed!\n"); diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/gui/README.md b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/gui/README.md similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/gui/README.md rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/gui/README.md diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/gui/build.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/gui/build.sh similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/gui/build.sh rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/gui/build.sh diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/gui/lv_config/lv_conf.h b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/gui/lv_config/lv_conf.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/gui/lv_config/lv_conf.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/gui/lv_config/lv_conf.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/gui/lv_config/lv_drv_conf.h b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/gui/lv_config/lv_drv_conf.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/gui/lv_config/lv_drv_conf.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/gui/lv_config/lv_drv_conf.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/gui/lv_config/system_header.h b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/gui/lv_config/system_header.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/gui/lv_config/system_header.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/gui/lv_config/system_header.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/gui/wamr_config_gui.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/gui/wamr_config_gui.cmake similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/gui/wamr_config_gui.cmake rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/gui/wamr_config_gui.cmake diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/gui/wasm-apps/build_apps.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/gui/wasm-apps/build_apps.sh similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/gui/wasm-apps/build_apps.sh rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/gui/wasm-apps/build_apps.sh diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/gui/wasm-apps/decrease/Makefile b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/gui/wasm-apps/decrease/Makefile similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/gui/wasm-apps/decrease/Makefile rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/gui/wasm-apps/decrease/Makefile diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/gui/wasm-apps/decrease/src/main.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/gui/wasm-apps/decrease/src/main.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/gui/wasm-apps/decrease/src/main.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/gui/wasm-apps/decrease/src/main.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/gui/wasm-apps/increase/CMakeLists.txt b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/gui/wasm-apps/increase/CMakeLists.txt similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/gui/wasm-apps/increase/CMakeLists.txt rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/gui/wasm-apps/increase/CMakeLists.txt diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/gui/wasm-apps/increase/Makefile b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/gui/wasm-apps/increase/Makefile similarity index 86% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/gui/wasm-apps/increase/Makefile rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/gui/wasm-apps/increase/Makefile index 2c150332aee..5f250d6efea 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/gui/wasm-apps/increase/Makefile +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/gui/wasm-apps/increase/Makefile @@ -25,9 +25,9 @@ SRCS += $(APP_FRAMEWORK_DIR)/wgl/app/src/*.c all: @$(CC) $(CFLAGS) $(SRCS) \ - --target=wasm32 -O3 -z stack-size=2048 -Wl,--initial-memory=65536 \ - -Wl,--allow-undefined \ - -Wl,--strip-all,--no-entry -nostdlib \ + --target=wasm32-wasi -O3 -z stack-size=2048 -Wl,--initial-memory=65536 \ + -nostdlib -Wl,--allow-undefined \ + -Wl,--strip-all,--no-entry \ -Wl,--export=on_init -Wl,--export=on_timer_callback \ -Wl,--export=on_widget_event \ -Wl,--export=__heap_base,--export=__data_end \ diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/gui/wasm-apps/increase/src/main.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/gui/wasm-apps/increase/src/main.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/gui/wasm-apps/increase/src/main.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/gui/wasm-apps/increase/src/main.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/gui/wasm-runtime-wgl/src/platform/linux/iwasm_main.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/gui/wasm-runtime-wgl/src/platform/linux/iwasm_main.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/gui/wasm-runtime-wgl/src/platform/linux/iwasm_main.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/gui/wasm-runtime-wgl/src/platform/linux/iwasm_main.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/gui/wasm-runtime-wgl/src/platform/linux/lv_drv_conf.h b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/gui/wasm-runtime-wgl/src/platform/linux/lv_drv_conf.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/gui/wasm-runtime-wgl/src/platform/linux/lv_drv_conf.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/gui/wasm-runtime-wgl/src/platform/linux/lv_drv_conf.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/gui/wasm-runtime-wgl/src/platform/linux/main.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/gui/wasm-runtime-wgl/src/platform/linux/main.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/gui/wasm-runtime-wgl/src/platform/linux/main.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/gui/wasm-runtime-wgl/src/platform/linux/main.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/gui/wasm-runtime-wgl/src/platform/zephyr/LICENSE b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/gui/wasm-runtime-wgl/src/platform/zephyr/LICENSE similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/gui/wasm-runtime-wgl/src/platform/zephyr/LICENSE rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/gui/wasm-runtime-wgl/src/platform/zephyr/LICENSE diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/gui/wasm-runtime-wgl/src/platform/zephyr/XPT2046.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/gui/wasm-runtime-wgl/src/platform/zephyr/XPT2046.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/gui/wasm-runtime-wgl/src/platform/zephyr/XPT2046.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/gui/wasm-runtime-wgl/src/platform/zephyr/XPT2046.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/gui/wasm-runtime-wgl/src/platform/zephyr/XPT2046.h b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/gui/wasm-runtime-wgl/src/platform/zephyr/XPT2046.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/gui/wasm-runtime-wgl/src/platform/zephyr/XPT2046.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/gui/wasm-runtime-wgl/src/platform/zephyr/XPT2046.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/gui/wasm-runtime-wgl/src/platform/zephyr/board_config.h b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/gui/wasm-runtime-wgl/src/platform/zephyr/board_config.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/gui/wasm-runtime-wgl/src/platform/zephyr/board_config.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/gui/wasm-runtime-wgl/src/platform/zephyr/board_config.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/gui/wasm-runtime-wgl/src/platform/zephyr/display.h b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/gui/wasm-runtime-wgl/src/platform/zephyr/display.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/gui/wasm-runtime-wgl/src/platform/zephyr/display.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/gui/wasm-runtime-wgl/src/platform/zephyr/display.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/gui/wasm-runtime-wgl/src/platform/zephyr/display_ili9340.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/gui/wasm-runtime-wgl/src/platform/zephyr/display_ili9340.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/gui/wasm-runtime-wgl/src/platform/zephyr/display_ili9340.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/gui/wasm-runtime-wgl/src/platform/zephyr/display_ili9340.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/gui/wasm-runtime-wgl/src/platform/zephyr/display_ili9340.h b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/gui/wasm-runtime-wgl/src/platform/zephyr/display_ili9340.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/gui/wasm-runtime-wgl/src/platform/zephyr/display_ili9340.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/gui/wasm-runtime-wgl/src/platform/zephyr/display_ili9340.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/gui/wasm-runtime-wgl/src/platform/zephyr/display_ili9340_adafruit_1480.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/gui/wasm-runtime-wgl/src/platform/zephyr/display_ili9340_adafruit_1480.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/gui/wasm-runtime-wgl/src/platform/zephyr/display_ili9340_adafruit_1480.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/gui/wasm-runtime-wgl/src/platform/zephyr/display_ili9340_adafruit_1480.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/gui/wasm-runtime-wgl/src/platform/zephyr/iwasm_main.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/gui/wasm-runtime-wgl/src/platform/zephyr/iwasm_main.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/gui/wasm-runtime-wgl/src/platform/zephyr/iwasm_main.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/gui/wasm-runtime-wgl/src/platform/zephyr/iwasm_main.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/gui/wasm-runtime-wgl/src/platform/zephyr/main.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/gui/wasm-runtime-wgl/src/platform/zephyr/main.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/gui/wasm-runtime-wgl/src/platform/zephyr/main.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/gui/wasm-runtime-wgl/src/platform/zephyr/main.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/gui/wasm-runtime-wgl/src/platform/zephyr/pin_config_jlf.h b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/gui/wasm-runtime-wgl/src/platform/zephyr/pin_config_jlf.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/gui/wasm-runtime-wgl/src/platform/zephyr/pin_config_jlf.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/gui/wasm-runtime-wgl/src/platform/zephyr/pin_config_jlf.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/gui/wasm-runtime-wgl/src/platform/zephyr/pin_config_stm32.h b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/gui/wasm-runtime-wgl/src/platform/zephyr/pin_config_stm32.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/gui/wasm-runtime-wgl/src/platform/zephyr/pin_config_stm32.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/gui/wasm-runtime-wgl/src/platform/zephyr/pin_config_stm32.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/LICENCE.txt b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/LICENCE.txt similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/LICENCE.txt rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/LICENCE.txt diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/README.md b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/README.md similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/README.md rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/README.md diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/build.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/build.sh similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/build.sh rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/build.sh diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/lv_config/lv_conf.h b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/lv_config/lv_conf.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/lv_config/lv_conf.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/lv_config/lv_conf.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/lv_config/lv_drv_conf.h b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/lv_config/lv_drv_conf.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/lv_config/lv_drv_conf.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/lv_config/lv_drv_conf.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/vgl-native-ui-app/CMakeLists.txt b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/vgl-native-ui-app/CMakeLists.txt similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/vgl-native-ui-app/CMakeLists.txt rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/vgl-native-ui-app/CMakeLists.txt diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/vgl-native-ui-app/CMakeLists.txt.in b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/vgl-native-ui-app/CMakeLists.txt.in similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/vgl-native-ui-app/CMakeLists.txt.in rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/vgl-native-ui-app/CMakeLists.txt.in diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/vgl-native-ui-app/lv-drivers/.gitignore b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/vgl-native-ui-app/lv-drivers/.gitignore similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/vgl-native-ui-app/lv-drivers/.gitignore rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/vgl-native-ui-app/lv-drivers/.gitignore diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/vgl-native-ui-app/lv-drivers/display_indev.h b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/vgl-native-ui-app/lv-drivers/display_indev.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/vgl-native-ui-app/lv-drivers/display_indev.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/vgl-native-ui-app/lv-drivers/display_indev.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/vgl-native-ui-app/lv-drivers/indev/mouse.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/vgl-native-ui-app/lv-drivers/indev/mouse.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/vgl-native-ui-app/lv-drivers/indev/mouse.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/vgl-native-ui-app/lv-drivers/indev/mouse.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/vgl-native-ui-app/lv-drivers/indev/mouse.h b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/vgl-native-ui-app/lv-drivers/indev/mouse.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/vgl-native-ui-app/lv-drivers/indev/mouse.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/vgl-native-ui-app/lv-drivers/indev/mouse.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/vgl-native-ui-app/lv-drivers/linux_display_indev.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/vgl-native-ui-app/lv-drivers/linux_display_indev.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/vgl-native-ui-app/lv-drivers/linux_display_indev.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/vgl-native-ui-app/lv-drivers/linux_display_indev.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/vgl-native-ui-app/lv-drivers/system_header.h b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/vgl-native-ui-app/lv-drivers/system_header.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/vgl-native-ui-app/lv-drivers/system_header.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/vgl-native-ui-app/lv-drivers/system_header.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/vgl-native-ui-app/main.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/vgl-native-ui-app/main.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/vgl-native-ui-app/main.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/vgl-native-ui-app/main.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/vgl-wasm-runtime/CMakeLists.txt b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/vgl-wasm-runtime/CMakeLists.txt similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/vgl-wasm-runtime/CMakeLists.txt rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/vgl-wasm-runtime/CMakeLists.txt diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/vgl-wasm-runtime/src/display_indev.h b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/vgl-wasm-runtime/src/display_indev.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/vgl-wasm-runtime/src/display_indev.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/vgl-wasm-runtime/src/display_indev.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/vgl-wasm-runtime/src/platform/linux/display_indev.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/vgl-wasm-runtime/src/platform/linux/display_indev.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/vgl-wasm-runtime/src/platform/linux/display_indev.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/vgl-wasm-runtime/src/platform/linux/display_indev.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/vgl-wasm-runtime/src/platform/linux/iwasm_main.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/vgl-wasm-runtime/src/platform/linux/iwasm_main.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/vgl-wasm-runtime/src/platform/linux/iwasm_main.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/vgl-wasm-runtime/src/platform/linux/iwasm_main.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/vgl-wasm-runtime/src/platform/linux/main.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/vgl-wasm-runtime/src/platform/linux/main.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/vgl-wasm-runtime/src/platform/linux/main.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/vgl-wasm-runtime/src/platform/linux/main.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/vgl-wasm-runtime/src/platform/linux/mouse.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/vgl-wasm-runtime/src/platform/linux/mouse.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/vgl-wasm-runtime/src/platform/linux/mouse.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/vgl-wasm-runtime/src/platform/linux/mouse.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/LICENSE b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/LICENSE similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/LICENSE rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/LICENSE diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/XPT2046.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/XPT2046.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/XPT2046.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/XPT2046.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/XPT2046.h b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/XPT2046.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/XPT2046.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/XPT2046.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/board_config.h b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/board_config.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/board_config.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/board_config.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display.h b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display_ili9340.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display_ili9340.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display_ili9340.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display_ili9340.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display_ili9340.h b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display_ili9340.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display_ili9340.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display_ili9340.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display_ili9340_adafruit_1480.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display_ili9340_adafruit_1480.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display_ili9340_adafruit_1480.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display_ili9340_adafruit_1480.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display_indev.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display_indev.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display_indev.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/display_indev.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/iwasm_main.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/iwasm_main.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/iwasm_main.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/iwasm_main.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/main.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/main.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/main.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/main.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/pin_config_jlf.h b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/pin_config_jlf.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/pin_config_jlf.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/pin_config_jlf.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/pin_config_stm32.h b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/pin_config_stm32.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/pin_config_stm32.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/vgl-wasm-runtime/src/platform/zephyr/pin_config_stm32.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/wamr_config_littlevgl.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/wamr_config_littlevgl.cmake similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/wamr_config_littlevgl.cmake rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/wamr_config_littlevgl.cmake diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/wasm-apps/Makefile_wasm_app b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/wasm-apps/Makefile_wasm_app similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/wasm-apps/Makefile_wasm_app rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/wasm-apps/Makefile_wasm_app diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/wasm-apps/Makefile_wasm_app_no_wasi b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/wasm-apps/Makefile_wasm_app_no_wasi similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/wasm-apps/Makefile_wasm_app_no_wasi rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/wasm-apps/Makefile_wasm_app_no_wasi diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/wasm-apps/build_wasm_app.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/wasm-apps/build_wasm_app.sh similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/wasm-apps/build_wasm_app.sh rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/wasm-apps/build_wasm_app.sh diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/wasm-apps/src/display_indev.h b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/wasm-apps/src/display_indev.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/wasm-apps/src/display_indev.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/wasm-apps/src/display_indev.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/wasm-apps/src/main.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/wasm-apps/src/main.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/wasm-apps/src/main.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/wasm-apps/src/main.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/wasm-apps/src/system_header.h b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/wasm-apps/src/system_header.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/littlevgl/wasm-apps/src/system_header.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/littlevgl/wasm-apps/src/system_header.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/multi-module/CMakeLists.txt b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/multi-module/CMakeLists.txt similarity index 96% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/multi-module/CMakeLists.txt rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/multi-module/CMakeLists.txt index b57df2cb4c9..2769b97796a 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/multi-module/CMakeLists.txt +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/multi-module/CMakeLists.txt @@ -1,7 +1,10 @@ # Copyright (C) 2019 Intel Corporation. All rights reserved. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -cmake_minimum_required (VERSION 2.8...3.16) +cmake_minimum_required (VERSION 3.14) + +include(CheckPIESupported) + project(multi_module) ################ runtime settings ################ @@ -47,7 +50,6 @@ set(WAMR_BUILD_LIBC_WASI 1) set(WAMR_BUILD_MULTI_MODULE 1) # compiling and linking flags -set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pie -fPIE") if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang")) set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") endif () @@ -150,5 +152,8 @@ add_executable(multi_module src/main.c ${UNCOMMON_SHARED_SOURCE}) add_dependencies(multi_module vmlib WASM_MODULE) +check_pie_supported() +set_target_properties (multi_module PROPERTIES POSITION_INDEPENDENT_CODE ON) + # libraries target_link_libraries(multi_module PRIVATE vmlib -lpthread -lm) diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/multi-module/src/main.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/multi-module/src/main.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/multi-module/src/main.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/multi-module/src/main.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/multi-module/wasm-apps/CMakeLists.txt b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/multi-module/wasm-apps/CMakeLists.txt similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/multi-module/wasm-apps/CMakeLists.txt rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/multi-module/wasm-apps/CMakeLists.txt diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/multi-module/wasm-apps/mA.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/multi-module/wasm-apps/mA.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/multi-module/wasm-apps/mA.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/multi-module/wasm-apps/mA.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/multi-module/wasm-apps/mB.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/multi-module/wasm-apps/mB.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/multi-module/wasm-apps/mB.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/multi-module/wasm-apps/mB.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/multi-module/wasm-apps/mC.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/multi-module/wasm-apps/mC.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/multi-module/wasm-apps/mC.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/multi-module/wasm-apps/mC.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/multi-module/wasm-apps/mD.cpp b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/multi-module/wasm-apps/mD.cpp similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/multi-module/wasm-apps/mD.cpp rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/multi-module/wasm-apps/mD.cpp diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/multi-module/wasm-apps/mE.cpp b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/multi-module/wasm-apps/mE.cpp similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/multi-module/wasm-apps/mE.cpp rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/multi-module/wasm-apps/mE.cpp diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/multi-thread/CMakeLists.txt b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/multi-thread/CMakeLists.txt similarity index 93% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/multi-thread/CMakeLists.txt rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/multi-thread/CMakeLists.txt index 39485e1c188..67819eca2d6 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/multi-thread/CMakeLists.txt +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/multi-thread/CMakeLists.txt @@ -1,7 +1,10 @@ # Copyright (C) 2019 Intel Corporation. All rights reserved. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -cmake_minimum_required(VERSION 2.8) +cmake_minimum_required(VERSION 3.14) + +include(CheckPIESupported) + project(pthread) ################ runtime settings ################ @@ -48,7 +51,6 @@ set(WAMR_BUILD_LIB_PTHREAD 1) set(WAMR_BUILD_LIB_PTHREAD_SEMAPHORE 1) # compiling and linking flags -set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pie -fPIE") if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang")) set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") endif () @@ -73,5 +75,7 @@ set (RUNTIME_SOURCE_ALL ${UNCOMMON_SHARED_SOURCE} ) add_executable (iwasm ${RUNTIME_SOURCE_ALL}) +check_pie_supported() +set_target_properties (iwasm PROPERTIES POSITION_INDEPENDENT_CODE ON) target_link_libraries(iwasm vmlib -lpthread -lm -ldl) diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/multi-thread/wasm-apps/CMakeLists.txt b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/multi-thread/wasm-apps/CMakeLists.txt similarity index 86% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/multi-thread/wasm-apps/CMakeLists.txt rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/multi-thread/wasm-apps/CMakeLists.txt index 44ced1cc832..d7352e4274d 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/multi-thread/wasm-apps/CMakeLists.txt +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/multi-thread/wasm-apps/CMakeLists.txt @@ -38,3 +38,9 @@ set (CMAKE_EXE_LINKER_FLAGS add_executable(test.wasm main.c) target_link_libraries(test.wasm) + +add_executable(main_thread_exception.wasm main_thread_exception.c) +target_link_libraries(main_thread_exception.wasm) + +add_executable(main_global_atomic.wasm main_global_atomic.c) +target_link_libraries(main_global_atomic.wasm) \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/multi-thread/wasm-apps/main.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/multi-thread/wasm-apps/main.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/multi-thread/wasm-apps/main.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/multi-thread/wasm-apps/main.c diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/samples/multi-thread/wasm-apps/main_global_atomic.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/multi-thread/wasm-apps/main_global_atomic.c new file mode 100644 index 00000000000..dafbea886de --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/multi-thread/wasm-apps/main_global_atomic.c @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2023 Amazon.com Inc. or its affiliates. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include +#include + +#define MAX_NUM_THREADS 4 +#define NUM_ITER 1000 + +int g_count = 0; + +static void * +thread(void *arg) +{ + for (int i = 0; i < NUM_ITER; i++) { + __atomic_fetch_add(&g_count, 1, __ATOMIC_SEQ_CST); + } + + return NULL; +} + +int +main(int argc, char **argv) +{ + pthread_t tids[MAX_NUM_THREADS]; + + for (int i = 0; i < MAX_NUM_THREADS; i++) { + if (pthread_create(&tids[i], NULL, thread, NULL) != 0) { + printf("Thread creation failed\n"); + } + } + + for (int i = 0; i < MAX_NUM_THREADS; i++) { + if (pthread_join(tids[i], NULL) != 0) { + printf("Thread join failed\n"); + } + } + + printf("Value of counter after update: %d (expected=%d)\n", g_count, + MAX_NUM_THREADS * NUM_ITER); + if (g_count != MAX_NUM_THREADS * NUM_ITER) { + __builtin_trap(); + } + + return -1; +} \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/samples/multi-thread/wasm-apps/main_thread_exception.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/multi-thread/wasm-apps/main_thread_exception.c new file mode 100644 index 00000000000..80f170d40db --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/multi-thread/wasm-apps/main_thread_exception.c @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include +#include + +typedef struct ThreadArgs { + int start; + int length; +} ThreadArgs; + +void * +thread(void *args) +{ + while (1) { + /* When other threads (including main thread) throw exception, + this thread can successfully exit the dead loop */ + } +} + +int +main() +{ + pthread_t tids; + + if (pthread_create(&tids, NULL, thread, NULL) != 0) { + printf("pthread_create failed\n"); + } + + /* Trigger an exception */ + __builtin_trap(); + + return 0; +} diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/native-lib/CMakeLists.txt b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/native-lib/CMakeLists.txt similarity index 76% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/native-lib/CMakeLists.txt rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/native-lib/CMakeLists.txt index 00eb40d944f..d8201bae4f5 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/native-lib/CMakeLists.txt +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/native-lib/CMakeLists.txt @@ -1,7 +1,10 @@ # 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) + +include(CheckPIESupported) + project(native_lib) ################ runtime settings ############## @@ -46,17 +49,19 @@ set (WAMR_BUILD_LIBC_BUILTIN 1) set (WAMR_BUILD_FAST_INTERP 1) # compiling and linking flags -set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pie -fPIE") if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang")) set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") endif () set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wformat -Wformat-security") -# build out vmlib +# build out libiwasm set (WAMR_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../..) include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake) -add_library(vmlib ${WAMR_RUNTIME_LIB_SOURCE}) +# Note: we build libiwasm as a shared library here so that it can be +# shared between iwasm and native libraries. +add_library(libiwasm SHARED ${WAMR_RUNTIME_LIB_SOURCE}) +set_target_properties (libiwasm PROPERTIES OUTPUT_NAME iwasm) ################ wamr runtime ################### include (${SHARED_DIR}/utils/uncommon/shared_uncommon.cmake) @@ -68,11 +73,19 @@ set (RUNTIME_SOURCE_ALL add_executable (iwasm ${RUNTIME_SOURCE_ALL}) -target_link_libraries(iwasm vmlib -lpthread -lm -ldl) +check_pie_supported() +set_target_properties (iwasm PROPERTIES POSITION_INDEPENDENT_CODE ON) + +target_link_libraries(iwasm libiwasm -lpthread -lm -ldl) ################ native libraries ############### add_library (test_add SHARED test_add.c) add_library (test_sqrt SHARED test_sqrt.c) +add_library (test_hello SHARED test_hello.c) +# Note: Unlike simpler examples above, test_hello2 directly uses +# the API provided by the libiwasm library. +add_library (test_hello2 SHARED test_hello2.c) +target_link_libraries(test_hello2 libiwasm) ################ wasm application ############### add_subdirectory(wasm-app) diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/native-lib/README.md b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/native-lib/README.md similarity index 71% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/native-lib/README.md rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/native-lib/README.md index 797469bfee5..2bf65814d36 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/native-lib/README.md +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/native-lib/README.md @@ -49,14 +49,14 @@ will be generated. ```bash cd build -./iwasm --native-lib=libtest_add.so --native-lib=libtest_sqrt.so wasm-app/test.wasm +./iwasm --native-lib=./libtest_add.so --native-lib=./libtest_sqrt.so --native-lib=./libtest_hello.so --native-lib=./libtest_hello2.so wasm-app/test.wasm ``` ### macOS ```bash cd build -./iwasm --native-lib=libtest_add.dylib --native-lib=libtest_sqrt.dylib wasm-app/test.wasm +./iwasm --native-lib=libtest_add.dylib --native-lib=libtest_sqrt.dylib --native-lib=libtest_hello.dylib --native-lib=libtest_hello2.dylib wasm-app/test.wasm ``` The output is: @@ -65,4 +65,12 @@ The output is: Hello World! 10 + 20 = 30 sqrt(10, 20) = 500 +test_hello("main", 0x0, 0) = 41 +malloc(42) = 0x24e8 +test_hello("main", 0x24e8, 42) = 41 +Message from test_hello: Hello, main. This is test_hello_wrapper! +test_hello2("main", 0x0, 0) = 85 +malloc(86) = 0x24e8 +test_hello2("main", 0x24e8, 86) = 85 +Message from test_hello2: Hello, main. This is test_hello2_wrapper! Your wasm_module_inst_t is 0x7fd443704990. ``` diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/native-lib/test_add.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/native-lib/test_add.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/native-lib/test_add.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/native-lib/test_add.c diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/samples/native-lib/test_hello.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/native-lib/test_hello.c new file mode 100644 index 00000000000..c322ec24e8c --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/native-lib/test_hello.c @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include +#include + +#include "wasm_export.h" + +static int +test_hello_wrapper(wasm_exec_env_t exec_env, const char *name, char *result, + size_t resultlen) +{ + return snprintf(result, resultlen, "Hello, %s. This is %s!\n", name, + __func__); +} + +/* clang-format off */ +#define REG_NATIVE_FUNC(func_name, signature) \ + { #func_name, func_name##_wrapper, signature, NULL } + +static NativeSymbol native_symbols[] = { + REG_NATIVE_FUNC(test_hello, "($*~)i") +}; +/* clang-format on */ + +uint32_t +get_native_lib(char **p_module_name, NativeSymbol **p_native_symbols) +{ + *p_module_name = "env"; + *p_native_symbols = native_symbols; + return sizeof(native_symbols) / sizeof(NativeSymbol); +} diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/samples/native-lib/test_hello2.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/native-lib/test_hello2.c new file mode 100644 index 00000000000..2c8f69ed6b5 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/native-lib/test_hello2.c @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +/* + * This example basically does the same thing as test_hello.c, + * using wasm_export.h API. + */ + +#include +#include + +#include "wasm_export.h" + +static int +test_hello2_wrapper(wasm_exec_env_t exec_env, uint32_t nameaddr, + uint32_t resultaddr, uint32_t resultlen) +{ + /* + * Perform wasm_runtime_malloc to check if the runtime has been + * initialized as expected. + * This would fail with "memory hasn't been initialize" error + * unless we are not sharing a runtime with the loader app. (iwasm) + */ + void *p = wasm_runtime_malloc(1); + if (p == NULL) { + return -1; + } + wasm_runtime_free(p); + + wasm_module_inst_t inst = wasm_runtime_get_module_inst(exec_env); + if (!wasm_runtime_validate_app_str_addr(inst, nameaddr) + || !wasm_runtime_validate_app_addr(inst, resultaddr, resultlen)) { + return -1; + } + const char *name = wasm_runtime_addr_app_to_native(inst, nameaddr); + char *result = wasm_runtime_addr_app_to_native(inst, resultaddr); + return snprintf(result, resultlen, + "Hello, %s. This is %s! Your wasm_module_inst_t is %p.\n", + name, __func__, inst); +} + +/* clang-format off */ +#define REG_NATIVE_FUNC(func_name, signature) \ + { #func_name, func_name##_wrapper, signature, NULL } + +static NativeSymbol native_symbols[] = { + REG_NATIVE_FUNC(test_hello2, "(iii)i") +}; +/* clang-format on */ + +uint32_t +get_native_lib(char **p_module_name, NativeSymbol **p_native_symbols) +{ + *p_module_name = "env"; + *p_native_symbols = native_symbols; + return sizeof(native_symbols) / sizeof(NativeSymbol); +} diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/native-lib/test_sqrt.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/native-lib/test_sqrt.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/native-lib/test_sqrt.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/native-lib/test_sqrt.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/native-lib/wasm-app/CMakeLists.txt b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/native-lib/wasm-app/CMakeLists.txt similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/native-lib/wasm-app/CMakeLists.txt rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/native-lib/wasm-app/CMakeLists.txt diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/samples/native-lib/wasm-app/main.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/native-lib/wasm-app/main.c new file mode 100644 index 00000000000..dba652daf0b --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/native-lib/wasm-app/main.c @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include +#include + +int +test_add(int x, int y); + +int +test_sqrt(int x, int y); + +int +test_hello(const char *name, char *buf, size_t buflen); + +int +test_hello2(const char *name, char *buf, size_t buflen); + +int +main(int argc, char **argv) +{ + const char *name = __func__; + char *buf; + size_t buflen; + int x = 10, y = 20, res; + + printf("Hello World!\n"); + + res = test_add(x, y); + printf("%d + %d = %d\n", x, y, res); + + res = test_sqrt(x, y); + printf("sqrt(%d, %d) = %d\n", x, y, res); + + res = test_hello(name, NULL, 0); + printf("test_hello(\"%s\", %p, %zu) = %d\n", name, NULL, (size_t)0, res); + if (res == -1) { + return -1; + } + buflen = res + 1; + buf = malloc(buflen); + printf("malloc(%zu) = %p\n", buflen, buf); + res = test_hello(__func__, buf, buflen); + if (res == -1) { + return -1; + } + printf("test_hello(\"%s\", %p, %zu) = %d\n", name, buf, buflen, res); + printf("Message from test_hello: %s", buf); + free(buf); + + res = test_hello2(name, NULL, 0); + printf("test_hello2(\"%s\", %p, %zu) = %d\n", name, NULL, (size_t)0, res); + if (res == -1) { + return -1; + } + buflen = res + 1; + buf = malloc(buflen); + printf("malloc(%zu) = %p\n", buflen, buf); + res = test_hello2(__func__, buf, buflen); + if (res == -1) { + return -1; + } + printf("test_hello2(\"%s\", %p, %zu) = %d\n", name, buf, buflen, res); + printf("Message from test_hello2: %s", buf); + free(buf); + + return 0; +} diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/ref-types/CMakeLists.txt b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/ref-types/CMakeLists.txt similarity index 85% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/ref-types/CMakeLists.txt rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/ref-types/CMakeLists.txt index 0cce37f32e4..325699b2084 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/ref-types/CMakeLists.txt +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/ref-types/CMakeLists.txt @@ -1,7 +1,9 @@ # Copyright (C) 2019 Intel Corporation. All rights reserved. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -cmake_minimum_required (VERSION 2.9) +cmake_minimum_required (VERSION 3.14) + +include(CheckPIESupported) if (NOT WAMR_BUILD_PLATFORM STREQUAL "windows") project(ref-types) @@ -70,7 +72,6 @@ set(WAMR_BUILD_REF_TYPES 1) if (NOT MSVC) # compiling and linking flags - set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pie -fPIE") if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang")) set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") endif () @@ -101,12 +102,24 @@ find_program(WAT2WASM if(NOT WAT2WASM) message(SEND_ERROR "can not find wat2wasm") +else () + execute_process(COMMAND ${WAT2WASM} --version + OUTPUT_VARIABLE WAT2WASM_VERSION_OUTPUT) + string(STRIP ${WAT2WASM_VERSION_OUTPUT} WAT2WASM_VERSION) + message("-- Found wat2wasm ${WAT2WASM_VERSION}") endif() +if (${WAT2WASM_VERSION} VERSION_LESS 1.0.26) + set(WAT2WASM_FLAGS "--enable-reference-types") +endif () + include (${SHARED_DIR}/utils/uncommon/shared_uncommon.cmake) add_executable(hello src/hello.c ${UNCOMMON_SHARED_SOURCE}) +check_pie_supported() +set_target_properties (hello PROPERTIES POSITION_INDEPENDENT_CODE ON) + target_include_directories(hello PRIVATE ${UNCOMMON_SHARED_DIR}) target_link_libraries(hello vmlib -lpthread -lm) @@ -118,7 +131,7 @@ endif() # wat to wasm file(GLOB WAT_FILE src/hello.wat) add_custom_target(hello_wasm ALL - COMMAND ${WAT2WASM} ${WAT_FILE} --enable-reference-types -o ${PROJECT_BINARY_DIR}/hello.wasm + COMMAND ${WAT2WASM} ${WAT_FILE} ${WAT2WASM_FLAGS} -o ${PROJECT_BINARY_DIR}/hello.wasm DEPENDS ${WAT_FILE} BYPRODUCTS ${PROJECT_BINARY_DIR}/hello.wasm VERBATIM diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/ref-types/src/hello.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/ref-types/src/hello.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/ref-types/src/hello.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/ref-types/src/hello.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/ref-types/src/hello.wat b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/ref-types/src/hello.wat similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/ref-types/src/hello.wat rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/ref-types/src/hello.wat diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/sgx-ra/CMakeLists.txt b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/sgx-ra/CMakeLists.txt similarity index 90% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/sgx-ra/CMakeLists.txt rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/sgx-ra/CMakeLists.txt index 721582a890c..7ab5522489f 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/sgx-ra/CMakeLists.txt +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/sgx-ra/CMakeLists.txt @@ -39,10 +39,6 @@ set (WAMR_BUILD_FAST_INTERP 1) set (WAMR_BUILD_LIB_RATS 1) # compiling and linking flags -if (COLLECT_CODE_COVERAGE EQUAL 1) - set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage") -endif () - set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu11 -ffunction-sections -fdata-sections \ -Wall -Wno-unused-parameter -Wno-pedantic \ @@ -64,7 +60,8 @@ add_custom_command ( add_custom_target (vmlib_untrusted ALL DEPENDS libvmlib_untrusted.a) execute_process ( - COMMAND bash -c "sed -i -E 's/^#define LIB_RATS 0/#define LIB_RATS 1/g' ${SGX_PLATFORM_DIR}/enclave-sample/Enclave/Enclave.edl" + COMMAND bash -c "sed -i -E 's/^#define WASM_ENABLE_LIB_RATS 0/#define WASM_ENABLE_LIB_RATS 1/g' ${SGX_PLATFORM_DIR}/enclave-sample/Enclave/Enclave.edl" + COMMAND bash -c "sed -i -E 's/^WAMR_BUILD_LIB_RATS = 0/WAMR_BUILD_LIB_RATS = 1/g' ${SGX_PLATFORM_DIR}/enclave-sample/Makefile" OUTPUT_VARIABLE cmdOutput ) diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/samples/sgx-ra/README.md b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/sgx-ra/README.md new file mode 100644 index 00000000000..39a2f2d9ca6 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/sgx-ra/README.md @@ -0,0 +1,203 @@ +"sgx-ra" sample introduction +============== + +This sample demonstrates how to execute Remote Attestation on SGX with [librats](https://github.com/inclavare-containers/librats) and run it with iwasm. It can only build on [SGX supported processors](https://www.intel.com/content/www/us/en/support/articles/000028173/processors.html), please check it. + +## Preparation + +SGX-RA requires to have installed: + - the WASI-SDK, located in `/opt/wasi-sdk` + - CMake >= 3.11, which is not provided on Ubuntu 18.04 (use [Kitware APT Repository](https://apt.kitware.com/)) + +### Intel SGX dependencies + +Before starting, we need to download and install [SGX SDK](https://download.01.org/intel-sgx/latest/linux-latest/distro) and [SGX DCAP Library](https://download.01.org/intel-sgx/latest/dcap-latest) referring to this [guide](https://download.01.org/intel-sgx/sgx-dcap/1.8/linux/docs/Intel_SGX_DCAP_Linux_SW_Installation_Guide.pdf). + +The following commands are an example of the SGX environment installation on Ubuntu 18.04. +``` shell +# Set your platform, you can get the platforms list on +# https://download.01.org/intel-sgx/latest/linux-latest/distro +$ cd $HOME +$ SGX_PLATFORM=ubuntu18.04-server +$ SGX_SDK_VERSION=2.17.100.3 +$ SGX_DRIVER_VERSION=1.41 + +# install the dependencies +$ sudo apt-get update +$ sudo apt-get install -y dkms + +# install SGX Driver +$ wget https://download.01.org/intel-sgx/latest/linux-latest/distro/$SGX_PLATFORM/sgx_linux_x64_driver_$SGX_DRIVER_VERSION.bin +$ chmod +x sgx_linux_x64_driver_$SGX_DRIVER_VERSION.bin +$ sudo ./sgx_linux_x64_driver_$SGX_DRIVER_VERSION.bin + +# install SGX SDK +$ wget https://download.01.org/intel-sgx/latest/linux-latest/distro/$SGX_PLATFORM/sgx_linux_x64_sdk_$SGX_SDK_VERSION.bin +$ chmod +x sgx_linux_x64_sdk_$SGX_SDK_VERSION.bin +$ sudo ./sgx_linux_x64_sdk_$SGX_SDK_VERSION.bin + +# install SGX DCAP Library +$ echo 'deb [arch=amd64] https://download.01.org/intel-sgx/sgx_repo/ubuntu bionic main' | sudo tee /etc/apt/sources.list.d/intel-sgx.list > /dev/null +$ wget -O - https://download.01.org/intel-sgx/sgx_repo/ubuntu/intel-sgx-deb.key | sudo apt-key add - +$ sudo apt-get update +$ sudo apt-get install -y libsgx-uae-service libsgx-dcap-default-qpl-dev libsgx-dcap-ql-dev libsgx-dcap-quote-verify-dev + +# install SGX SSL Library +$ git clone https://github.com/intel/linux-sgx.git +$ cd linux-sgx && make preparation +$ sudo cp external/toolset/{current_distr}/* /usr/local/bin +$ # Verify that the paths are correctly set +$ which ar as ld objcopy objdump ranlib +$ cd ../ +$ git clone https://github.com/intel/intel-sgx-ssl.git +$ wget https://www.openssl.org/source/openssl-1.1.1q.tar.gz +$ cp openssl-1.1.1q.tar.gz intel-sgx-ssl/openssl_source +$ rm -f openssl-1.1.1q.tar.gz +$ cd intel-sgx-ssl/Linux +$ source /opt/intel/sgxsdk/environment +$ make all +$ sudo make install +``` + +You can optionally grant users to communicate with the SDK platform using the following command. +Otherwise, enclaves must be launched with root privileges. + +```shell +sudo usermod -a -G sgx_prv +``` + +### Intel Provisioning Certification Service (Intel PCS) + +Intel DCAP connects to Intel PCS to download the attestation collateral for SGX-enabled machines. +Intel provides a [quick install guide](https://www.intel.com/content/www/us/en/developer/articles/guide/intel-software-guard-extensions-data-center-attestation-primitives-quick-install-guide.html) to set up a simplified environment. +This section summarizes the commands to issue for setting up a working environment on Ubuntu 18.04. + +### Subscribe to Intel PCS Web services + +Intel SGX DCAP requires a complimentary subscription to the Intel PCS. +To subscribe to the service, browse the [Intel SGX Software Services](https://api.portal.trustedservices.intel.com/) page. +A the end of the subscription process, save the primary and the secondary keys. + +### Set up the Intel Provisioning Certification Caching Service (Intel PCCS) + +Intel PCCS is a caching mechanism for attestation collateral, preventing continuously communicating with Intel PCS during attestation. +Intel provides an implementation of the cache mechanism. + +The following commands set up Intel PCCS. +```shell +# install Node.js +$ curl -o setup.sh -sL https://deb.nodesource.com/setup_14.x +$ chmod a+x setup.sh +$ sudo ./setup.sh +# install PCCS software +$ sudo apt-get install -y cracklib-runtime sqlite3 python build-essential +$ sudo apt-get install -y sgx-dcap-pccs +``` + +The installation will run the PCCS setup script, asking you several questions. + +``` +Do you want to configure PCCS now? (Y/N) +``` + +Answer "Y" to this question. + +``` +Set HTTPS listening port [8081] (1024-65535) +``` + +Accept the default listening port of 8081. + +``` +Set the PCCS service to accept local connections only? [Y] (Y/N) +``` + +Answer "N" to this question. We want the PCCS service to accept connections from other systems. + +``` +Set your Intel PCS API key (Press ENTER to skip) +``` + +Enter either your primary or secondary key retrieved from the previous subsection. +If you already subscribed, you can retrieve them [here](https://api.portal.trustedservices.intel.com/developer). + +``` +Choose caching fill method : [LAZY] (LAZY/OFFLINE/REQ) +``` + +Answer "REQ" to this question. This places the caching service in the "on request" mode, which means it will fetch the attestation collateral for hosts as provisioning requests are received. + +``` +Set PCCS server administrator password: +Re-enter administrator password: +Set PCCS server user password: +Re-enter user password: +``` + +Enter two passwords for the PCCS server. + +``` +Do you want to generate insecure HTTPS key and cert for PCCS service? [Y] (Y/N) +``` + +Answer "Y" to this question. + +### Provisioning a system into Intel PCCS + +Now that the PCCS is up and running, it's time to provision an Intel SGX-enabled platform. +We use the tool `PCKIDRetrievalTool` to get the attestation collateral of the current machine. + +``` shell +$ sudo apt-get install -y sgx-pck-id-retrieval-tool +``` + +Adapt the configuration file of `PCKIDRetrievalTool` located in `/opt/intel/sgx-pck-id-retrieval-tool/network_setting.conf` and make the following changes: +- Change the **PCCS_URL** to match your caching service's location. +- Uncomment the **user_token** parameter, and set it to the user password you created when configuring the PCCS. +- Set the **proxy_type** to fit your environment (most likely, this will be `direct`) +- Ensure **USE_SECURE_CERT** is set to `FALSE` since we're using a self-signed certificate for testing purposes. + +Save your changes and run the provisioning tool. + +```shell +$ PCKIDRetrievalTool +Intel(R) Software Guard Extensions PCK Cert ID Retrieval Tool Version 1.14.100.3 + +the data has been sent to cache server successfully and pckid_retrieval.csv has been generated successfully! +``` + +You may get some warnings during this execution of the tool. +A correct insertion into the cache server usually means the retrieval of the attestation collateral worked. +Execute the following command to verify the collateral could be stored in your instance of Intel PCCS: + +``` +curl -k https://localhost:8081/sgx/certification/v3/qe/identity +``` + +This should print a JSON value with the attestation collateral. + +### Runtime configuration + +Edit the configuration file, `/etc/sgx_default_qcnl.conf`, and make the following changes: +- Set the **PCCS_URL** parameter to the location of our PCCS server. +- Set **USE_SECURE_CERT** to `FALSE` since we're using a self-signed certificate for testing purposes. + +This system is now ready to run Intel SGX workloads with generate evidence for remote attestation. + +## Build and executing the sample + +``` shell +$ mkdir build && cd build +$ cmake .. +$ make +$ # run the sample +$ ./iwasm wasm-app/test.wasm +``` + +The sample will print the evidence in JSON and the message: *Evidence is trusted.* + +## Further readings + +- [Intel SGX Software Installation Guide For Linux OS](https://download.01.org/intel-sgx/latest/dcap-latest/linux/docs/Intel_SGX_SW_Installation_Guide_for_Linux.pdf) +- [Intel Software Guard Extensions (Intel® SGX) Data Center Attestation Primitives: Library API ](https://download.01.org/intel-sgx/latest/dcap-latest/linux/docs/Intel_SGX_ECDSA_QuoteLibReference_DCAP_API.pdf) +- [Remote Attestation for Multi-Package Platforms using Intel SGX Datacenter Attestation Primitives (DCAP)](https://download.01.org/intel-sgx/latest/dcap-latest/linux/docs/Intel_SGX_DCAP_Multipackage_SW.pdf) diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/sgx-ra/wasm-app/CMakeLists.txt b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/sgx-ra/wasm-app/CMakeLists.txt similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/sgx-ra/wasm-app/CMakeLists.txt rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/sgx-ra/wasm-app/CMakeLists.txt diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/samples/sgx-ra/wasm-app/main.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/sgx-ra/wasm-app/main.c new file mode 100644 index 00000000000..89c4144aa78 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/sgx-ra/wasm-app/main.c @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2022 Intel Corporation + * Copyright (c) 2020-2021 Alibaba Cloud + * + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include +#include +#include "lib_rats_wrapper.h" + +#define __is_print(ch) ((unsigned int)((ch) - ' ') < 127u - ' ') + +/** + * hex_dump + * + * @brief dump data in hex format + * + * @param title: Title + * @param buf: User buffer + * @param size: Dump data size + * @param number: The number of outputs per line + * + * @return void + */ +void +hex_dump(const char *title, const uint8_t *buf, uint32_t size, uint32_t number) +{ + int i, j; + if (title) { + printf("\n\t%s:\n\n", title); + } + + for (i = 0; i < size; i += number) { + printf("%08X: ", i); + + for (j = 0; j < number; j++) { + if (j % 8 == 0) { + printf(" "); + } + if (i + j < size) + printf("%02X ", buf[i + j]); + else + printf(" "); + } + printf(" "); + + for (j = 0; j < number; j++) { + if (i + j < size) { + printf("%c", __is_print(buf[i + j]) ? buf[i + j] : '.'); + } + } + printf("\n"); + } +} + +int +main(int argc, char **argv) +{ + int ret_code = -1; + char *evidence_json = NULL; + + // Generate user_data by SHA256 buffer and the wasm module. + // user_data = SHA256(sha256_wasm_module || buffer) + const char *buffer = "This is a sample."; + + // If you want to declare the evidence of type rats_sgx_evidence_t on the + // stack, you should modify the stack size of the CMAKE_EXE_LINKER_FLAGS in + // CMakeLists.txt to 51200 at least. + rats_sgx_evidence_t *evidence = + (rats_sgx_evidence_t *)malloc(sizeof(rats_sgx_evidence_t)); + if (!evidence) { + printf("ERROR: No memory to allocate.\n"); + goto err; + } + + int rats_err = librats_collect(&evidence_json, buffer); + if (rats_err != 0) { + printf("ERROR: Collect evidence failed, error code: %#x\n", rats_err); + goto err; + } + + if (librats_parse_evidence(evidence_json, evidence) != 0) { + printf("ERROR: Parse evidence failed.\n"); + goto err; + } + + // You could use these parameters for further verification. + hex_dump("Quote", evidence->quote, evidence->quote_size, 32); + hex_dump("User Data", evidence->user_data, SGX_USER_DATA_SIZE, 32); + hex_dump("MRENCLAVE", evidence->mr_enclave, SGX_MEASUREMENT_SIZE, 32); + hex_dump("MRSIGNER", evidence->mr_signer, SGX_MEASUREMENT_SIZE, 32); + printf("\n\tProduct ID:\t\t%u\n", evidence->product_id); + printf("\tSecurity Version:\t%u\n", evidence->security_version); + printf("\tAttributes.flags:\t%llu\n", evidence->att_flags); + printf("\tAttribute.xfrm:\t\t%llu\n", evidence->att_xfrm); + + rats_err = librats_verify((const char *)evidence_json, evidence->user_data); + if (rats_err != 0) { + printf("ERROR: Evidence is not trusted, error code: %#x.\n", rats_err); + goto err; + } + + ret_code = 0; + printf("Evidence is trusted.\n"); + +err: + if (evidence_json) { + free(evidence_json); + } + + if (evidence) { + free(evidence); + } + + return ret_code; +} diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/simple/.gitignore b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/simple/.gitignore similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/simple/.gitignore rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/simple/.gitignore diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/simple/CMakeLists.txt b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/simple/CMakeLists.txt similarity index 81% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/simple/CMakeLists.txt rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/simple/CMakeLists.txt index 90d6c232547..f3a0848fec8 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/simple/CMakeLists.txt +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/simple/CMakeLists.txt @@ -12,6 +12,11 @@ message(STATUS "WAMR_BUILD_SDK_PROFILE=${WAMR_BUILD_SDK_PROFILE}") set (CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") set (CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") +if ("$ENV{COLLECT_CODE_COVERAGE}" STREQUAL "1" OR COLLECT_CODE_COVERAGE EQUAL 1) + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage") + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage") +endif () + set (WAMR_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../..) ## use library and headers in the SDK diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/simple/README.md b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/simple/README.md similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/simple/README.md rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/simple/README.md diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/simple/build.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/simple/build.sh similarity index 97% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/simple/build.sh rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/simple/build.sh index aab9997e2e5..4e8155156a3 100755 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/simple/build.sh +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/simple/build.sh @@ -56,7 +56,7 @@ done if [ "$CLEAN" = "TRUE" ]; then - rm -rf $CURR_DIR/cmake_build + rm -rf $CURR_DIR/cmake-build fi @@ -107,8 +107,8 @@ cd ${WAMR_DIR}/wamr-sdk echo "#####################build simple project" cd ${CURR_DIR} -mkdir -p cmake_build/$PROFILE -cd cmake_build/$PROFILE +mkdir -p cmake-build/$PROFILE +cd cmake-build/$PROFILE cmake ../.. -DWAMR_BUILD_SDK_PROFILE=$PROFILE $CM_TOOLCHAIN $CM_BUILD_TYPE make if [ $? != 0 ];then diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/simple/profiles/arm-interp/toolchain.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/simple/profiles/arm-interp/toolchain.cmake similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/simple/profiles/arm-interp/toolchain.cmake rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/simple/profiles/arm-interp/toolchain.cmake diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/simple/profiles/arm-interp/wamr_config_simple.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/simple/profiles/arm-interp/wamr_config_simple.cmake similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/simple/profiles/arm-interp/wamr_config_simple.cmake rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/simple/profiles/arm-interp/wamr_config_simple.cmake diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/simple/profiles/arm64-aot/toolchain.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/simple/profiles/arm64-aot/toolchain.cmake similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/simple/profiles/arm64-aot/toolchain.cmake rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/simple/profiles/arm64-aot/toolchain.cmake diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/simple/profiles/arm64-aot/wamr_config_simple.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/simple/profiles/arm64-aot/wamr_config_simple.cmake similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/simple/profiles/arm64-aot/wamr_config_simple.cmake rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/simple/profiles/arm64-aot/wamr_config_simple.cmake diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/simple/profiles/arm64-interp/toolchain.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/simple/profiles/arm64-interp/toolchain.cmake similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/simple/profiles/arm64-interp/toolchain.cmake rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/simple/profiles/arm64-interp/toolchain.cmake diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/simple/profiles/arm64-interp/wamr_config_simple.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/simple/profiles/arm64-interp/wamr_config_simple.cmake similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/simple/profiles/arm64-interp/wamr_config_simple.cmake rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/simple/profiles/arm64-interp/wamr_config_simple.cmake diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/simple/profiles/host-aot/wamr_config_simple.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/simple/profiles/host-aot/wamr_config_simple.cmake similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/simple/profiles/host-aot/wamr_config_simple.cmake rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/simple/profiles/host-aot/wamr_config_simple.cmake diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/simple/profiles/host-interp/wamr_config_simple.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/simple/profiles/host-interp/wamr_config_simple.cmake similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/simple/profiles/host-interp/wamr_config_simple.cmake rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/simple/profiles/host-interp/wamr_config_simple.cmake diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/samples/simple/profiles/macos-interp/wamr_config_simple.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/simple/profiles/macos-interp/wamr_config_simple.cmake new file mode 100644 index 00000000000..d13c06d9774 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/simple/profiles/macos-interp/wamr_config_simple.cmake @@ -0,0 +1,11 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +set (WAMR_BUILD_PLATFORM "darwin") +set (WAMR_BUILD_TARGET X86_64) +set (WAMR_BUILD_INTERP 1) +set (WAMR_BUILD_AOT 1) +set (WAMR_BUILD_JIT 0) +set (WAMR_BUILD_LIBC_BUILTIN 1) +set (WAMR_BUILD_LIBC_WASI 0) +set (WAMR_BUILD_APP_FRAMEWORK 1) +set (WAMR_BUILD_APP_LIST WAMR_APP_BUILD_BASE WAMR_APP_BUILD_CONNECTION WAMR_APP_BUILD_SENSOR) diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/samples/simple/sample_test_run.py b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/simple/sample_test_run.py new file mode 100755 index 00000000000..09c36db5ead --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/simple/sample_test_run.py @@ -0,0 +1,224 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# + +import argparse +import shlex +import subprocess +import sys +import time +import traceback +import glob + +WAMRC_CMD = "../../wamr-compiler/build/wamrc" + +def compile_wasm_files_to_aot(wasm_apps_dir): + wasm_files = glob.glob(wasm_apps_dir + "/*.wasm") + print("Compile wasm app into aot files") + for wasm_file in wasm_files: + aot_file = wasm_file[0 : len(wasm_file) - 5] + ".aot"; + cmd = [ WAMRC_CMD, "-o", aot_file, wasm_file ] + subprocess.check_call(cmd) + +def start_server(cwd): + """ + Startup the 'simple' process works in TCP server mode + """ + app_server = subprocess.Popen(shlex.split("./simple -s "), cwd=cwd) + return app_server + + +def query_installed_application(cwd): + """ + Query all installed applications + """ + qry_prc = subprocess.run( + shlex.split("./host_tool -q"), cwd=cwd, check=False, capture_output=True + ) + assert qry_prc.returncode == 69 + return qry_prc.returncode, qry_prc.stdout + + +def install_wasm_application(wasm_name, wasm_file, cwd): + """ + Install a wasm application + """ + inst_prc = subprocess.run( + shlex.split(f"./host_tool -i {wasm_name} -f {wasm_file}"), + cwd=cwd, + check=False, + capture_output=True, + ) + assert inst_prc.returncode == 65 + return inst_prc.returncode, inst_prc.stdout + + +def uninstall_wasm_application(wasm_name, cwd): + """ + Uninstall a wasm application + """ + + unst_prc = subprocess.run( + shlex.split(f"./host_tool -u {wasm_name}"), + cwd=cwd, + check=False, + capture_output=True, + ) + assert unst_prc.returncode == 66 + return unst_prc.returncode, unst_prc.stdout + + +def send_get_to_wasm_application(wasm_name, url, cwd): + """ + send a request (GET) from host to an applicaton + """ + qry_prc = subprocess.run( + shlex.split(f"./host_tool -r /app/{wasm_name}{url} -A GET"), + cwd=cwd, + check=False, + capture_output=True, + ) + assert qry_prc.returncode == 69 + return qry_prc.returncode, qry_prc.stdout + + +def main(): + """ + GO!GO!!GO!!! + """ + parser = argparse.ArgumentParser(description="run the sample and examine outputs") + parser.add_argument("working_directory", type=str) + parser.add_argument("--aot", action='store_true', help="Test with AOT") + args = parser.parse_args() + + test_aot = False + suffix = ".wasm" + if not args.aot: + print("Test with interpreter mode") + else: + print("Test with AOT mode") + test_aot = True + suffix = ".aot" + wasm_apps_dir = args.working_directory + "/wasm-apps" + compile_wasm_files_to_aot(wasm_apps_dir) + + ret = 1 + app_server = None + try: + app_server = start_server(args.working_directory) + + # wait for a second + time.sleep(1) + + print("--> Install timer" + suffix + "...") + install_wasm_application( + "timer", "./wasm-apps/timer" + suffix, args.working_directory + ) + + # wait for a second + time.sleep(3) + + print("--> Query all installed applications...") + query_installed_application(args.working_directory) + + print("--> Install event_publisher" + suffix + "...") + install_wasm_application( + "event_publisher", + "./wasm-apps/event_publisher" + suffix, + args.working_directory, + ) + + print("--> Install event_subscriber" + suffix + "...") + install_wasm_application( + "event_subscriber", + "./wasm-apps/event_subscriber" + suffix, + args.working_directory, + ) + + print("--> Query all installed applications...") + query_installed_application(args.working_directory) + + print("--> Uninstall timer" + suffix + "...") + uninstall_wasm_application("timer", args.working_directory) + + print("--> Query all installed applications...") + query_installed_application(args.working_directory) + + print("--> Uninstall event_publisher" + suffix + "...") + uninstall_wasm_application( + "event_publisher", + args.working_directory, + ) + + print("--> Uninstall event_subscriber" + suffix + "...") + uninstall_wasm_application( + "event_subscriber", + args.working_directory, + ) + + print("--> Query all installed applications...") + query_installed_application(args.working_directory) + + print("--> Install request_handler" + suffix + "...") + install_wasm_application( + "request_handler", + "./wasm-apps/request_handler" + suffix, + args.working_directory, + ) + + print("--> Query again...") + query_installed_application(args.working_directory) + + print("--> Install request_sender" + suffix + "...") + install_wasm_application( + "request_sender", + "./wasm-apps/request_sender" + suffix, + args.working_directory, + ) + + print("--> Send GET to the Wasm application named request_handler...") + send_get_to_wasm_application("request_handler", "/url1", args.working_directory) + + print("--> Uninstall request_handler" + suffix + "...") + uninstall_wasm_application( + "request_handler", + args.working_directory, + ) + + print("--> Uninstall request_sender" + suffix + "...") + uninstall_wasm_application( + "request_sender", + args.working_directory, + ) + + # Install a wasm app named "__exit_app_manager__" just to make app manager exit + # while the wasm app is uninstalled, so as to collect the code coverage data. + # Only available when collecting code coverage is enabled. + print("--> Install timer" + suffix + "...") + install_wasm_application( + "__exit_app_manager__", "./wasm-apps/timer" + suffix, args.working_directory + ) + + print("--> Uninstall timer" + suffix + "...") + uninstall_wasm_application( + "__exit_app_manager__", + args.working_directory, + ) + + # wait for a second + time.sleep(1) + + print("--> All pass") + ret = 0 + except AssertionError: + traceback.print_exc() + finally: + app_server.kill() + + return ret + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/simple/src/iwasm_main.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/simple/src/iwasm_main.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/simple/src/iwasm_main.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/simple/src/iwasm_main.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/simple/src/main.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/simple/src/main.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/simple/src/main.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/simple/src/main.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/simple/wasm-apps/connection.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/simple/wasm-apps/connection.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/simple/wasm-apps/connection.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/simple/wasm-apps/connection.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/simple/wasm-apps/event_publisher.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/simple/wasm-apps/event_publisher.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/simple/wasm-apps/event_publisher.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/simple/wasm-apps/event_publisher.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/simple/wasm-apps/event_subscriber.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/simple/wasm-apps/event_subscriber.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/simple/wasm-apps/event_subscriber.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/simple/wasm-apps/event_subscriber.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/simple/wasm-apps/request_handler.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/simple/wasm-apps/request_handler.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/simple/wasm-apps/request_handler.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/simple/wasm-apps/request_handler.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/simple/wasm-apps/request_sender.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/simple/wasm-apps/request_sender.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/simple/wasm-apps/request_sender.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/simple/wasm-apps/request_sender.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/simple/wasm-apps/sensor.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/simple/wasm-apps/sensor.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/simple/wasm-apps/sensor.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/simple/wasm-apps/sensor.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/simple/wasm-apps/timer.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/simple/wasm-apps/timer.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/simple/wasm-apps/timer.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/simple/wasm-apps/timer.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/socket-api/CMakeLists.txt b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/socket-api/CMakeLists.txt similarity index 97% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/socket-api/CMakeLists.txt rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/socket-api/CMakeLists.txt index fc8bdda7fc6..e68a63eb03a 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/socket-api/CMakeLists.txt +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/socket-api/CMakeLists.txt @@ -1,7 +1,10 @@ # Copyright (C) 2019 Intel Corporation. All rights reserved. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -cmake_minimum_required(VERSION 2.8...3.18) +cmake_minimum_required(VERSION 3.14) + +include(CheckPIESupported) + project(socket_api_sample) ####################################### @@ -170,7 +173,6 @@ set(WAMR_BUILD_LIBC_WASI 1) set(WAMR_BUILD_LIB_PTHREAD 1) # compiling and linking flags -set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pie -fPIE") if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang")) set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") endif () @@ -188,4 +190,6 @@ set (RUNTIME_SOURCE_ALL ${UNCOMMON_SHARED_SOURCE} ) add_executable (iwasm ${RUNTIME_SOURCE_ALL}) +check_pie_supported() +set_target_properties (iwasm PROPERTIES POSITION_INDEPENDENT_CODE ON) target_link_libraries(iwasm vmlib -lpthread -lm -ldl) diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/socket-api/README.md b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/socket-api/README.md similarity index 96% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/socket-api/README.md rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/socket-api/README.md index a838c8a6e7b..a3bc5ac1523 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/socket-api/README.md +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/socket-api/README.md @@ -68,7 +68,7 @@ Say Hi from the Server send and receive data via 127.0.0.1:1234. ```bash -$ ./iwasm --addr-pool=127.0.0.1/0 ./send_recv.wasm +$ ./iwasm --addr-pool=127.0.0.1/0 ./send_recv.wasm ``` The output is: @@ -121,7 +121,7 @@ Shuting down ``` ```bash -$ ./iwasm --addr-pool=127.0.0.1/15 --heap-size=10000000 timeout_client.wasm +$ ./iwasm --addr-pool=127.0.0.1/15 timeout_client.wasm ``` The output is: @@ -164,7 +164,7 @@ Datagram sent `addr_resolve.wasm` demonstrates the usage of resolving a domain name ``` -$ ./iwasm --allow-resolve=*.com addr_resolve.wasm github.com +$ ./iwasm --allow-resolve=*.com addr_resolve.wasm github.com ``` The command displays the host name and its corresponding IP address: diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/samples/socket-api/sample_test_run.py b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/socket-api/sample_test_run.py new file mode 100755 index 00000000000..ec00602817b --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/socket-api/sample_test_run.py @@ -0,0 +1,141 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2023 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# + +import argparse +import shlex +import subprocess +import sys +import time +import traceback +import glob + +WAMRC_CMD = "../../wamr-compiler/build/wamrc" + +def compile_wasm_files_to_aot(wasm_apps_dir): + wasm_files = glob.glob(wasm_apps_dir + "/*.wasm") + print("Compile wasm app into aot files") + for wasm_file in wasm_files: + aot_file = wasm_file[0 : len(wasm_file) - 5] + ".aot"; + cmd = [ WAMRC_CMD, "-o", aot_file, wasm_file ] + subprocess.check_call(cmd) + +def start_server(cmd, cwd): + app_server = subprocess.Popen(shlex.split(cmd), cwd=cwd) + return app_server + +def run_cmd(cmd, cwd): + qry_prc = subprocess.run( + shlex.split(cmd), cwd=cwd, check=False, capture_output=True + ) + if (qry_prc.returncode != 0): + print("Run {} failed, return {}".format(cmd), qry_prc.returncode) + return + print("return code: {}, output:\n{}".format(qry_prc.returncode, + qry_prc.stdout.decode())) + +def main(): + """ + GO!GO!!GO!!! + """ + parser = argparse.ArgumentParser(description="run the sample and examine outputs") + parser.add_argument("working_directory", type=str) + parser.add_argument("--aot", action='store_true', help="Test with AOT") + args = parser.parse_args() + + test_aot = False + suffix = ".wasm" + if not args.aot: + print("Test with interpreter mode") + else: + print("Test with AOT mode") + test_aot = True + suffix = ".aot" + wasm_apps_dir = args.working_directory + compile_wasm_files_to_aot(wasm_apps_dir) + + ret = 1 + app_server = None + try: + print("\n================================") + print("Test TCP server and client") + cmd = "./iwasm --addr-pool=0.0.0.0/15 tcp_server" + suffix + app_server = start_server(cmd, args.working_directory) + # wait for a second + time.sleep(1) + cmd = "./iwasm --addr-pool=127.0.0.1/15 tcp_client" + suffix + for i in range(5): + run_cmd(cmd, args.working_directory) + + print("\n================================") + print("Test UDP server and client") + cmd = "./iwasm --addr-pool=0.0.0.0/15 udp_server" + suffix + app_server = start_server(cmd, args.working_directory) + # wait for a second + time.sleep(1) + cmd = "./iwasm --addr-pool=127.0.0.1/15 udp_client" + suffix + for i in range(5): + run_cmd(cmd, args.working_directory) + + print("\n=====================================================") + print("Sleep 80 seconds to wait TCP server port actually close") + time.sleep(80) + + print("\n================================") + print("Test send and receive") + cmd = "./iwasm --addr-pool=127.0.0.1/0 ./send_recv" + suffix + run_cmd(cmd, args.working_directory) + + print("\n================================") + print("Test socket options") + cmd = "./iwasm socket_opts" + suffix + run_cmd(cmd, args.working_directory) + + print("\n================================") + print("Test timeout server and client") + cmd = "./iwasm --addr-pool=0.0.0.0/15 timeout_server" + suffix + app_server = start_server(cmd, args.working_directory) + # wait for a second + time.sleep(1) + cmd = "./iwasm --addr-pool=127.0.0.1/15 timeout_client" + suffix + run_cmd(cmd, args.working_directory) + + print("\n==========================================") + print("Test multicast_client and multicast_server") + cmd = "./iwasm --addr-pool=0.0.0.0/0,::/0 multicast_client.wasm 224.0.0.1" + app_server = start_server(cmd, args.working_directory) + # wait for a second + time.sleep(1) + cmd = "./multicast_server 224.0.0.1" + run_cmd(cmd, args.working_directory) + + cmd = "./iwasm --addr-pool=0.0.0.0/0,::/0 multicast_client.wasm FF02:113D:6FDD:2C17:A643:FFE2:1BD1:3CD2" + app_server = start_server(cmd, args.working_directory) + # wait for a second + time.sleep(1) + cmd = "./multicast_server FF02:113D:6FDD:2C17:A643:FFE2:1BD1:3CD2" + run_cmd(cmd, args.working_directory) + + print("\n================================") + print("Test address resolving") + cmd = "./iwasm --allow-resolve=*.com addr_resolve.wasm github.com" + cmd = "./multicast_server FF02:113D:6FDD:2C17:A643:FFE2:1BD1:3CD2" + run_cmd(cmd, args.working_directory) + + # wait for a second + time.sleep(1) + + print("--> All pass") + ret = 0 + except AssertionError: + traceback.print_exc() + finally: + app_server.kill() + + return ret + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/socket-api/wasm-src/CMakeLists.txt b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/socket-api/wasm-src/CMakeLists.txt similarity index 96% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/socket-api/wasm-src/CMakeLists.txt rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/socket-api/wasm-src/CMakeLists.txt index fda5d308391..8f11e0a6b4f 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/socket-api/wasm-src/CMakeLists.txt +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/socket-api/wasm-src/CMakeLists.txt @@ -54,7 +54,9 @@ function(COMPILE_WITH_CLANG SOURCE_FILE) target_link_options(${MAIN_TARGET_NAME} PRIVATE LINKER:--export=__heap_base LINKER:--export=__data_end - LINKER:--shared-memory,--max-memory=196608 + LINKER:--export=malloc + LINKER:--export=free + LINKER:--shared-memory,--max-memory=10485760 LINKER:--no-check-features LINKER:--allow-undefined ) diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/socket-api/wasm-src/addr_resolve.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/socket-api/wasm-src/addr_resolve.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/socket-api/wasm-src/addr_resolve.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/socket-api/wasm-src/addr_resolve.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/socket-api/wasm-src/inc/.gitkeep b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/socket-api/wasm-src/inc/.gitkeep similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/socket-api/wasm-src/inc/.gitkeep rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/socket-api/wasm-src/inc/.gitkeep diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/socket-api/wasm-src/multicast_client.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/socket-api/wasm-src/multicast_client.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/socket-api/wasm-src/multicast_client.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/socket-api/wasm-src/multicast_client.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/socket-api/wasm-src/multicast_server.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/socket-api/wasm-src/multicast_server.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/socket-api/wasm-src/multicast_server.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/socket-api/wasm-src/multicast_server.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/socket-api/wasm-src/send_recv.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/socket-api/wasm-src/send_recv.c similarity index 91% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/socket-api/wasm-src/send_recv.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/socket-api/wasm-src/send_recv.c index 169dc471e93..0071b2a7bcf 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/socket-api/wasm-src/send_recv.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/socket-api/wasm-src/send_recv.c @@ -19,6 +19,7 @@ static pthread_mutex_t lock = { 0 }; static pthread_cond_t cond = { 0 }; +static bool server_create_failed = false; static bool server_is_ready = false; void * @@ -46,6 +47,8 @@ run_as_server(void *arg) pthread_mutex_lock(&lock); sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { + server_create_failed = true; + pthread_cond_signal(&cond); pthread_mutex_unlock(&lock); perror("Create a socket failed"); return NULL; @@ -53,6 +56,8 @@ run_as_server(void *arg) #ifndef __wasi__ if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on))) { + server_create_failed = true; + pthread_cond_signal(&cond); pthread_mutex_unlock(&lock); perror("Setsockopt failed"); goto fail1; @@ -66,12 +71,16 @@ run_as_server(void *arg) addrlen = sizeof(addr); if (bind(sock, (struct sockaddr *)&addr, addrlen) < 0) { + server_create_failed = true; + pthread_cond_signal(&cond); pthread_mutex_unlock(&lock); perror("Bind failed"); goto fail1; } if (listen(sock, 0) < 0) { + server_create_failed = true; + pthread_cond_signal(&cond); pthread_mutex_unlock(&lock); perror("Listen failed"); goto fail1; @@ -117,11 +126,15 @@ run_as_client(void *arg) ssize_t recv_len = 0; pthread_mutex_lock(&lock); - while (false == server_is_ready) { + while (!server_create_failed && !server_is_ready) { pthread_cond_wait(&cond, &lock); } pthread_mutex_unlock(&lock); + if (server_create_failed) { + return NULL; + } + printf("Client is running...\n"); sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/socket-api/wasm-src/socket_opts.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/socket-api/wasm-src/socket_opts.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/socket-api/wasm-src/socket_opts.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/socket-api/wasm-src/socket_opts.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/socket-api/wasm-src/socket_utils.h b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/socket-api/wasm-src/socket_utils.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/socket-api/wasm-src/socket_utils.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/socket-api/wasm-src/socket_utils.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/socket-api/wasm-src/tcp_client.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/socket-api/wasm-src/tcp_client.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/socket-api/wasm-src/tcp_client.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/socket-api/wasm-src/tcp_client.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/socket-api/wasm-src/tcp_server.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/socket-api/wasm-src/tcp_server.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/socket-api/wasm-src/tcp_server.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/socket-api/wasm-src/tcp_server.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/socket-api/wasm-src/timeout_client.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/socket-api/wasm-src/timeout_client.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/socket-api/wasm-src/timeout_client.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/socket-api/wasm-src/timeout_client.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/socket-api/wasm-src/timeout_server.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/socket-api/wasm-src/timeout_server.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/socket-api/wasm-src/timeout_server.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/socket-api/wasm-src/timeout_server.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/socket-api/wasm-src/udp_client.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/socket-api/wasm-src/udp_client.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/socket-api/wasm-src/udp_client.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/socket-api/wasm-src/udp_client.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/socket-api/wasm-src/udp_server.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/socket-api/wasm-src/udp_server.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/socket-api/wasm-src/udp_server.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/socket-api/wasm-src/udp_server.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/spawn-thread/CMakeLists.txt b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/spawn-thread/CMakeLists.txt similarity index 93% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/spawn-thread/CMakeLists.txt rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/spawn-thread/CMakeLists.txt index 16618e30350..7b76311d767 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/spawn-thread/CMakeLists.txt +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/spawn-thread/CMakeLists.txt @@ -1,7 +1,10 @@ # Copyright (C) 2019 Intel Corporation. All rights reserved. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -cmake_minimum_required(VERSION 2.8) +cmake_minimum_required(VERSION 3.14) + +include(CheckPIESupported) + project(spawn_thread) ################ runtime settings ################ @@ -47,7 +50,6 @@ set(WAMR_BUILD_FAST_INTERP 1) set(WAMR_BUILD_LIB_PTHREAD 1) # compiling and linking flags -set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pie -fPIE") if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang")) set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") endif () @@ -72,4 +74,6 @@ set (RUNTIME_SOURCE_ALL ${UNCOMMON_SHARED_SOURCE} ) add_executable (spawn_thread ${RUNTIME_SOURCE_ALL}) +check_pie_supported() +set_target_properties (spawn_thread PROPERTIES POSITION_INDEPENDENT_CODE ON) target_link_libraries(spawn_thread vmlib -lpthread -lm) diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/spawn-thread/src/main.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/spawn-thread/src/main.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/spawn-thread/src/main.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/spawn-thread/src/main.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/spawn-thread/wasm-apps/CMakeLists.txt b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/spawn-thread/wasm-apps/CMakeLists.txt similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/spawn-thread/wasm-apps/CMakeLists.txt rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/spawn-thread/wasm-apps/CMakeLists.txt diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/spawn-thread/wasm-apps/sum.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/spawn-thread/wasm-apps/sum.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/spawn-thread/wasm-apps/sum.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/spawn-thread/wasm-apps/sum.c diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasi-threads/CMakeLists.txt b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasi-threads/CMakeLists.txt new file mode 100644 index 00000000000..467f5fd1f95 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasi-threads/CMakeLists.txt @@ -0,0 +1,80 @@ +# Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required(VERSION 3.14) + +include(CheckPIESupported) + +project(wasi_threads_sample) + +################ runtime settings ################ +string (TOLOWER ${CMAKE_HOST_SYSTEM_NAME} WAMR_BUILD_PLATFORM) +if (APPLE) + add_definitions(-DBH_PLATFORM_DARWIN) +endif () + +# Resetdefault linker flags +set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") +set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") + +# WAMR features switch + +# Set WAMR_BUILD_TARGET, currently values supported: +# "X86_64", "AMD_64", "X86_32", "AARCH64[sub]", "ARM[sub]", "THUMB[sub]", +# "MIPS", "XTENSA", "RISCV64[sub]", "RISCV32[sub]" +if (NOT DEFINED WAMR_BUILD_TARGET) + if (CMAKE_SYSTEM_PROCESSOR MATCHES "^(arm64|aarch64)") + set (WAMR_BUILD_TARGET "AARCH64") + elseif (CMAKE_SYSTEM_PROCESSOR STREQUAL "riscv64") + set (WAMR_BUILD_TARGET "RISCV64") + elseif (CMAKE_SIZEOF_VOID_P EQUAL 8) + # Build as X86_64 by default in 64-bit platform + set (WAMR_BUILD_TARGET "X86_64") + elseif (CMAKE_SIZEOF_VOID_P EQUAL 4) + # Build as X86_32 by default in 32-bit platform + set (WAMR_BUILD_TARGET "X86_32") + else () + message(SEND_ERROR "Unsupported build target platform!") + endif () +endif () + +if (NOT CMAKE_BUILD_TYPE) + set (CMAKE_BUILD_TYPE Release) +endif () + +set(WAMR_BUILD_INTERP 1) +set(WAMR_BUILD_AOT 1) +set(WAMR_BUILD_JIT 0) +set(WAMR_BUILD_LIBC_BUILTIN 1) +set(WAMR_BUILD_FAST_INTERP 1) +set(WAMR_BUILD_LIBC_WASI 1) +set(WAMR_BUILD_LIB_WASI_THREADS 1) + +# compiling and linking flags +if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang")) + set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") +endif () +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wformat -Wformat-security") + +# build out vmlib +set(WAMR_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../..) +include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake) + +add_library(vmlib ${WAMR_RUNTIME_LIB_SOURCE}) +################################################ + + +################ wasm application ################ +add_subdirectory(wasm-apps) + +################ wamr runtime ################ +include (${SHARED_DIR}/utils/uncommon/shared_uncommon.cmake) + +set (RUNTIME_SOURCE_ALL + ${CMAKE_CURRENT_LIST_DIR}/../../product-mini/platforms/linux/main.c + ${UNCOMMON_SHARED_SOURCE} +) +add_executable (iwasm ${RUNTIME_SOURCE_ALL}) +check_pie_supported() +set_target_properties (iwasm PROPERTIES POSITION_INDEPENDENT_CODE ON) +target_link_libraries(iwasm vmlib -lpthread -lm -ldl) diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasi-threads/README.md b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasi-threads/README.md new file mode 100644 index 00000000000..a79a3cd6a6d --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasi-threads/README.md @@ -0,0 +1,22 @@ +# "WASI threads" sample introduction + +To run the sample, `wasi-sdk` >= 20 is required. + +## Build and run the samples + +```shell +$ mkdir build +$ cd build +$ cmake .. +$ make +... +$ ./iwasm wasm-apps/no_pthread.wasm +``` + +## Run samples in AOT mode +```shell +$ ../../../wamr-compiler/build/wamrc \ + --enable-multi-thread \ + -o wasm-apps/no_pthread.aot wasm-apps/no_pthread.wasm +$ ./iwasm wasm-apps/no_pthread.aot +``` diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasi-threads/wasm-apps/CMakeLists.txt b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasi-threads/wasm-apps/CMakeLists.txt new file mode 100644 index 00000000000..87f21e9fd56 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasi-threads/wasm-apps/CMakeLists.txt @@ -0,0 +1,46 @@ +# Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +if (APPLE) + set (HAVE_FLAG_SEARCH_PATHS_FIRST 0) + set (CMAKE_C_LINK_FLAGS "") + set (CMAKE_CXX_LINK_FLAGS "") +endif () + +if (NOT DEFINED WASI_SDK_DIR) + set (WASI_SDK_DIR "/opt/wasi-sdk") +endif () + +if (DEFINED WASI_SYSROOT) + set (CMAKE_SYSROOT "${WASI_SYSROOT}") +endif () + +set (CMAKE_C_COMPILER "${WASI_SDK_DIR}/bin/clang") +set (CMAKE_ASM_COMPILER "${WASI_SDK_DIR}/bin/clang") +set (CMAKE_EXE_LINKER_FLAGS "-target wasm32-wasi-threads") + +if ("$ENV{COLLECT_CODE_COVERAGE}" STREQUAL "1" OR COLLECT_CODE_COVERAGE EQUAL 1) + set (CMAKE_C_FLAGS "") + set (CMAKE_CXX_FLAGS "") +endif () + +function (compile_sample SOURCE_FILE) + get_filename_component (FILE_NAME ${SOURCE_FILE} NAME_WLE) + set (WASM_MODULE ${FILE_NAME}.wasm) + add_executable (${WASM_MODULE} ${SOURCE_FILE} ${ARGN}) + + target_compile_options (${WASM_MODULE} PRIVATE + -pthread -ftls-model=local-exec) + + target_link_options (${WASM_MODULE} PRIVATE + -z stack-size=32768 + LINKER:--export=__heap_base + LINKER:--export=__data_end + LINKER:--shared-memory,--max-memory=1966080 + LINKER:--export=wasi_thread_start + LINKER:--export=malloc + LINKER:--export=free + ) +endfunction () + +compile_sample(no_pthread.c wasi_thread_start.S) \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasi-threads/wasm-apps/no_pthread.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasi-threads/wasm-apps/no_pthread.c new file mode 100644 index 00000000000..dc3c9553023 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasi-threads/wasm-apps/no_pthread.c @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2022 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 +#include +#include + +#include "wasi_thread_start.h" + +static const int64_t SECOND = 1000 * 1000 * 1000; + +typedef struct { + start_args_t base; + int th_ready; + int value; + int thread_id; +} shared_t; + +void +__wasi_thread_start_C(int thread_id, int *start_arg) +{ + shared_t *data = (shared_t *)start_arg; + + printf("New thread ID: %d, starting parameter: %d\n", thread_id, + data->value); + + data->thread_id = thread_id; + data->value += 8; + printf("Updated value: %d\n", data->value); + + __atomic_store_n(&data->th_ready, 1, __ATOMIC_SEQ_CST); + __builtin_wasm_memory_atomic_notify(&data->th_ready, 1); +} + +int +main(int argc, char **argv) +{ + shared_t data = { { NULL }, 0, 52, -1 }; + int thread_id; + int ret = EXIT_SUCCESS; + + if (!start_args_init(&data.base)) { + printf("Stack allocation for thread failed\n"); + return EXIT_FAILURE; + } + + thread_id = __wasi_thread_spawn(&data); + if (thread_id < 0) { + printf("Failed to create thread: %d\n", thread_id); + ret = EXIT_FAILURE; + goto final; + } + + if (__builtin_wasm_memory_atomic_wait32(&data.th_ready, 0, SECOND) == 2) { + printf("Timeout\n"); + ret = EXIT_FAILURE; + goto final; + } + + printf("Thread completed, new value: %d, thread id: %d\n", data.value, + data.thread_id); + + assert(thread_id == data.thread_id); + +final: + start_args_deinit(&data.base); + + return ret; +} diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasi-threads/wasm-apps/wasi_thread_start.S b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasi-threads/wasm-apps/wasi_thread_start.S new file mode 100644 index 00000000000..ea8fd140062 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasi-threads/wasm-apps/wasi_thread_start.S @@ -0,0 +1,22 @@ +# A slightly modified copy of the wasi-libc implementation +# https://github.com/WebAssembly/wasi-libc/pull/376/ + .globaltype __stack_pointer, i32 + .functype __wasi_thread_start_C (i32, i32) -> () + + .globl wasi_thread_start + +wasi_thread_start: + .functype wasi_thread_start (i32, i32) -> () + + # Set up the minimum C environment. + # Note: offsetof(start_arg, stack) == 0 + local.get 1 # start_arg + i32.load 0 # stack + global.set __stack_pointer + + # Make the C function do the rest of work. + local.get 0 # tid + local.get 1 # start_arg + call __wasi_thread_start_C + + end_function \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasi-threads/wasm-apps/wasi_thread_start.h b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasi-threads/wasm-apps/wasi_thread_start.h new file mode 100644 index 00000000000..a46917d0a0d --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasi-threads/wasm-apps/wasi_thread_start.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2022 Amazon.com Inc. or its affiliates. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ +#ifndef WASI_THREAD_START_H +#define WASI_THREAD_START_H + +#define STACK_SIZE 32 * 1024 // same as the main stack + +typedef struct { + void *stack; +} start_args_t; + +static inline int +start_args_init(start_args_t *start_args) +{ + start_args->stack = malloc(STACK_SIZE); + if (!start_args->stack) { + return 0; + } + + start_args->stack += STACK_SIZE; + return 1; +} + +static inline void +start_args_deinit(start_args_t *start_args) +{ + free(start_args->stack - STACK_SIZE); +} + +#endif \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api-imports/.gitignore b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api-imports/.gitignore new file mode 100644 index 00000000000..ab998a6eb6a --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api-imports/.gitignore @@ -0,0 +1,2 @@ +/wasm/inc/** +!/wasm/inc/.* diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api-imports/CMakeLists.txt b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api-imports/CMakeLists.txt new file mode 100644 index 00000000000..1325e110cb8 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api-imports/CMakeLists.txt @@ -0,0 +1,174 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required(VERSION 3.14) +project(how-to-deal-with-import) + +include(CMakePrintHelpers) +include(CTest) +include(ExternalProject) +include(FetchContent) + +# +# dependencies +# +set(WAMR_ROOT ${CMAKE_CURRENT_LIST_DIR}/../../) +# wasm required headers +execute_process( + COMMAND ${CMAKE_COMMAND} -E copy_if_different + ${WARM_ROOT}/${WAMR_ROOT}/wamr-sdk/app/libc-builtin-sysroot/include/pthread.h + ${CMAKE_CURRENT_LIST_DIR}/wasm/inc +) + +# vmlib +################ runtime settings ################ +string (TOLOWER ${CMAKE_HOST_SYSTEM_NAME} WAMR_BUILD_PLATFORM) +if (APPLE) + add_definitions(-DBH_PLATFORM_DARWIN) +endif () + +# Resetdefault linker flags +set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") +set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") + +# WAMR features switch + +# Set WAMR_BUILD_TARGET, currently values supported: +# "X86_64", "AMD_64", "X86_32", "AARCH64[sub]", "ARM[sub]", "THUMB[sub]", +# "MIPS", "XTENSA", "RISCV64[sub]", "RISCV32[sub]" +if (NOT DEFINED WAMR_BUILD_TARGET) + if (CMAKE_SYSTEM_PROCESSOR MATCHES "^(arm64|aarch64)") + set (WAMR_BUILD_TARGET "AARCH64") + elseif (CMAKE_SYSTEM_PROCESSOR STREQUAL "riscv64") + set (WAMR_BUILD_TARGET "RISCV64") + elseif (CMAKE_SIZEOF_VOID_P EQUAL 8) + # Build as X86_64 by default in 64-bit platform + set (WAMR_BUILD_TARGET "X86_64") + elseif (CMAKE_SIZEOF_VOID_P EQUAL 4) + # Build as X86_32 by default in 32-bit platform + set (WAMR_BUILD_TARGET "X86_32") + else () + message(SEND_ERROR "Unsupported build target platform!") + endif () +endif () + +if (NOT CMAKE_BUILD_TYPE) + set (CMAKE_BUILD_TYPE Release) +endif () + +if (NOT DEFINED WAMR_BUILD_AOT) + # Enable AOT by default. + set (WAMR_BUILD_AOT 1) +endif () +if (NOT DEFINED WAMR_BUILD_INTERP) + # Disable Interpreter by default + set (WAMR_BUILD_INTERP 0) +endif () +set(WAMR_BUILD_JIT 0) +set(WAMR_BUILD_FAST_INTERP 1) +set(WAMR_BUILD_LIB_PTHREAD 1) +set(WAMR_BUILD_LIBC_BUILTIN 1) +set(WAMR_BUILD_LIBC_WASI 1) +set(WAMR_BUILD_SIMD 0) + +# compiling and linking flags +if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang")) + set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") +endif () +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wformat -Wformat-security") + +# build out vmlib +set(WAMR_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../..) +include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake) + +add_library(vmlib ${WAMR_RUNTIME_LIB_SOURCE}) +target_link_libraries(vmlib INTERFACE dl m pthread) +if(WAMR_BUILD_AOT EQUAL 1) + target_compile_definitions(vmlib INTERFACE -DWASM_ENABLE_AOT=1) +else() + target_compile_definitions(vmlib INTERFACE -DWASM_ENABLE_AOT=0) +endif() + +if(WAMR_BUILD_INTERP EQUAL 1) + target_compile_definitions(vmlib INTERFACE -DWASM_ENABLE_INTERP=1) +else() + target_compile_definitions(vmlib INTERFACE -DWASM_ENABLE_INTERP=0) +endif() + +if(CMAKE_BUILD_TYPE STREQUAL "Debug") + # ASAN + UBSAN + target_compile_options(vmlib INTERFACE -fsanitize=address,undefined) + target_link_options(vmlib INTERFACE -fsanitize=address,undefined) +endif() + +# # MSAN +# target_compile_options(vmlib INTERFACE -fsanitize=memory -fno-optimize-sibling-calls -fsanitize-memory-track-origins=2 -fno-omit-frame-pointer) +# target_link_options(vmlib INTERFACE -fsanitize=memory) + +# wamrc +if(WAMR_BUILD_AOT EQUAL 1 AND WAMR_BUILD_INTERP EQUAL 0) + ExternalProject_Add(wamrc + PREFIX wamrc-build + SOURCE_DIR ${WAMR_ROOT}/wamr-compiler + CONFIGURE_COMMAND ${CMAKE_COMMAND} -S ${WAMR_ROOT}/wamr-compiler -B build + BUILD_COMMAND ${CMAKE_COMMAND} --build build --target wamrc + INSTALL_COMMAND ${CMAKE_COMMAND} -E copy_if_different build/wamrc ${CMAKE_CURRENT_BINARY_DIR}/wamrc + ) +endif() + +# +# host +add_subdirectory(host) +add_custom_target( + install_host ALL + COMMAND ${CMAKE_COMMAND} -E copy_if_different ./host/example1 . + DEPENDS example1 + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} +) + +# TODO: replace it with a find_package() +set(WASI_SDK_DIR /opt/wasi-sdk-19.0/) +set(WASI_TOOLCHAIN_FILE ${WASI_SDK_DIR}/share/cmake/wasi-sdk.cmake) +set(WASI_SYS_ROOT ${WASI_SDK_DIR}/share/wasi-sysroot) + +# +# wasm +if(WAMR_BUILD_AOT EQUAL 1 AND WAMR_BUILD_INTERP EQUAL 0) + ExternalProject_Add(wasm + PREFIX wasm-build + DEPENDS wamrc + BUILD_ALWAYS TRUE + SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/wasm + CONFIGURE_COMMAND ${CMAKE_COMMAND} -S ${CMAKE_CURRENT_LIST_DIR}/wasm -B build + -DWASI_SDK_PREFIX=${WASI_SDK_DIR} + -DCMAKE_TOOLCHAIN_FILE=${WASI_TOOLCHAIN_FILE} + -DCMAKE_SYSROOT=${WASI_SYS_ROOT} + -DWASM_TO_AOT=ON + -DWAMRC_PATH=${CMAKE_CURRENT_BINARY_DIR}/wamrc + -DSOCKET_WASI_CMAKE=${WAMR_ROOT}/core/iwasm/libraries/lib-socket/lib_socket_wasi.cmake + BUILD_COMMAND ${CMAKE_COMMAND} --build build + INSTALL_COMMAND ${CMAKE_COMMAND} --install build --prefix ${CMAKE_CURRENT_BINARY_DIR} + ) +else() + ExternalProject_Add(wasm + PREFIX wasm-build + BUILD_ALWAYS TRUE + SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/wasm + CONFIGURE_COMMAND ${CMAKE_COMMAND} -S ${CMAKE_CURRENT_LIST_DIR}/wasm -B build + -DWASI_SDK_PREFIX=${WASI_SDK_DIR} + -DCMAKE_TOOLCHAIN_FILE=${WASI_TOOLCHAIN_FILE} + -DCMAKE_SYSROOT=${WASI_SYS_ROOT} + -DSOCKET_WASI_CMAKE=${WAMR_ROOT}/core/iwasm/libraries/lib-socket/lib_socket_wasi.cmake + BUILD_COMMAND ${CMAKE_COMMAND} --build build + INSTALL_COMMAND ${CMAKE_COMMAND} --install build --prefix ${CMAKE_CURRENT_BINARY_DIR} + ) +endif() + +# +# Test +# +add_test( + NAME run_example1 + COMMAND ./example1 + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} +) diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api-imports/README.md b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api-imports/README.md new file mode 100644 index 00000000000..9b61a6e744b --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api-imports/README.md @@ -0,0 +1,174 @@ +# How to create `imports` for wasm_instance_new() properly + +It's always been asked how to create `wasm_extern_vec_t *imports` for +`wasm_instance_new()`? + +```c +WASM_API_EXTERN own wasm_instance_t* wasm_instance_new( + wasm_store_t*, const wasm_module_t*, const wasm_extern_vec_t *imports, + own wasm_trap_t** trap +); +``` + +`wasm_extern_vec_t *imports` is required to match the requirement of _the +import section_ of a .wasm. + +```bash +$ /opt/wabt-1.0.31/bin/wasm-objdump -j Import -x .wasm + +Section Details: + +Import[27]: + - func[0] sig=2 <- env.pthread_mutex_lock + - func[1] sig=2 <- env.pthread_mutex_unlock + - func[2] sig=2 <- env.pthread_cond_signal + - func[3] sig=3 <- env.log + ... + - func[11] sig=4 <__imported_wasi_snapshot_preview1_sock_bind> <- wasi_snapshot_preview1.sock_bind + - func[12] sig=4 <__imported_wasi_snapshot_preview1_sock_connect> <- wasi_snapshot_preview1.sock_connect + - func[13] sig=4 <__imported_wasi_snapshot_preview1_sock_listen> <- wasi_snapshot_preview1.sock_listen + - func[14] sig=5 <__imported_wasi_snapshot_preview1_sock_open> <- wasi_snapshot_preview1.sock_open + - func[15] sig=4 <__imported_wasi_snapshot_preview1_sock_addr_remote> <- wasi_snapshot_preview1.sock_addr_remote + - func[16] sig=4 <__imported_wasi_snapshot_preview1_args_get> <- wasi_snapshot_preview1.args_get + - func[17] sig=4 <__imported_wasi_snapshot_preview1_args_sizes_get> <- wasi_snapshot_preview1.args_sizes_get + ... +``` + +Developers should fill in _imports_ with enough host functions and make sure +there are no linking problems during instantiation. + +```bash +TODO: linking warnings +``` + +## A natural way + +One natural answer is "to create a list which matches every item in _the import +section_" of the .wasm. Since developers can see the section details of +a .wasm by tools like _wasm-objdump_, the answer is doable. Most of the time, +if they also prepare Wasm modules, developers have full control over import +requirements, and they only need to take a look at the order of _the import +section_. + +Yes, _the order_. A proper `wasm_extern_vec_t *imports` includes two things: + +1. how many `wasm_extern_t` +2. and order of those + +Because there is no "name information" in a `wasm_extern_t`. The only way is let +`wasm_instance_new()` to tell which item in _the import section_ of a .wasm +should match any item in `wasm_extern_vec_t *imports` is based on **_index_**. + +The algorithm is quite straightforward. The first one of _the import section_ matches +`wasm_extern_vec_t *imports->data[0] `. The second one matches `wasm_extern_vec_t *imports->data[1]`. +And so on. + +So the order of `wasm_extern_vec_t *imports` becomes quite a burden. It requires +developers always checking _the import section_ visually. + +Until here, the natural way is still workable although involving some handy work. +Right? + +## A blocker + +Sorry, the situation changes a lot when driving wasm32-wasi Wasm modules with +wasm-c-api. + +As you know, WASI provides _a set of crossing-platform standard libraries_ for +Wasm modules, and leaves some _interfaces_ for native platform-dependent supports. +Those _interfaces_ are those import items with the module name `wasi_snapshot_preview1` +in a Wasm module. + +It seems not economical to let developers provide their version of host +implementations of the `wasi_snapshot_preview1.XXX` functions. All those support +should be packed into a common library and shared in different Wasm modules. +Like a [cargo WASI](https://github.com/bytecodealliance/cargo-wasi). + +WAMR chooses to integrate the WASI support library in the runtime to reduce +developers' compilation work. It brings developers a new thing of a proper +`wasm_extern_vec_t *imports` that developers should avoid overwriting those items +of _the import section_ of a Wasm module that will be provided by the runtime. It +also not economical to code for those functions. + +Using module names as a filter seems to be a simple way. But some private +additional c/c++ libraries are supported in WAMR. Those supporting will bring +more import items that don't use `wasi_snapshot_preview1` as module names but are still +covered by the WASM runtime. Like `env.pthread_`. Plus, [the native lib registeration](https://github.com/bytecodealliance/wasm-micro-runtime/blob/main/doc/export_native_api.md) +provides another possible way to fill in the requirement of _the import section_. + +Let's take summarize. A proper `wasm_extern_vec_t *imports` should include: + +1. provides all necessary host implementations for items in _the import section_ +2. should not override runtime provided implementation or covered by native + registrations. functinal or econmical. +3. keep them in a right order + +## A recommendation + +The recommendation is: + +- use `wasm_module_imports()` to build the order +- use `wasm_importtype_is_linked()` to avoid overwriting + +[wasm-c-api-imports](.) is a simple showcase of how to do that. + +First, let's take a look at the Wasm module. [send_recv](./wasm/send_recv.c) +uses both standard WASI and WAMR_BUILD_LIB_PTHREAD supporting. Plus a private +native function `host_log`. + +So, `wasm_extern_vec_t *imports` should only include the host implementation of +`host_log` and avoid WASI related(`wasm-c-api-imports.XXX`) and pthread related(`env.pthread_XXX`). + +[Here is how to do](./host/example1.c): + +- get import types with `wasm_module_imports(0)`. it contains name information + +```c + wasm_importtype_vec_t importtypes = { 0 }; + wasm_module_imports(module, &importtypes); +``` + +- traversal import types. The final `wasm_importvec_t *imports` should have the + same order with `wasm_importtype_vec_t` + +```c + for (unsigned i = 0; i < importtypes.num_elems; i++) +``` + +- use `wasm_importtype_is_linked()` to avoid those covered by the runtime and + registered natives. A little tip is use "wasm_extern_new_empty()" to create + a placeholder. + +```c + /* use wasm_extern_new_empty() to create a placeholder */ + if (wasm_importtype_is_linked(importtype)) { + externs[i] = wasm_extern_new_empty( + store, wasm_externtype_kind(wasm_importtype_type(importtype))); + continue; + } +``` + +- use `wasm_importtype_module()` to get the module name, use `wasm_importtype_name()` + to get the field name. + +```c + const wasm_name_t *module_name = + wasm_importtype_module(importtypes.data[i]); + const wasm_name_t *field_name = + wasm_importtype_name(importtypes.data[i]); +``` + +- fill in `wasm_externvec_t *imports` dynamically and programmatically. + +```c + if (strncmp(module_name->data, "env", strlen("env")) == 0 + && strncmp(field_name->data, "log", strlen("log")) == 0) { + wasm_functype_t *log_type = wasm_functype_new_2_0( + wasm_valtype_new_i64(), wasm_valtype_new_i32()); + wasm_func_t *log_func = wasm_func_new(store, log_type, host_logs); + wasm_functype_delete(log_type); + + externs[i] = wasm_func_as_extern(log_func); + } + } +``` diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api-imports/host/CMakeLists.txt b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api-imports/host/CMakeLists.txt new file mode 100644 index 00000000000..e2636f09e12 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api-imports/host/CMakeLists.txt @@ -0,0 +1,12 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required(VERSION 3.14) +project(host) + +set(CMAKE_BUILD_TYPE Debug) + +# +# host +add_executable(example1 ./example1.c) +target_link_libraries(example1 vmlib) diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api-imports/host/example1.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api-imports/host/example1.c new file mode 100644 index 00000000000..ccf574d7946 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api-imports/host/example1.c @@ -0,0 +1,204 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include +#include +#include "wasm_c_api.h" +#include "wasm_export.h" + +static wasm_trap_t * +host_logs(const wasm_val_vec_t *args, wasm_val_vec_t *results) +{ + return NULL; +} + +static bool +build_imports(wasm_store_t *store, const wasm_module_t *module, + wasm_extern_vec_t *out) +{ + wasm_importtype_vec_t importtypes = { 0 }; + wasm_module_imports(module, &importtypes); + + wasm_extern_t *externs[32] = { 0 }; + + for (unsigned i = 0; i < importtypes.num_elems; i++) { + wasm_importtype_t *importtype = importtypes.data[i]; + + /* use wasm_extern_new_empty() to create a placeholder */ + if (wasm_importtype_is_linked(importtype)) { + externs[i] = wasm_extern_new_empty( + store, wasm_externtype_kind(wasm_importtype_type(importtype))); + continue; + } + + const wasm_name_t *module_name = + wasm_importtype_module(importtypes.data[i]); + const wasm_name_t *field_name = + wasm_importtype_name(importtypes.data[i]); + + if (strncmp(module_name->data, "env", strlen("env")) == 0 + && strncmp(field_name->data, "log", strlen("log")) == 0) { + wasm_functype_t *log_type = wasm_functype_new_2_0( + wasm_valtype_new_i64(), wasm_valtype_new_i32()); + wasm_func_t *log_func = wasm_func_new(store, log_type, host_logs); + wasm_functype_delete(log_type); + + externs[i] = wasm_func_as_extern(log_func); + } + } + + wasm_extern_vec_new(out, importtypes.num_elems, externs); + wasm_importtype_vec_delete(&importtypes); + return true; +} + +int +main() +{ + int main_ret = EXIT_FAILURE; + + // Initialize. + printf("Initializing...\n"); + wasm_engine_t *engine = wasm_engine_new(); + if (!engine) + goto quit; + + wasm_store_t *store = wasm_store_new(engine); + if (!store) + goto delete_engine; + + // Load binary. + printf("Loading binary...\n"); +#if WASM_ENABLE_AOT != 0 && WASM_ENABLE_INTERP == 0 + FILE *file = fopen("send_recv.aot", "rb"); + printf("> Load .aot\n"); +#else + FILE *file = fopen("send_recv.wasm", "rb"); + printf("> Load .wasm\n"); +#endif + if (!file) { + printf("> Error loading module!\n"); + goto delete_store; + } + + int ret = fseek(file, 0L, SEEK_END); + if (ret == -1) { + printf("> Error loading module!\n"); + goto close_file; + } + + long file_size = ftell(file); + if (file_size == -1) { + printf("> Error loading module!\n"); + goto close_file; + } + + ret = fseek(file, 0L, SEEK_SET); + if (ret == -1) { + printf("> Error loading module!\n"); + goto close_file; + } + + wasm_byte_vec_t binary; + wasm_byte_vec_new_uninitialized(&binary, file_size); + + if (fread(binary.data, file_size, 1, file) != 1) { + printf("> Error loading module!\n"); + goto delete_binary; + } + + // Compile. + printf("Compiling module...\n"); + wasm_module_t *module = wasm_module_new(store, &binary); + if (!module) { + printf("> Error compiling module!\n"); + goto delete_binary; + } + + // Set Wasi Context + const char *addr_pool[1] = { "127.0.0.1" }; + wasm_runtime_set_wasi_addr_pool(*module, addr_pool, 1); + + // Instantiate. + printf("Instantiating module...\n"); + wasm_extern_vec_t imports = { 0 }; + ret = build_imports(store, module, &imports); + if (!ret) { + printf("> Error building imports!\n"); + goto delete_module; + } + + wasm_instance_t *instance = + wasm_instance_new(store, module, &imports, NULL); + if (!instance) { + printf("> Error instantiating module!\n"); + goto delete_imports; + } + + // Extract export. + printf("Extracting export...\n"); + wasm_extern_vec_t exports; + wasm_instance_exports(instance, &exports); + if (exports.size == 0) { + printf("> Error accessing exports!\n"); + goto delete_instance; + } + + /** + * should use information from wasm_module_exports to avoid hard coding "1" + */ + const wasm_func_t *start_func = wasm_extern_as_func(exports.data[1]); + if (start_func == NULL) { + printf("> Error accessing export!\n"); + goto delete_exports; + } + + // Call. "_start(nil) -> i32" + printf("Calling _start ...\n"); + wasm_val_t rs[1] = { WASM_I32_VAL(0) }; + wasm_val_vec_t args = WASM_EMPTY_VEC; + wasm_val_vec_t results = WASM_ARRAY_VEC(rs); + wasm_trap_t *trap = wasm_func_call(start_func, &args, &results); + if (trap) { + wasm_name_t message = { 0 }; + wasm_trap_message(trap, &message); + + printf("> Error calling function! %s\n", message.data); + + wasm_name_delete(&message); + wasm_trap_delete(trap); + goto delete_exports; + } + + // Print result. + printf("Printing result...\n"); + printf("> %u\n", rs[0].of.i32); + + // Shut down. + printf("Shutting down...\n"); + + // All done. + printf("Done.\n"); + main_ret = EXIT_SUCCESS; + +delete_exports: + wasm_extern_vec_delete(&exports); +delete_instance: + wasm_instance_delete(instance); +delete_imports: + wasm_extern_vec_delete(&imports); +delete_module: + wasm_module_delete(module); +delete_binary: + wasm_byte_vec_delete(&binary); +close_file: + fclose(file); +delete_store: + wasm_store_delete(store); +delete_engine: + wasm_engine_delete(engine); +quit: + return main_ret; +} \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api-imports/wasm/CMakeLists.txt b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api-imports/wasm/CMakeLists.txt new file mode 100644 index 00000000000..6b2743cb5b4 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api-imports/wasm/CMakeLists.txt @@ -0,0 +1,47 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required (VERSION 3.14) +project(wasm_modules) + +if(NOT SOCKET_WASI_CMAKE) + message(FATAL_ERROR "Require SOCKET_WASI_CMAKE") +endif() + +option(WASM_TO_AOT "transfer wasm to aot" OFF) +if(WASM_TO_AOT AND NOT WAMRC_PATH) + message(FATAL_ERROR "Require WAMRC_PATH when WASM_TO_AOT is ON") +endif() + +# +# c -> wasm +include(${SOCKET_WASI_CMAKE}) +add_executable(send_recv ${CMAKE_CURRENT_LIST_DIR}/send_recv.c) +set_target_properties(send_recv PROPERTIES SUFFIX .wasm) +target_include_directories(send_recv PUBLIC ${CMAKE_CURRENT_LIST_DIR}/inc) +target_link_libraries(send_recv socket_wasi_ext) +target_link_options(send_recv PRIVATE + LINKER:--export=__heap_base + LINKER:--export=__data_end + LINKER:--shared-memory,--max-memory=196608 + LINKER:--no-check-features + LINKER:--allow-undefined +) + +if(WASM_TO_AOT) + # wasm -> aot + add_custom_target(send_recv_aot ALL + COMMAND pwd && ${WAMRC_PATH} --enable-multi-thread -o ./send_recv.aot ./send_recv.wasm + DEPENDS send_recv + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + ) +endif() + +# +# install +if(WASM_TO_AOT) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/send_recv.aot DESTINATION . ) +else() + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/send_recv.wasm DESTINATION . ) +endif() + diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/README.md b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api-imports/wasm/inc/.gitkeep similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/core/iwasm/README.md rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api-imports/wasm/inc/.gitkeep diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api-imports/wasm/send_recv.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api-imports/wasm/send_recv.c new file mode 100644 index 00000000000..d9f95573a52 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api-imports/wasm/send_recv.c @@ -0,0 +1,244 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef __wasi__ +#include +#include "pthread.h" +#else +#include +#endif + +static pthread_mutex_t lock = { 0 }; +static pthread_cond_t cond = { 0 }; +static bool server_create_failed = false; +static bool server_is_ready = false; + +#ifdef __wasi__ +__attribute__((import_name("log"))) extern void +host_log(uint64_t message, uint32_t length); +#endif + +static void +local_printf(const char *formatter, ...) +{ + char buffer[128] = { 0 }; + va_list args; + + va_start(args, formatter); + vsnprintf(buffer, 128, formatter, args); + va_end(args); + +#ifdef __wasi__ + host_log((uint64_t)(void *)buffer, strlen(buffer)); +#endif + printf("--> %s", buffer); +} + +void * +run_as_server(void *arg) +{ + int sock = -1, on = 1; + struct sockaddr_in addr = { 0 }; + int addrlen = 0; + int new_sock = -1; + char *buf[] = { + "The stars shine down", "It brings us light", "Light comes down", + "To make us paths", "It watches us", "And mourns for us", + }; + struct iovec iov[] = { + { .iov_base = buf[0], .iov_len = strlen(buf[0]) + 1 }, + { .iov_base = buf[1], .iov_len = strlen(buf[1]) + 1 }, + { .iov_base = buf[2], .iov_len = strlen(buf[2]) + 1 }, + { .iov_base = buf[3], .iov_len = strlen(buf[3]) + 1 }, + { .iov_base = buf[4], .iov_len = strlen(buf[4]) + 1 }, + { .iov_base = buf[5], .iov_len = strlen(buf[5]) + 1 }, + }; + struct msghdr msg = { .msg_iov = iov, .msg_iovlen = 6 }; + ssize_t send_len = 0; + + pthread_mutex_lock(&lock); + sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock < 0) { + server_create_failed = true; + pthread_cond_signal(&cond); + pthread_mutex_unlock(&lock); + perror("Create a socket failed"); + return NULL; + } + +#ifndef __wasi__ + if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on))) { + server_create_failed = true; + pthread_cond_signal(&cond); + pthread_mutex_unlock(&lock); + perror("Setsockopt failed"); + goto fail1; + } +#endif + + /* 0.0.0.0:1234 */ + addr.sin_family = AF_INET; + addr.sin_port = htons(1234); + addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + + addrlen = sizeof(addr); + if (bind(sock, (struct sockaddr *)&addr, addrlen) < 0) { + server_create_failed = true; + pthread_cond_signal(&cond); + pthread_mutex_unlock(&lock); + perror("Bind failed"); + goto fail1; + } + + if (listen(sock, 0) < 0) { + server_create_failed = true; + pthread_cond_signal(&cond); + pthread_mutex_unlock(&lock); + perror("Listen failed"); + goto fail1; + } + + server_is_ready = true; + pthread_cond_signal(&cond); + pthread_mutex_unlock(&lock); + + local_printf("Server is online ... \n"); + + new_sock = accept(sock, (struct sockaddr *)&addr, (socklen_t *)&addrlen); + if (new_sock < 0) { + perror("Accept failed"); + goto fail1; + } + + local_printf("Start sending. \n"); + send_len = sendmsg(new_sock, &msg, 0); + if (send_len < 0) { + perror("Sendmsg failed"); + goto fail2; + } + local_printf("Send %ld bytes successfully!\n", send_len); + +fail2: + close(new_sock); +fail1: + shutdown(sock, SHUT_RD); + close(sock); + return NULL; +} + +void * +run_as_client(void *arg) +{ + int sock = -1; + struct sockaddr_in addr = { 0 }; + /* buf of server is 106 bytes */ + char buf[110] = { 0 }; + struct iovec iov = { .iov_base = buf, .iov_len = sizeof(buf) }; + struct msghdr msg = { .msg_iov = &iov, .msg_iovlen = 1 }; + ssize_t recv_len = 0; + + pthread_mutex_lock(&lock); + while (!server_create_failed && !server_is_ready) { + pthread_cond_wait(&cond, &lock); + } + pthread_mutex_unlock(&lock); + + if (server_create_failed) { + return NULL; + } + + local_printf("Client is running...\n"); + sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock < 0) { + perror("Create a socket failed"); + return NULL; + } + + /* 127.0.0.1:1234 */ + addr.sin_family = AF_INET; + addr.sin_port = htons(1234); + addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + + if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + perror("Connect failed"); + goto fail; + } + + local_printf("Start receiving. \n"); + recv_len = recvmsg(sock, &msg, 0); + if (recv_len < 0) { + perror("Recvmsg failed"); + goto fail; + } + + local_printf("Receive %ld bytes successlly!\n", recv_len); + assert(recv_len == 106); + + local_printf("Data:\n"); + char *s = msg.msg_iov->iov_base; + while (strlen(s) > 0) { + local_printf(" %s\n", s); + s += strlen(s) + 1; + } + +fail: + shutdown(sock, SHUT_RD); + close(sock); + return NULL; +} + +int +main(int argc, char *argv[]) +{ + pthread_t cs[2] = { 0 }; + uint8_t i = 0; + int ret = EXIT_SUCCESS; + + if (pthread_mutex_init(&lock, NULL)) { + perror("Initialize mutex failed"); + ret = EXIT_FAILURE; + goto RETURN; + } + + if (pthread_cond_init(&cond, NULL)) { + perror("Initialize condition failed"); + ret = EXIT_FAILURE; + goto DESTROY_MUTEX; + } + + if (pthread_create(&cs[0], NULL, run_as_server, NULL)) { + perror("Create a server thread failed"); + ret = EXIT_FAILURE; + goto DESTROY_COND; + } + + if (pthread_create(&cs[1], NULL, run_as_client, NULL)) { + perror("Create a client thread failed"); + ret = EXIT_FAILURE; + goto DESTROY_COND; + } + + for (i = 0; i < 2; i++) { + pthread_join(cs[i], NULL); + } + +DESTROY_COND: + pthread_cond_destroy(&cond); +DESTROY_MUTEX: + pthread_mutex_destroy(&lock); +RETURN: + return ret; +} diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/CMakeLists.txt b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/CMakeLists.txt similarity index 72% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/CMakeLists.txt rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/CMakeLists.txt index 63fb06e74fe..c528fe16d6f 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/CMakeLists.txt +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/CMakeLists.txt @@ -1,7 +1,9 @@ # Copyright (C) 2019 Intel Corporation. All rights reserved. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -cmake_minimum_required (VERSION 2.9) +cmake_minimum_required (VERSION 3.14) + +include(CheckPIESupported) if (NOT WAMR_BUILD_PLATFORM STREQUAL "windows") project(c-api) @@ -22,7 +24,7 @@ if (APPLE) add_definitions(-DBH_PLATFORM_DARWIN) endif () -# Resetdefault linker flags +# Reset default linker flags set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") @@ -71,7 +73,6 @@ endif() if (NOT MSVC) # compiling and linking flags - set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pie -fPIE") if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang")) set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") endif () @@ -86,11 +87,24 @@ endif() set(WAMR_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../..) include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake) +if (NOT DEFINED SANITIZER) + set(SANITIZER "") +elseif (SANITIZER STREQUAL "ubsan") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O2 -fno-omit-frame-pointer -fsanitize=undefined -fno-sanitize-recover=all -fno-sanitize=alignment" ) + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=undefined") +elseif (NOT (SANITIZER STREQUAL "") ) + message(SEND_ERROR "Unsupported sanitizer: ${SANITIZER}") +endif() + add_library(vmlib STATIC ${WAMR_RUNTIME_LIB_SOURCE}) if (MSVC) target_compile_definitions(vmlib PRIVATE WASM_API_EXTERN=) endif() target_link_libraries (vmlib ${LLVM_AVAILABLE_LIBS} ${UV_A_LIBS} -lm -ldl -lpthread) + +if (WAMR_BUILD_WASM_CACHE EQUAL 1) + target_link_libraries(vmlib boringssl_crypto) +endif () ################################################ ################ application related ################ @@ -103,8 +117,17 @@ find_program(WAT2WASM if(NOT WAT2WASM) message(SEND_ERROR "can not find wat2wasm") +else () + execute_process(COMMAND ${WAT2WASM} --version + OUTPUT_VARIABLE WAT2WASM_VERSION_OUTPUT) + string(STRIP ${WAT2WASM_VERSION_OUTPUT} WAT2WASM_VERSION) + message("-- Found wat2wasm ${WAT2WASM_VERSION}") endif() +if (${WAT2WASM_VERSION} VERSION_LESS 1.0.26) + set(WAT2WASM_FLAGS "--enable-reference-types") +endif () + if(${WAMR_BUILD_AOT} EQUAL 1) ## locate wamrc find_program(WAMRC @@ -122,25 +145,26 @@ include (${SHARED_DIR}/utils/uncommon/shared_uncommon.cmake) set(MM_UTIL src/utils/multi_module_utils.c) # build executable for each .c -set(EXAMPLES - callback - callback_chain - empty_imports - global - hello - hostref - memory - reflect - table - trap -) +list(APPEND EXAMPLES callback callback_chain empty_imports global hello hostref memory reflect table trap) +# FIXME enable both in the future +#list(APPEND EXAMPLES clone threads) +# FIXME +# if(WAMR_BUILD_JIT EQUAL 1 AND WAMR_BUILD_LAZY_JIT EQUAL 0) +# list(APPEND EXAMPLES serialize) +# endif() + +check_pie_supported() + +include(CTest) +enable_testing() foreach(EX ${EXAMPLES}) set(SRC ${CMAKE_CURRENT_LIST_DIR}/src/${EX}.c) add_executable(${EX} ${SRC} ${UNCOMMON_SHARED_SOURCE} ${MM_UTIL}) + set_target_properties (${EX} PROPERTIES POSITION_INDEPENDENT_CODE ON) target_include_directories(${EX} PRIVATE ${UNCOMMON_SHARED_DIR}) - target_link_libraries(${EX} vmlib -lpthread -lm) + target_link_libraries(${EX} vmlib) if (MSVC) target_compile_definitions(${EX} PRIVATE WASM_API_EXTERN=) endif() @@ -149,7 +173,7 @@ foreach(EX ${EXAMPLES}) set(WAT ${CMAKE_CURRENT_LIST_DIR}/src/${EX}.wat) add_custom_target(${EX}_WASM - COMMAND ${WAT2WASM} ${WAT} --enable-reference-types -o ${PROJECT_BINARY_DIR}/${EX}.wasm + COMMAND ${WAT2WASM} ${WAT} ${WAT2WASM_FLAGS} -o ${PROJECT_BINARY_DIR}/${EX}.wasm DEPENDS ${WAT} BYPRODUCTS ${PROJECT_BINARY_DIR}/${EX}.wasm VERBATIM @@ -168,6 +192,12 @@ foreach(EX ${EXAMPLES}) ) add_dependencies(${EX} ${EX}_AOT) endif() + + # run `ctest --test-dir build` + add_test(NAME Test_${EX} + COMMAND ./${EX} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + ) endforeach() if (CMAKE_BUILD_TYPE STREQUAL "Debug") @@ -176,14 +206,5 @@ if (CMAKE_BUILD_TYPE STREQUAL "Debug") REQUIRED ) - if(VALGRIND) - foreach(EX ${EXAMPLES}) - add_custom_target(${EX}_LEAK_TEST - COMMAND ${VALGRIND} --tool=memcheck --leak-check=yes ./${EX} - DEPENDS ${EX} ${EX}_WASM - VERBATIM - COMMENT "run a leak check on ${EX}" - ) - endforeach() - endif (VALGRIND) -endif (CMAKE_BUILD_TYPE STREQUAL "Debug") + # run `ctest -T memcheck -V --test-dir build` +endif() diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/README.md b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/README.md similarity index 91% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/README.md rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/README.md index 51b8642a262..b2327670611 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/README.md +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/README.md @@ -4,9 +4,9 @@ Before staring, we need to download and intall [WABT](https://github.com/WebAsse ``` shell $ cd /opt -$ wget https://github.com/WebAssembly/wabt/releases/download/1.0.19/wabt-1.0.19-ubuntu.tar.gz -$ tar -xzf wabt-1.0.19-ubuntu.tar.gz -$ mv wabt-1.0.19 wabt +$ wget https://github.com/WebAssembly/wabt/releases/download/1.0.31/wabt-1.0.31-ubuntu.tar.gz +$ tar -xzf wabt-1.0.31-ubuntu.tar.gz +$ mv wabt-1.0.31 wabt ``` By default, all samples are compiled and run in "interpreter" mode. @@ -47,4 +47,4 @@ $ ./global $ ... $ ./callback $ ... -``` \ No newline at end of file +``` diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/src/LICENSE b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/LICENSE similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/src/LICENSE rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/LICENSE diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/src/callback.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/callback.c similarity index 96% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/src/callback.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/callback.c index b1294670d30..ccb9ec0675c 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/src/callback.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/callback.c @@ -169,9 +169,11 @@ int main(int argc, const char* argv[]) { wasm_val_t rs[1] = { WASM_INIT_VAL }; wasm_val_vec_t args = WASM_ARRAY_VEC(as); wasm_val_vec_t results = WASM_ARRAY_VEC(rs); - if (wasm_func_call(run_func, &args, &results)) { - printf("> Error calling function!\n"); - return 1; + wasm_trap_t *trap = wasm_func_call(run_func, &args, &results); + if (trap) { + printf("> Error calling function!\n"); + wasm_trap_delete(trap); + return 1; } wasm_extern_vec_delete(&exports); diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/src/callback.wat b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/callback.wat similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/src/callback.wat rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/callback.wat diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/src/callback_chain.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/callback_chain.c similarity index 99% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/src/callback_chain.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/callback_chain.c index 13b86ecc657..e4f5801dc15 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/src/callback_chain.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/callback_chain.c @@ -238,7 +238,7 @@ main(int argc, const char *argv[]) IMPORT_FUNCTION_LIST(CREATE_WASM_FUNCTION) #undef CREATE_WASM_FUNCTION - wasm_extern_t *fs[10] = { 0 }; + wasm_extern_t *fs[2] = { 0 }; #define ADD_TO_FUNCTION_LIST(name, index, ...) \ fs[index] = wasm_func_as_extern(function_##name); IMPORT_FUNCTION_LIST(ADD_TO_FUNCTION_LIST) diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/src/callback_chain.wat b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/callback_chain.wat similarity index 93% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/src/callback_chain.wat rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/callback_chain.wat index b29cf8a4e08..80bbf4f74b3 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/src/callback_chain.wat +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/callback_chain.wat @@ -3,7 +3,7 @@ (module (func $get_pairs (import "" "get_pairs") (result i32)) - (func $log (import"" "log") (param i32 i32)) + (func $log (import "" "log") (param i32 i32)) (func $on_start (export "on_start") (call $log (i32.const 0) (i32.const 9)) @@ -29,4 +29,4 @@ (data (i32.const 9) "on_stop") (data (i32.const 17) "malloc") (data (i32.const 24) "free") -) \ No newline at end of file +) diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/clone.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/clone.c new file mode 100644 index 00000000000..da83b379066 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/clone.c @@ -0,0 +1,535 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +#include +#include +#include +#include +#include + +#include "wasm_c_api.h" + +#define WORKER_NUMBER 10 + +/******************************* VM *******************************/ +/* Use wasm_vm_t and vm_xxx to simulate a minimal Wasm VM in Envoy */ + +typedef struct _vm { + wasm_engine_t *engine; + wasm_store_t *store; + wasm_module_t *module; + wasm_shared_module_t *shared_module; + wasm_instance_t *instance; + wasm_func_t **function_list; + wasm_memory_t *memory; + wasm_table_t *table; + wasm_extern_vec_t *exports; +} wasm_vm_t; + +typedef enum _clone_level { + not_cloneable = 0, + compiled_bytecode, + instantiated_module +} clone_level; + +typedef struct _thread_arg_t { + char name[32]; + bool *ready_go_flag; + pthread_mutex_t *ready_go_lock; + pthread_cond_t *ready_go_cond; + const wasm_vm_t *base_vm; +} thread_arg_t; + +wasm_vm_t * +vm_new() +{ + wasm_vm_t *vm = NULL; + + vm = malloc(sizeof(struct _vm)); + if (!vm) + goto fail; + + memset(vm, 0, sizeof(wasm_vm_t)); + + vm->engine = wasm_engine_new(); + if (!vm->engine) + goto fail; + + vm->store = wasm_store_new(vm->engine); + if (!vm->store) + goto fail; + + return vm; + +fail: + if (vm) { + if (vm->engine) + wasm_engine_delete(vm->engine); + + free(vm); + } + return NULL; +} + +wasm_vm_t * +vm_release(wasm_vm_t *vm) +{ + if (!vm) + return NULL; + + if (vm->function_list) { + free(vm->function_list); + vm->function_list = NULL; + } + + vm->memory = NULL; + + if (vm->exports) { + wasm_extern_vec_delete(vm->exports); + free(vm->exports); + vm->exports = NULL; + } + + wasm_instance_delete(vm->instance); + vm->instance = NULL; + + wasm_shared_module_delete(vm->shared_module); + vm->shared_module = NULL; + + wasm_module_delete(vm->module); + vm->module = NULL; + + wasm_store_delete(vm->store); + vm->store = NULL; + + wasm_engine_delete(vm->engine); + vm->engine = NULL; + + free(vm); + return NULL; +} + +bool +vm_load(wasm_vm_t *vm, const wasm_byte_vec_t *binary) +{ + vm->module = wasm_module_new(vm->store, binary); + vm->shared_module = wasm_module_share(vm->module); + return vm->module != NULL; +} + +bool +vm_link(wasm_vm_t *vm, wasm_extern_vec_t *imports) +{ + vm->instance = wasm_instance_new(vm->store, vm->module, imports, NULL); + if (!vm->instance) + goto fail; + + vm->exports = malloc(sizeof(wasm_extern_vec_t)); + if (!vm->exports) + goto fail; + + memset(vm->exports, 0, sizeof(wasm_extern_vec_t)); + wasm_instance_exports(vm->instance, vm->exports); + /* an exported memory, and two exported functions */ + assert(vm->exports->size == 3); + + /* bind memory */ + assert(wasm_extern_kind(vm->exports->data[0]) == WASM_EXTERN_MEMORY); + vm->memory = wasm_extern_as_memory(vm->exports->data[0]); + + vm->function_list = malloc(2 * sizeof(wasm_func_t *)); + if (!vm->function_list) + goto fail; + + memset(vm->function_list, 0, 2 * sizeof(wasm_func_t *)); + + /* bind wasm_set_byte(...) */ + assert(wasm_extern_kind(vm->exports->data[1]) == WASM_EXTERN_FUNC); + vm->function_list[0] = wasm_extern_as_func(vm->exports->data[1]); + + /* bind wasm_get_byte(...) */ + assert(wasm_extern_kind(vm->exports->data[2]) == WASM_EXTERN_FUNC); + vm->function_list[1] = wasm_extern_as_func(vm->exports->data[2]); + + return true; +fail: + return false; +} + +wasm_vm_t * +vm_clone_from_module(const wasm_vm_t *base) +{ + printf("Initializing...\n"); + wasm_vm_t *secondary = NULL; + + secondary = vm_new(); + if (secondary) { + printf("Reuse module and bypass vm_load()..."); + secondary->module = + wasm_module_obtain(base->store, base->shared_module); + if (!secondary->module) + secondary = vm_release(secondary); + } + + return secondary; +} + +wasm_vm_t * +vm_clone_from_instance(const wasm_vm_t *base) +{ + /** + * if do a clone of the level instantiated_module, need to malloc and + * initialie + * - global. WASMGlobalIntance and global data + * - memory. WAAMMemoryInstance, memory_data and heap + * - table. WASMTableInstance, table_data + * - exports. all global, memory and table + * + * it is almost everything in wasm_instantiate() except funciton. + */ + (void)base; + printf("Unsupported\n"); + return NULL; +} + +wasm_vm_t * +vm_clone(const wasm_vm_t *base, clone_level level) +{ + if (level == not_cloneable) + return NULL; + + if (level == compiled_bytecode) + return vm_clone_from_module(base); + else + return vm_clone_from_instance(base); +} + +bool +vm_memory_set_byte(const wasm_vm_t *vm, uint32_t offset, uint8_t byte) +{ + byte_t *data = wasm_memory_data(vm->memory); + assert(data); + *(data + offset) = byte; + return true; +} + +bool +vm_memory_get_byte(const wasm_vm_t *vm, uint32_t offset, uint8_t *byte) +{ + byte_t *data = wasm_memory_data(vm->memory); + assert(data); + *byte = *(data + offset); + return true; +} + +bool +vm_function_set_byte(const wasm_vm_t *vm, uint32_t offset, uint8_t byte) +{ + wasm_val_t a_v[2] = { WASM_I32_VAL(offset), WASM_I32_VAL(byte) }; + wasm_val_vec_t args = WASM_ARRAY_VEC(a_v); + wasm_val_vec_t results = WASM_EMPTY_VEC; + wasm_trap_t *trap = wasm_func_call(vm->function_list[0], &args, &results); + if (trap) { + printf("call wasm_set_byte failed"); + wasm_trap_delete(trap); + return false; + } + + return true; +} + +bool +vm_function_get_byte(const wasm_vm_t *vm, uint32_t offset, uint8_t *byte) +{ + wasm_val_t a_v[1] = { WASM_I32_VAL(offset) }; + wasm_val_vec_t args = WASM_ARRAY_VEC(a_v); + wasm_val_t r_v[1] = { WASM_INIT_VAL }; + wasm_val_vec_t results = WASM_ARRAY_VEC(r_v); + wasm_trap_t *trap = wasm_func_call(vm->function_list[1], &args, &results); + if (trap) { + printf("call wasm_get_byte failed"); + wasm_trap_delete(trap); + return false; + } + + assert(results.data->kind == WASM_I32); + *byte = results.data->of.i32; + return true; +} + +static bool +load_wasm_file_content(const char *file_name, wasm_byte_vec_t *out) +{ + bool ret = false; +#if WASM_ENABLE_AOT != 0 && WASM_ENABLE_INTERP == 0 + FILE *file = fopen(file_name, "rb"); +#else + FILE *file = fopen(file_name, "rb"); +#endif + if (!file) { + printf("> Error loading .wasm!\n"); + goto quit; + } + + int offset = fseek(file, 0L, SEEK_END); + if (offset == -1) { + printf("> Error loading .wasm!\n"); + goto close_file; + } + + long file_size = ftell(file); + if (file_size == -1) { + printf("> Error loading .wasm!\n"); + goto close_file; + } + + offset = fseek(file, 0L, SEEK_SET); + if (offset == -1) { + printf("> Error loading .wasm!\n"); + goto close_file; + } + + wasm_byte_vec_new_uninitialized(out, file_size); + if (fread(out->data, file_size, 1, file) != 1) { + printf("> Error loading content!\n"); + goto close_file; + } + + ret = true; +close_file: + fclose(file); +quit: + return ret; +} + +static pthread_key_t name_key; + +wasm_trap_t * +report_cb(const wasm_val_vec_t *args, wasm_val_vec_t *results) +{ + (void)results; + + assert(args->data[0].kind == WASM_I32); + uint32_t chk_pnt_no = args->data[0].of.i32; + + char *name = pthread_getspecific(name_key); + printf("[%s] Pass CHK POINT #%u\n", name, chk_pnt_no); + + return NULL; +} + +bool +run_code_start(wasm_vm_t **out) +{ + bool ret = false; + + printf("Initializing...\n"); + wasm_vm_t *vm = vm_new(); + if (!vm) + goto fail; + + printf("Loading binary...\n"); + wasm_byte_vec_t binary = { 0 }; +#if WASM_ENABLE_AOT != 0 && WASM_ENABLE_INTERP == 0 + const char *file_name = "clone.aot"; +#else + const char *file_name = "clone.wasm"; +#endif + if (!load_wasm_file_content(file_name, &binary)) + goto release_vm; + + printf("Compiling module...\n"); + ret = vm_load(vm, &binary); + wasm_byte_vec_delete(&binary); + if (!ret) + goto release_vm; + + printf("Creating callback...\n"); + wasm_functype_t *callback_type = + wasm_functype_new_1_0(wasm_valtype_new_i32()); + if (!callback_type) + goto release_vm; + + wasm_func_t *callback = wasm_func_new(vm->store, callback_type, report_cb); + wasm_functype_delete(callback_type); + if (!callback) + goto release_vm; + + printf("Instantiating module...\n"); + wasm_extern_t *externs[] = { wasm_func_as_extern(callback) }; + wasm_extern_vec_t imports = WASM_ARRAY_VEC(externs); + ret = vm_link(vm, &imports); + wasm_func_delete(callback); + if (!ret) + goto release_vm; + + *out = vm; + return true; + +release_vm: + vm_release(vm); +fail: + return false; +} + +bool +run_warm_start_w_compiled_bytecode(const wasm_vm_t *first, wasm_vm_t **out) +{ + bool ret; + wasm_vm_t *secondary = vm_clone(first, compiled_bytecode); + if (!secondary) + goto fail; + + printf("Creating callback...\n"); + wasm_functype_t *callback_type = + wasm_functype_new_1_0(wasm_valtype_new_i32()); + if (!callback_type) + goto release_vm; + + wasm_func_t *callback = + wasm_func_new(secondary->store, callback_type, report_cb); + wasm_functype_delete(callback_type); + if (!callback) + goto release_vm; + + printf("Instantiating module...\n"); + wasm_extern_t *externs[] = { wasm_func_as_extern(callback) }; + wasm_extern_vec_t imports = WASM_ARRAY_VEC(externs); + ret = vm_link(secondary, &imports); + wasm_func_delete(callback); + if (!ret) + goto release_vm; + + *out = secondary; + return true; + +release_vm: + vm_release(secondary); +fail: + return false; +} + +bool +run_warm_start_w_instantiated_module(const wasm_vm_t *first, wasm_vm_t **out) +{ + wasm_vm_t *secondary = vm_clone(first, instantiated_module); + if (!secondary) + return false; + + *out = secondary; + return true; +} + +void +run_test(const wasm_vm_t *vm) +{ + uint8_t byte = 0xFF; + + /* read initialization */ + vm_function_get_byte(vm, 10, &byte); + assert(byte == 0x0); + vm_memory_get_byte(vm, 10, &byte); + assert(byte == 0x0); + + /* read after writing */ + vm_function_set_byte(vm, 16, 0xab); + vm_function_get_byte(vm, 16, &byte); + assert(byte == 0xab); + + vm_memory_set_byte(vm, 16, 0xcd); + vm_memory_get_byte(vm, 16, &byte); + assert(byte == 0xcd); + + /* reading and writing across */ + vm_function_set_byte(vm, 16, 0xef); + vm_memory_get_byte(vm, 16, &byte); + assert(byte == 0xef); + + vm_memory_set_byte(vm, 16, 0x67); + vm_function_get_byte(vm, 16, &byte); + assert(byte == 0x67); + + printf("All Passed ...\n"); +} + +static void * +thrd_func(void *arg) +{ + thread_arg_t *thrd_arg = (thread_arg_t *)arg; + + sleep(rand() % 5); + printf("Running warm start at %s...\n", thrd_arg->name); + + pthread_setspecific(name_key, thrd_arg->name); + + wasm_vm_t *vm; + if (!run_warm_start_w_compiled_bytecode(thrd_arg->base_vm, &vm)) + return NULL; + + pthread_mutex_trylock(thrd_arg->ready_go_lock); + while (!(*thrd_arg->ready_go_flag)) { + pthread_cond_wait(thrd_arg->ready_go_cond, thrd_arg->ready_go_lock); + } + pthread_mutex_unlock(thrd_arg->ready_go_lock); + + printf("Running test at %s...\n", thrd_arg->name); + run_test(vm); + + vm_release(vm); + pthread_exit(NULL); + return NULL; +} + +int +main() +{ + int ret = EXIT_FAILURE; + bool ready_go_flag = false; + pthread_mutex_t ready_go_lock = PTHREAD_MUTEX_INITIALIZER; + pthread_cond_t ready_go_cond = PTHREAD_COND_INITIALIZER; + pthread_key_create(&name_key, NULL); + pthread_setspecific(name_key, "Execution Thread"); + + printf("Running cold start at the execution thread...\n"); + wasm_vm_t *base_vm; + if (!run_code_start(&base_vm)) + goto quit; + run_test(base_vm); + + printf("Running warm start at other threads...\n"); + + pthread_t tids[WORKER_NUMBER] = { 0 }; + thread_arg_t thrd_args[WORKER_NUMBER] = { 0 }; + for (size_t i = 0; i < sizeof(tids) / sizeof(tids[0]); i++) { + thread_arg_t *thrd_arg = thrd_args + i; + + snprintf(thrd_arg->name, 32, "Worker#%lu", i); + thrd_arg->ready_go_cond = &ready_go_cond; + thrd_arg->ready_go_lock = &ready_go_lock; + thrd_arg->ready_go_flag = &ready_go_flag; + thrd_arg->base_vm = base_vm; + + int ret = pthread_create(&tids[i], NULL, thrd_func, thrd_arg); + if (ret != 0) + break; + } + + sleep(1); + pthread_mutex_trylock(&ready_go_lock); + ready_go_flag = true; + pthread_mutex_unlock(&ready_go_lock); + pthread_cond_broadcast(&ready_go_cond); + + sleep(3); + for (size_t i = 0; i < sizeof(tids) / sizeof(tids[0]); i++) { + if (tids[i] != 0) + pthread_join(tids[i], NULL); + } + + vm_release(base_vm); + ret = EXIT_SUCCESS; +quit: + return ret; +} diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/clone.wat b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/clone.wat new file mode 100644 index 00000000000..e9934cc0d9f --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/clone.wat @@ -0,0 +1,15 @@ +(module + (func $report (import "" "report") (param i32)) + + (memory (export "mem") 1 1) + + (func $wasm_set_byte (export "set_byte") (param i32 i32) + (call $report (i32.const 1)) + (i32.store8 (local.get 0) (local.get 1)) + ) + + (func $wasm_get_byte (export "get_byte") (param i32) (result i32) + (call $report (i32.const 2)) + (i32.load(local.get 0)) + ) +) \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/src/empty_imports.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/empty_imports.c similarity index 90% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/src/empty_imports.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/empty_imports.c index 5858ed6b548..c8788b51ac6 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/src/empty_imports.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/empty_imports.c @@ -97,10 +97,16 @@ int main(int argc, const char* argv[]) { wasm_val_t results[1] = { WASM_INIT_VAL }; wasm_val_vec_t results_vec = WASM_ARRAY_VEC(results); - if (wasm_func_call(add_func, &args_vec, &results_vec) - || results_vec.data[0].of.i32 != 7) { - printf("> Error calling function!\n"); - return 1; + wasm_trap_t *trap = wasm_func_call(add_func, &args_vec, &results_vec); + if (trap) { + printf("> Error calling function!\n"); + wasm_trap_delete(trap); + return 1; + } + + if (results_vec.data[0].of.i32 != 7) { + printf("> Error calling function!\n"); + return 1; } wasm_extern_vec_delete(&exports); diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/src/empty_imports.wat b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/empty_imports.wat similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/src/empty_imports.wat rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/empty_imports.wat diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/src/global.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/global.c similarity index 87% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/src/global.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/global.c index bc4671d2393..91c8cb654d1 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/src/global.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/global.c @@ -37,15 +37,22 @@ wasm_func_t* get_export_func(const wasm_extern_vec_t* exports, size_t i) { check(val, type, expected); \ } -#define check_call(func, type, expected) \ - { \ - wasm_val_t vs[1]; \ - wasm_val_vec_t args = WASM_EMPTY_VEC; \ - wasm_val_vec_t results = WASM_ARRAY_VEC(vs); \ - wasm_func_call(func, &args, &results); \ - check(vs[0], type, expected); \ - } - +#define check_trap(trap) \ + if (trap) { \ + printf("> Error calling function\n"); \ + wasm_trap_delete(trap); \ + exit(1); \ + } + +#define check_call(func, type, expected) \ + { \ + wasm_val_t vs[1]; \ + wasm_val_vec_t args = WASM_EMPTY_VEC; \ + wasm_val_vec_t results = WASM_ARRAY_VEC(vs); \ + wasm_trap_t *trap = wasm_func_call(func, &args, &results); \ + check_trap(trap); \ + check(vs[0], type, expected); \ + } int main(int argc, const char* argv[]) { // Initialize. @@ -225,16 +232,23 @@ int main(int argc, const char* argv[]) { wasm_val_vec_t res = WASM_EMPTY_VEC; wasm_val_t vs73[] = { WASM_F32_VAL(73) }; wasm_val_vec_t args73 = WASM_ARRAY_VEC(vs73); - wasm_func_call(set_var_f32_import, &args73, &res); + wasm_trap_t *trap = wasm_func_call(set_var_f32_import, &args73, &res); + check_trap(trap); + wasm_val_t vs74[] = { WASM_I64_VAL(74) }; wasm_val_vec_t args74 = WASM_ARRAY_VEC(vs74); - wasm_func_call(set_var_i64_import, &args74, &res); + trap = wasm_func_call(set_var_i64_import, &args74, &res); + check_trap(trap); + wasm_val_t vs77[] = { WASM_F32_VAL(77) }; wasm_val_vec_t args77 = WASM_ARRAY_VEC(vs77); - wasm_func_call(set_var_f32_export, &args77, &res); + trap = wasm_func_call(set_var_f32_export, &args77, &res); + check_trap(trap); + wasm_val_t vs78[] = { WASM_I64_VAL(78) }; wasm_val_vec_t args78 = WASM_ARRAY_VEC(vs78); - wasm_func_call(set_var_i64_export, &args78, &res); + trap = wasm_func_call(set_var_i64_export, &args78, &res); + check_trap(trap); check_global(var_f32_import, f32, 73); check_global(var_i64_import, i64, 74); diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/src/global.wat b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/global.wat similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/src/global.wat rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/global.wat diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/src/globalexportimport-0.wat b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/globalexportimport-0.wat similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/src/globalexportimport-0.wat rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/globalexportimport-0.wat diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/src/globalexportimport-1.wat b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/globalexportimport-1.wat similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/src/globalexportimport-1.wat rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/globalexportimport-1.wat diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/src/globalexportimport.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/globalexportimport.c similarity index 85% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/src/globalexportimport.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/globalexportimport.c index 92420a1b9f6..1c1715f2e5e 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/src/globalexportimport.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/globalexportimport.c @@ -50,13 +50,21 @@ wasm_func_t* get_export_func(const wasm_extern_vec_t* exports, size_t i) { check(val, type, expected); \ } -#define check_call(func, type, expected) \ - { \ - wasm_val_vec_t results; \ - wasm_val_vec_new_uninitialized(&results, 1); \ - wasm_func_call(func, NULL, &results); \ - check(results.data[0], type, expected); \ - } +#define check_trap(trap) \ + if (trap) { \ + printf("> Error calling function\n"); \ + wasm_trap_delete(trap); \ + exit(1); \ + } + +#define check_call(func, type, expected) \ + { \ + wasm_val_vec_t results; \ + wasm_val_vec_new_uninitialized(&results, 1); \ + wasm_trap_t *trap = wasm_func_call(func, NULL, &results); \ + check_trap(trap); \ + check(results.data[0], type, expected); \ + } wasm_module_t * create_module_from_file(wasm_store_t* store, const char * filename) { @@ -149,7 +157,9 @@ int main(int argc, const char* argv[]) { printf("Modify the variable to 77.0...\n"); wasm_val_vec_t args77; wasm_val_vec_new(&args77, 1, (wasm_val_t []){ {.kind = WASM_F32, .of = {.f32 = 77.0}} }); - wasm_func_call(set_var_f32_export, &args77, NULL); //Call to module export + wasm_trap_t *trap = wasm_func_call(set_var_f32_export, &args77, + NULL); // Call to module export + check_trap(trap); check_call(get_var_f32_export, f32, 77.0); //Call to module export check_global(var_f32_export, f32, 77.0); //Failed here, still 37 check_call(get_var_f32_import, f32, 77.0); //Call to module import Failed here, still 37 @@ -158,7 +168,8 @@ int main(int argc, const char* argv[]) { printf("Modify the variable to 78.0...\n"); wasm_val_vec_t args78; wasm_val_vec_new(&args78, 1, (wasm_val_t []){ {.kind = WASM_F32, .of = {.f32 = 78.0}} }); - wasm_func_call(set_var_f32_import, &args78, NULL); + trap = wasm_func_call(set_var_f32_import, &args78, NULL); + check_trap(trap); check_global(var_f32_export, f32, 78.0); check_call(get_var_f32_export, f32, 78.0); //Call to module export Failed here, still 77 check_call(get_var_f32_import, f32, 78.0); //Call to module import diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/src/hello.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/hello.c similarity index 94% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/src/hello.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/hello.c index 5a2b9843e7c..3ebea87b089 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/src/hello.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/hello.c @@ -118,9 +118,11 @@ int main(int argc, const char* argv[]) { printf("Calling export...\n"); wasm_val_vec_t args = WASM_EMPTY_VEC; wasm_val_vec_t results = WASM_EMPTY_VEC; - if (wasm_func_call(run_func, &args, &results)) { - printf("> Error calling function!\n"); - return 1; + wasm_trap_t *trap = wasm_func_call(run_func, &args, &results); + if (trap) { + printf("> Error calling function!\n"); + wasm_trap_delete(trap); + return 1; } wasm_extern_vec_delete(&exports); diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/src/hello.wat b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/hello.wat similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/src/hello.wat rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/hello.wat diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/src/hostref.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/hostref.c similarity index 90% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/src/hostref.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/hostref.c index a411ddd9f4d..219c862d685 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/src/hostref.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/hostref.c @@ -50,9 +50,11 @@ own wasm_ref_t* call_v_r(const wasm_func_t* func) { wasm_val_t rs[] = { WASM_INIT_VAL }; wasm_val_vec_t args = WASM_EMPTY_VEC; wasm_val_vec_t results = WASM_ARRAY_VEC(rs); - if (wasm_func_call(func, &args, &results)) { - printf("> Error calling function!\n"); - exit(1); + wasm_trap_t *trap = wasm_func_call(func, &args, &results); + if (trap) { + printf("> Error calling function!\n"); + wasm_trap_delete(trap); + exit(1); } printf("okay\n"); return rs[0].of.ref; @@ -63,9 +65,11 @@ void call_r_v(const wasm_func_t* func, wasm_ref_t* ref) { wasm_val_t vs[1] = { WASM_REF_VAL(ref) }; wasm_val_vec_t args = WASM_ARRAY_VEC(vs); wasm_val_vec_t results = WASM_EMPTY_VEC; - if (wasm_func_call(func, &args, &results)) { - printf("> Error calling function!\n"); - exit(1); + wasm_trap_t *trap = wasm_func_call(func, &args, &results); + if (trap) { + printf("> Error calling function!\n"); + wasm_trap_delete(trap); + exit(1); } printf("okay\n"); } @@ -76,9 +80,11 @@ own wasm_ref_t* call_r_r(const wasm_func_t* func, wasm_ref_t* ref) { wasm_val_t rs[1] = { WASM_INIT_VAL }; wasm_val_vec_t args = WASM_ARRAY_VEC(vs); wasm_val_vec_t results = WASM_ARRAY_VEC(rs); - if (wasm_func_call(func, &args, &results)) { - printf("> Error calling function!\n"); - exit(1); + wasm_trap_t *trap = wasm_func_call(func, &args, &results); + if (trap) { + printf("> Error calling function!\n"); + wasm_trap_delete(trap); + exit(1); } printf("okay\n"); return rs[0].of.ref; @@ -89,9 +95,11 @@ void call_ir_v(const wasm_func_t* func, int32_t i, wasm_ref_t* ref) { wasm_val_t vs[2] = { WASM_I32_VAL(i), WASM_REF_VAL(ref) }; wasm_val_vec_t args = WASM_ARRAY_VEC(vs); wasm_val_vec_t results = WASM_EMPTY_VEC; - if (wasm_func_call(func, &args, &results)) { - printf("> Error calling function!\n"); - exit(1); + wasm_trap_t *trap = wasm_func_call(func, &args, &results); + if (trap) { + printf("> Error calling function!\n"); + wasm_trap_delete(trap); + exit(1); } printf("okay\n"); } @@ -102,9 +110,11 @@ own wasm_ref_t* call_i_r(const wasm_func_t* func, int32_t i) { wasm_val_t rs[1] = { WASM_INIT_VAL }; wasm_val_vec_t args = WASM_ARRAY_VEC(vs); wasm_val_vec_t results = WASM_ARRAY_VEC(rs); - if (wasm_func_call(func, &args, &results)) { - printf("> Error calling function!\n"); - exit(1); + wasm_trap_t *trap = wasm_func_call(func, &args, &results); + if (trap) { + printf("> Error calling function!\n"); + wasm_trap_delete(trap); + exit(1); } printf("okay\n"); return rs[0].of.ref; diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/src/hostref.wat b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/hostref.wat similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/src/hostref.wat rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/hostref.wat diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/src/memory.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/memory.c similarity index 93% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/src/memory.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/memory.c index 64d1c077788..737dd8501d7 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/src/memory.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/memory.c @@ -36,9 +36,16 @@ void check_call(wasm_func_t* func, int i, wasm_val_t args[], int32_t expected) { wasm_val_t r[] = {WASM_INIT_VAL}; wasm_val_vec_t args_ = {i, args, i, sizeof(wasm_val_t), NULL}; wasm_val_vec_t results = WASM_ARRAY_VEC(r); - if (wasm_func_call(func, &args_, &results) || r[0].of.i32 != expected) { - printf("> Error on result\n"); - exit(1); + wasm_trap_t *trap = wasm_func_call(func, &args_, &results); + if (trap) { + printf("> Error on result\n"); + wasm_trap_delete(trap); + exit(1); + } + + if (r[0].of.i32 != expected) { + printf("> Error on result\n"); + exit(1); } } @@ -59,9 +66,11 @@ void check_call2(wasm_func_t* func, int32_t arg1, int32_t arg2, int32_t expected void check_ok(wasm_func_t* func, int i, wasm_val_t args[]) { wasm_val_vec_t args_ = {i, args, i, sizeof(wasm_val_t), NULL}; wasm_val_vec_t results = WASM_EMPTY_VEC; - if (wasm_func_call(func, &args_, &results)) { - printf("> Error on result, expected empty\n"); - exit(1); + wasm_trap_t *trap = wasm_func_call(func, &args_, &results); + if (trap) { + printf("> Error on result, expected empty\n"); + wasm_trap_delete(trap); + exit(1); } } diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/src/memory.wat b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/memory.wat similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/src/memory.wat rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/memory.wat diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/src/multi.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/multi.c similarity index 96% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/src/multi.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/multi.c index 92ef0eea777..a1c8fa9fc9f 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/src/multi.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/multi.c @@ -133,9 +133,11 @@ int main(int argc, const char* argv[]) { }; wasm_val_vec_t args = WASM_ARRAY_VEC(vals); wasm_val_vec_t results = WASM_ARRAY_VEC(res); - if (wasm_func_call(run_func, &args, &results)) { - printf("> Error calling function!\n"); - return 1; + wasm_trap_t *trap = wasm_func_call(run_func, &args, &results); + if (trap) { + printf("> Error calling function!\n"); + wasm_trap_delete(trap); + return 1; } wasm_extern_vec_delete(&exports); diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/src/multi.wat b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/multi.wat similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/src/multi.wat rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/multi.wat diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/src/reflect.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/reflect.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/src/reflect.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/reflect.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/src/reflect.wat b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/reflect.wat similarity index 80% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/src/reflect.wat rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/reflect.wat index 261dfd3c339..7a80e86ddeb 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/src/reflect.wat +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/reflect.wat @@ -1,6 +1,6 @@ (module (func (export "func") (param i32 f64 f32) (result i32) (unreachable)) (global (export "global") f64 (f64.const 0)) - (table (export "table") 0 50 anyfunc) + (table (export "table") 0 50 funcref) (memory (export "memory") 1) ) diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/serialize.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/serialize.c new file mode 100644 index 00000000000..83436817f21 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/serialize.c @@ -0,0 +1,131 @@ +#include +#include +#include +#include + +#include "wasm_c_api.h" + +#define own + +// A function to be called from Wasm code. +own wasm_trap_t * +hello_callback(const wasm_val_vec_t *args, wasm_val_vec_t *results) +{ + printf("Calling back...\n"); + printf("> Hello World!\n"); + return NULL; +} + +int +main(int argc, const char *argv[]) +{ + // Initialize. + printf("Initializing...\n"); + wasm_engine_t *engine = wasm_engine_new(); + wasm_store_t *store = wasm_store_new(engine); + + // Load binary. + printf("Loading binary...\n"); + FILE *file = fopen("serialize.wasm", "rb"); + if (!file) { + printf("> Error loading module!\n"); + return 1; + } + fseek(file, 0L, SEEK_END); + size_t file_size = ftell(file); + fseek(file, 0L, SEEK_SET); + wasm_byte_vec_t binary; + wasm_byte_vec_new_uninitialized(&binary, file_size); + if (fread(binary.data, file_size, 1, file) != 1) { + printf("> Error loading module!\n"); + return 1; + } + fclose(file); + + // Compile. + printf("Compiling module...\n"); + own wasm_module_t *module = wasm_module_new(store, &binary); + if (!module) { + printf("> Error compiling module!\n"); + return 1; + } + + wasm_byte_vec_delete(&binary); + + // Serialize module. + printf("Serializing module...\n"); + own wasm_byte_vec_t serialized; + wasm_module_serialize(module, &serialized); + + wasm_module_delete(module); + + // Deserialize module. + printf("Deserializing module...\n"); + own wasm_module_t *deserialized = + wasm_module_deserialize(store, &serialized); + if (!deserialized) { + printf("> Error deserializing module!\n"); + return 1; + } + + wasm_byte_vec_delete(&serialized); + + // Create external print functions. + printf("Creating callback...\n"); + own wasm_functype_t *hello_type = wasm_functype_new_0_0(); + own wasm_func_t *hello_func = + wasm_func_new(store, hello_type, hello_callback); + + wasm_functype_delete(hello_type); + + // Instantiate. + printf("Instantiating deserialized module...\n"); + wasm_extern_t *externs[] = { wasm_func_as_extern(hello_func) }; + wasm_extern_vec_t imports = WASM_ARRAY_VEC(externs); + own wasm_instance_t *instance = + wasm_instance_new(store, deserialized, &imports, NULL); + if (!instance) { + printf("> Error instantiating module!\n"); + return 1; + } + + wasm_func_delete(hello_func); + + // Extract export. + printf("Extracting export...\n"); + own wasm_extern_vec_t exports; + wasm_instance_exports(instance, &exports); + if (exports.size == 0) { + printf("> Error accessing exports!\n"); + return 1; + } + const wasm_func_t *run_func = wasm_extern_as_func(exports.data[0]); + if (run_func == NULL) { + printf("> Error accessing export!\n"); + return 1; + } + + wasm_module_delete(deserialized); + wasm_instance_delete(instance); + + // Call. + printf("Calling export...\n"); + wasm_val_vec_t empty = WASM_EMPTY_VEC; + wasm_trap_t *trap = wasm_func_call(run_func, &empty, &empty); + if (trap) { + printf("> Error calling function!\n"); + wasm_trap_delete(trap); + return 1; + } + + wasm_extern_vec_delete(&exports); + + // Shut down. + printf("Shutting down...\n"); + wasm_store_delete(store); + wasm_engine_delete(engine); + + // All done. + printf("Done.\n"); + return 0; +} diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/serialize.wat b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/serialize.wat new file mode 100644 index 00000000000..1c56c558222 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/serialize.wat @@ -0,0 +1,4 @@ +(module + (func $hello (import "" "hello")) + (func (export "run") (call $hello)) +) diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/src/table.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/table.c similarity index 95% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/src/table.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/table.c index 0bf68e05a7a..c4a7da8bcf0 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/src/table.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/table.c @@ -53,9 +53,16 @@ void check_call(wasm_func_t* func, int32_t arg1, int32_t arg2, int32_t expected) wasm_val_t r[1] = { WASM_INIT_VAL }; wasm_val_vec_t args = WASM_ARRAY_VEC(vs); wasm_val_vec_t results = WASM_ARRAY_VEC(r); - if (wasm_func_call(func, &args, &results) || r[0].of.i32 != expected) { - printf("> Error on result\n"); - exit(1); + wasm_trap_t *trap = wasm_func_call(func, &args, &results); + if (trap) { + printf("> Error on calling\n"); + wasm_trap_delete(trap); + exit(1); + } + + if (r[0].of.i32 != expected) { + printf("> Error on result\n"); + exit(1); } } diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/src/table.wat b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/table.wat similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/src/table.wat rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/table.wat diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/threads.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/threads.c new file mode 100644 index 00000000000..cbe4aaf4449 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/threads.c @@ -0,0 +1,187 @@ +#include +#include +#include +#include +#include +#include + +#include "wasm_c_api.h" + +#define own + +const int N_THREADS = 10; +const int N_REPS = 3; + +// A function to be called from Wasm code. +own wasm_trap_t * +callback(const wasm_val_vec_t *args, wasm_val_vec_t *results) +{ + assert(args->data[0].kind == WASM_I32); + printf("> Thread %d running\n", args->data[0].of.i32); + return NULL; +} + +typedef struct { + wasm_engine_t *engine; + wasm_shared_module_t *module; + int id; +} thread_args; + +void * +run(void *args_abs) +{ + thread_args *args = (thread_args *)args_abs; + + // Rereate store and module. + own wasm_store_t *store = wasm_store_new(args->engine); + own wasm_module_t *module = wasm_module_obtain(store, args->module); + + // Run the example N times. + for (int i = 0; i < N_REPS; ++i) { + usleep(100000); + + // Create imports. + own wasm_functype_t *func_type = + wasm_functype_new_1_0(wasm_valtype_new_i32()); + own wasm_func_t *func = wasm_func_new(store, func_type, callback); + wasm_functype_delete(func_type); + + wasm_val_t val = WASM_I32_VAL((int32_t)args->id); + own wasm_globaltype_t *global_type = + wasm_globaltype_new(wasm_valtype_new_i32(), WASM_CONST); + own wasm_global_t *global = wasm_global_new(store, global_type, &val); + wasm_globaltype_delete(global_type); + + // Instantiate. + wasm_extern_t *externs[] = { + wasm_func_as_extern(func), + wasm_global_as_extern(global), + }; + wasm_extern_vec_t imports = WASM_ARRAY_VEC(externs); + own wasm_instance_t *instance = + wasm_instance_new(store, module, &imports, NULL); + if (!instance) { + printf("> Error instantiating module!\n"); + return NULL; + } + + wasm_func_delete(func); + wasm_global_delete(global); + + // Extract export. + own wasm_extern_vec_t exports; + wasm_instance_exports(instance, &exports); + if (exports.size == 0) { + printf("> Error accessing exports!\n"); + return NULL; + } + const wasm_func_t *run_func = wasm_extern_as_func(exports.data[0]); + if (run_func == NULL) { + printf("> Error accessing export!\n"); + return NULL; + } + + wasm_instance_delete(instance); + + // Call. + wasm_val_vec_t empty = WASM_EMPTY_VEC; + wasm_trap_t *trap = wasm_func_call(run_func, &empty, &empty); + if (trap) { + printf("> Error calling function!\n"); + wasm_trap_delete(trap); + return NULL; + } + + wasm_extern_vec_delete(&exports); + } + + wasm_module_delete(module); + wasm_store_delete(store); + + free(args_abs); + + return NULL; +} + +int +main(int argc, const char *argv[]) +{ + // Initialize. + wasm_engine_t *engine = wasm_engine_new(); + + // Load binary. +#if WASM_ENABLE_AOT != 0 && WASM_ENABLE_INTERP == 0 + FILE *file = fopen("threads.aot", "rb"); +#else + FILE *file = fopen("threads.wasm", "rb"); +#endif + if (!file) { + printf("> Error loading module!\n"); + return 1; + } + + int ret = fseek(file, 0L, SEEK_END); + if (ret == -1) { + printf("> Error loading module!\n"); + fclose(file); + return 1; + } + + long file_size = ftell(file); + if (file_size == -1) { + printf("> Error loading module!\n"); + fclose(file); + return 1; + } + + ret = fseek(file, 0L, SEEK_SET); + if (ret == -1) { + printf("> Error loading module!\n"); + fclose(file); + return 1; + } + + wasm_byte_vec_t binary; + wasm_byte_vec_new_uninitialized(&binary, file_size); + if (fread(binary.data, file_size, 1, file) != 1) { + printf("> Error loading module!\n"); + return 1; + } + fclose(file); + + // Compile and share. + own wasm_store_t *store = wasm_store_new(engine); + own wasm_module_t *module = wasm_module_new(store, &binary); + if (!module) { + printf("> Error compiling module!\n"); + return 1; + } + + wasm_byte_vec_delete(&binary); + + own wasm_shared_module_t *shared = wasm_module_share(module); + + wasm_module_delete(module); + wasm_store_delete(store); + + // Spawn threads. + pthread_t threads[N_THREADS]; + for (int i = 0; i < N_THREADS; i++) { + thread_args *args = malloc(sizeof(thread_args)); + args->id = i; + args->engine = engine; + args->module = shared; + printf("Initializing thread %d...\n", i); + pthread_create(&threads[i], NULL, &run, args); + } + + for (int i = 0; i < N_THREADS; i++) { + printf("Waiting for thread: %d\n", i); + pthread_join(threads[i], NULL); + } + + wasm_shared_module_delete(shared); + wasm_engine_delete(engine); + + return 0; +} diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/threads.wat b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/threads.wat new file mode 100644 index 00000000000..29a3bbcc1a6 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/threads.wat @@ -0,0 +1,5 @@ +(module + (func $message (import "" "hello") (param i32)) + (global $id (import "" "id") i32) + (func (export "run") (call $message (global.get $id))) +) diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/src/trap.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/trap.c similarity index 97% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/src/trap.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/trap.c index 230b2d4e267..2637b73469a 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/src/trap.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/trap.c @@ -143,6 +143,8 @@ int main(int argc, const char* argv[]) { own wasm_name_t message; wasm_trap_message(trap, &message); printf("> %s\n", message.data); + assert(message.num_elems > 0); + assert(strncmp(message.data, "Exception: ", strlen("Exception: ")) == 0); printf("Printing origin...\n"); own wasm_frame_t* frame = wasm_trap_origin(trap); diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/src/trap.wat b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/trap.wat similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/src/trap.wat rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/trap.wat diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/src/utils/multi_module_utils.c b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/utils/multi_module_utils.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/wasm-c-api/src/utils/multi_module_utils.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/wasm-c-api/src/utils/multi_module_utils.c diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/CMakeLists.txt b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/CMakeLists.txt new file mode 100644 index 00000000000..667f0b4e84f --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/CMakeLists.txt @@ -0,0 +1,116 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required (VERSION 3.14) + +project(wasm_workloads) + +####################################### +add_subdirectory(bwa) +add_subdirectory(meshoptimizer) +add_subdirectory(wasm-av1) + +####################################### +include(ExternalProject) + +################ iwasm ################ +ExternalProject_Add(iwasm + PREFIX + iwasm-build + BUILD_ALWAYS + YES + SOURCE_DIR + ${CMAKE_CURRENT_SOURCE_DIR}/../../product-mini/platforms/linux + CONFIGURE_COMMAND + ${CMAKE_COMMAND} -S ${CMAKE_CURRENT_SOURCE_DIR}/../../product-mini/platforms/linux -B build -DWAMR_BUILD_LIBC_EMCC=1 + BUILD_COMMAND + ${CMAKE_COMMAND} --build build --parallel 4 + INSTALL_COMMAND + # FIXME: replace with --install + ${CMAKE_COMMAND} -E copy_if_different + ${CMAKE_CURRENT_BINARY_DIR}/iwasm-build/src/iwasm-build/build/iwasm + ${CMAKE_CURRENT_BINARY_DIR}/iwasm +) + +################ wamrc ################ +ExternalProject_Add(wamrc + PREFIX + wamrc-build + BUILD_ALWAYS + YES + SOURCE_DIR + ${CMAKE_CURRENT_SOURCE_DIR}/../../wamr-compiler + CONFIGURE_COMMAND + ${CMAKE_COMMAND} -S ${CMAKE_CURRENT_SOURCE_DIR}/../../wamr-compiler -B build + BUILD_COMMAND + ${CMAKE_COMMAND} --build build --parallel 4 + INSTALL_COMMAND + # FIXME: replace with --install + ${CMAKE_COMMAND} -E copy_if_different + ${CMAKE_CURRENT_BINARY_DIR}/wamrc-build/src/wamrc-build/build/wamrc + ${CMAKE_CURRENT_BINARY_DIR}/wamrc +) + +################ .aot ################ +add_custom_target( + bwa_to_aot + ALL + DEPENDS + bwa wamrc + COMMAND + ./wamrc -o bwa.aot ./bwa/bwa.wasm + WORKING_DIRECTORY + ${CMAKE_CURRENT_BINARY_DIR} +) + +add_custom_target( + codecbench_to_aot + ALL + DEPENDS + codecbench wamrc + COMMAND + ./wamrc -o codecbench.aot ./meshoptimizer/codecbench.wasm + WORKING_DIRECTORY + ${CMAKE_CURRENT_BINARY_DIR} +) + +add_custom_target( + av1_to_aot + ALL + DEPENDS + av1 wamrc + COMMAND + ./wamrc -o testavx.aot ./wasm-av1/testavx.opt.wasm + WORKING_DIRECTORY + ${CMAKE_CURRENT_BINARY_DIR} +) + +################ smoking test ################ +include(CTest) + +add_test( + NAME + run_bwa + COMMAND + ./iwasm --dir=. ./bwa.aot index ./bwa/hs38DH-extra.fa + WORKING_DIRECTORY + ${CMAKE_CURRENT_BINARY_DIR} +) + +add_test( + NAME + run_codecbench + COMMAND + ./iwasm codecbench.aot + WORKING_DIRECTORY + ${CMAKE_CURRENT_BINARY_DIR} +) + +add_test( + NAME + run_av1 + COMMAND + ./iwasm --dir=. testavx.aot ./wasm-av1/elephants_dream_480p24.ivf + WORKING_DIRECTORY + ${CMAKE_CURRENT_BINARY_DIR} +) diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/README.md b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/README.md similarity index 59% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/README.md rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/README.md index dd94e05ca0e..0e6a3a41b4e 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/README.md +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/README.md @@ -1,41 +1,30 @@ -All workloads have similar requirment of software dependencies, including -**emsdk**, **wabt** and **binaryen** +All workloads have similar requirment of software dependencies, including **emsdk** and **binaryen** -> There might be slight differences when using MacOS and other Linux distro than Ubuntu. This document only target -Ubuntu 18.04 as example. +> There might be slight differences when using MacOS and other Linux distro than Ubuntu. This document targets +Ubuntu 20.04 as an example. ## Installation instructions -use [preparation.sh](./preparation.sh) to install all dependencies before compiling any workload. +use [preparation.sh](./preparation.sh) to install all dependencies before compiling any workload. Or use [*vscode DevContainer*](../../.devcontainer/) -for details, the script includes below steps: - -- **wabt**. Install - [latest release](https://github.com/WebAssembly/wabt/releases/download/1.0.23/wabt-1.0.23-ubuntu.tar.gz) - to */opt/wabt* - -``` bash -$ wget https://github.com/WebAssembly/wabt/releases/download/${WABT_VER}/${WABT_FILE} -$ tar zxf ${WABT_FILE} -C /opt -$ ln -sf /opt/wabt-${WABT_VER} /opt/wabt -``` +The script installs below software: - **emsdk**. Refer to [the guide](https://emscripten.org/docs/getting_started/downloads.html). Don't forget to activate emsdk and set up environment variables. Verify it with `echo ${EMSDK}`. Please be sure to install and activate the building - of 2.0.26 + of 3.0.0 ``` bash $ cd /opt $ git clone https://github.com/emscripten-core/emsdk.git $ cd emsdk $ git pull -$ ./emsdk install 2.0.26 -$ ./emsdk activate 2.0.26 +$ ./emsdk install 3.0.0 +$ ./emsdk activate 3.0.0 $ echo "source /opt/emsdk/emsdk_env.sh" >> "${HOME}"/.bashrc ``` - **binaryen**. Install - [latest release](https://github.com/WebAssembly/binaryen/releases/download/version_101/binaryen-version_101-x86_64-linux.tar.gz) + [latest release](https://github.com/WebAssembly/binaryen/releases/download/version_111/binaryen-version_111-x86_64-linux.tar.gz) to */opt/binaryen* ``` bash diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/XNNPACK/.gitignore b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/XNNPACK/.gitignore similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/XNNPACK/.gitignore rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/XNNPACK/.gitignore diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/XNNPACK/CMakeLists.txt b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/XNNPACK/CMakeLists.txt similarity index 58% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/XNNPACK/CMakeLists.txt rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/XNNPACK/CMakeLists.txt index 3f67367a7a6..aef138d5e85 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/XNNPACK/CMakeLists.txt +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/XNNPACK/CMakeLists.txt @@ -11,12 +11,12 @@ include(ExternalProject) ExternalProject_Add(xnnpack PREFIX xnnpack GIT_REPOSITORY https://github.com/google/XNNPACK.git - GIT_TAG master + GIT_TAG 4570a7151aa4f3e57eca14a575eeff6bb13e26be GIT_PROGRESS ON SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/xnnpack - UPDATE_COMMAND git checkout . - && git reset --hard 4d738aef36872669e4bba05a4b259149ba8e62e1 - && cmake -E copy ${CMAKE_CURRENT_SOURCE_DIR}/benchmark.patch ${CMAKE_CURRENT_SOURCE_DIR}/xnnpack/third_party + 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 CONFIGURE_COMMAND "" # grep xnnpack_benchmark -A 1 BUILD.bazel \ @@ -24,70 +24,123 @@ ExternalProject_Add(xnnpack # | 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 + && 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_vrelu_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 diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/XNNPACK/README.md b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/XNNPACK/README.md similarity index 83% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/XNNPACK/README.md rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/XNNPACK/README.md index f6a207293b8..7984d9cee58 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/XNNPACK/README.md +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/XNNPACK/README.md @@ -24,7 +24,7 @@ Firstly please build iwasm with simd, libc-emcc and lib-pthread support: ``` bash $ cd /product-mini/platforms/linux/ $ mkdir build && cd build -$ cmake .. -DWAMR_BUILD_SIMD=1 -DWAMR_BUILD_LIBC_EMCC=1 -DWAMR_BUILD_LIB_PTHREAD=1 +$ cmake .. -DWAMR_BUILD_LIBC_EMCC=1 -DWAMR_BUILD_LIB_PTHREAD=1 $ make ``` @@ -42,7 +42,7 @@ Then compile wasm file to aot file and run: ``` shell $ cd /samples/workload/XNNPACK/xnnpack/bazel-bin -$ wamrc --enable-simd -o average_pooling_bench.aot average_pooling_bench.wasm (or other wasm files) +$ wamrc -o average_pooling_bench.aot average_pooling_bench.wasm (or other wasm files) $ iwasm average_pooling_bench.aot ``` diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/XNNPACK/benchmark.patch b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/XNNPACK/benchmark.patch similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/XNNPACK/benchmark.patch rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/XNNPACK/benchmark.patch diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/XNNPACK/xnnpack.patch b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/XNNPACK/xnnpack.patch new file mode 100644 index 00000000000..3fb6b230be9 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/XNNPACK/xnnpack.patch @@ -0,0 +1,141 @@ +diff --git a/.bazelrc b/.bazelrc +index 688279da1..376996885 100644 +--- a/.bazelrc ++++ b/.bazelrc +@@ -53,4 +53,9 @@ build:ios_fat --watchos_cpus=armv7k + 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: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 +--- 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"], + ) + + # FP16 library, used for half-precision conversions +@@ -92,8 +93,25 @@ http_archive( + ], + ) + ++load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") ++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" ++) ++ ++load("@emsdk//:deps.bzl", emsdk_deps = "deps") ++emsdk_deps() ++ ++load("@emsdk//:emscripten_deps.bzl", emsdk_emscripten_deps = "emscripten_deps") ++emsdk_emscripten_deps() ++ + # Android NDK location and version is auto-detected from $ANDROID_NDK_HOME environment variable +-android_ndk_repository(name = "androidndk") ++#android_ndk_repository(name = "androidndk") + + # Android SDK location and API is auto-detected from $ANDROID_HOME environment variable +-android_sdk_repository(name = "androidsdk") ++#android_sdk_repository(name = "androidsdk") +diff --git a/build_defs.bzl b/build_defs.bzl +index b8217a18d..6f2d1675e 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 = []): + ":emscripten": xnnpack_emscripten_deps(), + "//conditions:default": [], + }), +- tags = tags, ++ tags = tags, + ) +diff --git a/emscripten.bzl b/emscripten.bzl +index f1557a7b1..7f964a094 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", ++ "-s ERROR_ON_UNDEFINED_SYMBOLS=0", + "-s ALLOW_MEMORY_GROWTH=1", + "-s TOTAL_MEMORY=536870912", # 512M +- "--pre-js $(location :preamble.js.lds)", ++ "-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"}, + ) diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/bwa/.gitignore b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/bwa/.gitignore similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/bwa/.gitignore rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/bwa/.gitignore diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/bwa/CMakeLists.bwa_wasm.txt b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/bwa/CMakeLists.bwa_wasm.txt similarity index 89% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/bwa/CMakeLists.bwa_wasm.txt rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/bwa/CMakeLists.bwa_wasm.txt index c68b942f1a0..a8d1d8821d4 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/bwa/CMakeLists.bwa_wasm.txt +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/bwa/CMakeLists.bwa_wasm.txt @@ -1,11 +1,14 @@ # 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(bwa_wasm C) -include(${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/preparation.cmake) +list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../../cmake) + +################ dependencies ################ +find_package(Binaryen 111 REQUIRED) ################ LIBZ ################ set(LIBZ_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../libz) @@ -86,12 +89,6 @@ add_executable(${PROJECT_NAME} ${BWA_SOURCE}) set_target_properties(${PROJECT_NAME} PROPERTIES OUTPUT_NAME bwa.wasm) -target_include_directories(${PROJECT_NAME} - PRIVATE - ${WASI_SDK_HOME}/share/wasi-sysroot/include/libc/musl - ${WASI_SDK_HOME}/share/wasi-sysroot/include/sse -) - target_compile_definitions(${PROJECT_NAME} PRIVATE USE_MALLOC_WRAPPERS @@ -117,7 +114,7 @@ target_link_libraries(${PROJECT_NAME} z_wasm wasi-emulated-process-clocks) add_custom_target(bwa_wasm_opt ALL COMMAND - ${WASM_OPT} -Oz --enable-simd -o bwa.opt.wasm bwa.wasm + ${Binaryen_WASM_OPT} -Oz --enable-simd -o bwa.opt.wasm bwa.wasm BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/bwa.opt.wasm WORKING_DIRECTORY diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/bwa/CMakeLists.txt b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/bwa/CMakeLists.txt new file mode 100644 index 00000000000..5db52a38be7 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/bwa/CMakeLists.txt @@ -0,0 +1,73 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required (VERSION 3.14) + +project(bwa_wasm) + +list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../cmake) + +################ dependencies ################ +find_package(Python3 REQUIRED) +find_package(WASISDK 16.0 REQUIRED) +execute_process( + COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_LIST_DIR}/../../../test-tools/pick-up-emscripten-headers/collect_files.py --install ../include --loglevel=ERROR + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} +) + +####################################### +include(ExternalProject) + +################ libz ################ +ExternalProject_Add(libz_src + GIT_REPOSITORY https://github.com/madler/zlib.git + GIT_TAG 04f42ceca40f73e2978b50e93806c2a18c1281fc + GIT_PROGRESS ON + GIT_SHALLOW ON + SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/libz + UPDATE_COMMAND "" + PATCH_COMMAND "" + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" +) + +################ bwa ################ +ExternalProject_Add(bwa + GIT_REPOSITORY https://github.com/lh3/bwa.git + GIT_TAG 139f68fc4c3747813783a488aef2adc86626b01b + GIT_PROGRESS ON + GIT_SHALLOW ON + SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/bwa + DEPENDS libz_src + UPDATE_COMMAND git clean -ffdx && git checkout -- * + && ${CMAKE_COMMAND} -E echo "Copying pre-installed CMakeLists.txt" + && ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.bwa_wasm.txt CMakeLists.txt + && git apply ../bwa.patch + CONFIGURE_COMMAND ${CMAKE_COMMAND} + -DWASI_SDK_PREFIX=${WASISDK_HOME} + -DCMAKE_TOOLCHAIN_FILE=${WASISDK_TOOLCHAIN} + -DCMAKE_SYSROOT=${WASISDK_SYSROOT} + -DCMAKE_C_FLAGS=-isystem\ ${CMAKE_CURRENT_SOURCE_DIR}/../include/sse\ -isystem\ ${CMAKE_CURRENT_SOURCE_DIR}/../include/libc/musl + ${CMAKE_CURRENT_SOURCE_DIR}/bwa + BUILD_COMMAND make bwa_wasm_opt -j 4 + INSTALL_COMMAND ${CMAKE_COMMAND} -E copy_if_different ./bwa.opt.wasm ${CMAKE_CURRENT_BINARY_DIR}/bwa.wasm +) + +################ bwa data ################ +ExternalProject_Add(bwa-kit + PREFIX bwa-kit + URL https://sourceforge.net/projects/bio-bwa/files/bwakit/bwakit-0.7.15_x64-linux.tar.bz2/download + URL_HASH SHA256=0a7b11971bc7916b68e9df35a364afe77cb3000df02ffb3a6fbd1aff9be5878c + DOWNLOAD_NAME bwakit-0.7.15_x64-linux.tar.bz2 + DOWNLOAD_EXTRACT_TIMESTAMP ON + DOWNLOAD_NO_EXTRACT OFF + DOWNLOAD_NO_PROGRESS ON + UPDATE_COMMAND "" + PATCH_COMMAND "" + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND ${CMAKE_COMMAND} -E copy_if_different + ${CMAKE_CURRENT_BINARY_DIR}/bwa-kit/src/bwa-kit/resource-GRCh38/hs38DH-extra.fa + ${CMAKE_CURRENT_BINARY_DIR}/hs38DH-extra.fa +) diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/bwa/README.md b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/bwa/README.md similarity index 90% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/bwa/README.md rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/bwa/README.md index e826bb61f2d..a8fbe3e699c 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/bwa/README.md +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/bwa/README.md @@ -33,7 +33,7 @@ Firstly please build iwasm with simd support: ``` shell $ cd /product-mini/platforms/linux/ $ mkdir build && cd build -$ cmake .. -DWAMR_BUILD_SIMD=1 +$ cmake .. $ make ``` @@ -41,6 +41,6 @@ Then compile wasm file to aot file and run: ``` shell $ cd /samples/workload/bwa/build -$ /wamr-compiler/build/wamrc --enable-simd -o bwa.aot bwa.wasm +$ /wamr-compiler/build/wamrc -o bwa.aot bwa.wasm $ /product-mini/platforms/linux/iwasm --dir=. bwa.aot index hs38DH.fa ``` diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/bwa/bwa.patch b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/bwa/bwa.patch similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/bwa/bwa.patch rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/bwa/bwa.patch diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/cmake/FindBinaryen.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/cmake/FindBinaryen.cmake new file mode 100644 index 00000000000..b4a647861fb --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/cmake/FindBinaryen.cmake @@ -0,0 +1,43 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +# +# Output below variables: +# - Binaryen_HOME. the installation location +# + +include(CMakePrintHelpers) +include(FindPackageHandleStandardArgs) + +file(GLOB Binaryen_SEARCH_PATH "/opt/binaryen*") +find_path(Binaryen_HOME + NAMES bin/wasm-opt + PATHS ${Binaryen_SEARCH_PATH} + NO_CMAKE_FIND_ROOT_PATH + NO_SYSTEM_ENVIRONMENT_PATH + REQUIRED +) + +execute_process( + COMMAND ${Binaryen_HOME}/bin/wasm-opt --version + OUTPUT_VARIABLE WASM_OPT_OUTPUT + OUTPUT_STRIP_TRAILING_WHITESPACE +) + +string(REGEX MATCH version_[0-9]+ Binaryen_VERSION_tmp ${WASM_OPT_OUTPUT}) +string(REGEX MATCH [0-9]+ Binaryen_VERSION ${Binaryen_VERSION_tmp}) + +#cmake_print_variables(Binaryen_VERSION_tmp Binaryen_VERSION) + +find_package_handle_standard_args(Binaryen REQUIRED_VARS Binaryen_HOME VERSION_VAR Binaryen_VERSION) + +if(Binaryen_FOUND) + mark_as_advanced(Binaryen_SEARCH_PATH) + mark_as_advanced(Binaryen_VERSION_tmp) + mark_as_advanced(Binaryen_VERSION) + mark_as_advanced(WASM_OPT_OUTPUT) + + set(Binaryen_WASM_OPT ${Binaryen_HOME}/bin/wasm-opt) +else() + # TODO: install WASISDK +endif() diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/cmake/FindWASISDK.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/cmake/FindWASISDK.cmake new file mode 100644 index 00000000000..fff8aea4a59 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/cmake/FindWASISDK.cmake @@ -0,0 +1,38 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +# +# Output below variables: +# - WASISDK_HOME. the installation location +# - WASISDK_SYSROOT. where wasi-sysroot is +# - WASISDK_TOOLCHAIN. where wasi-sdk.cmake is +# + +include(CMakePrintHelpers) +include(FindPackageHandleStandardArgs) + +file(GLOB WASISDK_SEARCH_PATH "/opt/wasi-sdk-*") +find_path(WASISDK_HOME + NAMES share/wasi-sysroot + PATHS ${WASISDK_SEARCH_PATH} + NO_CMAKE_FIND_ROOT_PATH + NO_SYSTEM_ENVIRONMENT_PATH + REQUIRED +) + +string(REGEX MATCH [0-9]+\.[0-9]+\.*[0-9]* WASISDK_VERSION ${WASISDK_HOME}) + +#cmake_print_variables(WASISDK_HOME WASISDK_VERSION) +find_package_handle_standard_args(WASISDK REQUIRED_VARS WASISDK_HOME VERSION_VAR WASISDK_VERSION) + +if(WASISDK_FOUND) + mark_as_advanced(WASISDK_SEARCH_PATH) + mark_as_advanced(WASISDK_VERSION) + + set(WASISDK_CC_COMMAND ${WASISDK_HOME}/bin/clang) + set(WASISDK_CXX_COMMAND ${WASISDK_HOME}/bin/clang++) + set(WASISDK_SYSROOT ${WASISDK_HOME}/share/wasi-sysroot) + set(WASISDK_TOOLCHAIN ${WASISDK_HOME}/share/cmake/wasi-sdk.cmake) +else() + # TODO: install WASISDK +endif() diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/mysite/__init__.py b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/include/.gitkeep old mode 100755 new mode 100644 similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/mysite/__init__.py rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/include/.gitkeep diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/meshoptimizer/.gitignore b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/meshoptimizer/.gitignore similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/meshoptimizer/.gitignore rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/meshoptimizer/.gitignore diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/meshoptimizer/CMakeLists.txt b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/meshoptimizer/CMakeLists.txt new file mode 100644 index 00000000000..d6a1c358a62 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/meshoptimizer/CMakeLists.txt @@ -0,0 +1,38 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required (VERSION 3.14) + +project(bench-meshoptimizer) + +list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../cmake) + +################ dependencies ################ +find_package(Python3 REQUIRED) +find_package(WASISDK 16.0 REQUIRED) +execute_process( + COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_LIST_DIR}/../../../test-tools/pick-up-emscripten-headers/collect_files.py --install ../include --loglevel=ERROR + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} +) + +################ MESHOPTIMIZER ################ +include(ExternalProject) + +ExternalProject_Add(codecbench + PREFIX codecbench + GIT_REPOSITORY https://github.com/zeux/meshoptimizer.git + GIT_TAG f734fd572aed5bf76e84d9ed62ca6f4f6c47d84e + GIT_SHALLOW OFF + GIT_PROGRESS ON + SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/meshoptimizer + UPDATE_COMMAND git clean -fd && git checkout -- * + && ${CMAKE_COMMAND} -E echo "Applying patch" + && git apply ${CMAKE_CURRENT_SOURCE_DIR}/codecbench.patch + CONFIGURE_COMMAND ${CMAKE_COMMAND} + -DWASI_SDK_PREFIX=${WASISDK_HOME} + -DCMAKE_TOOLCHAIN_FILE=${WASISDK_TOOLCHAIN} + -DCMAKE_SYSROOT=${WASISDK_SYSROOT} + ${CMAKE_CURRENT_SOURCE_DIR}/meshoptimizer + BUILD_COMMAND make codecbench -j 4 + INSTALL_COMMAND ${CMAKE_COMMAND} -E copy_if_different ./codecbench.wasm ${CMAKE_CURRENT_BINARY_DIR}/codecbench.wasm +) diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/meshoptimizer/README.md b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/meshoptimizer/README.md similarity index 92% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/meshoptimizer/README.md rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/meshoptimizer/README.md index ceefb5723b8..466cd8759cb 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/meshoptimizer/README.md +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/meshoptimizer/README.md @@ -44,14 +44,14 @@ Firstly please build iwasm with simd support: ``` shell $ cd /product-mini/platforms/linux/ $ mkdir build && cd build -$ cmake .. -DWAMR_BUILD_SIMD=1 +$ cmake .. $ make ``` Then compile wasm file to aot file and run: ``` shell -$ /wamr-compiler/build/wamrc --enable-simd -o codecbench.aot codecbench.wasm +$ /wamr-compiler/build/wamrc -o codecbench.aot codecbench.wasm $ /product-mini/platforms/linux/build/iwasm codecbench.aot ``` diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/meshoptimizer/codecbench.patch b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/meshoptimizer/codecbench.patch similarity index 92% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/meshoptimizer/codecbench.patch rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/meshoptimizer/codecbench.patch index 667b8ab28fe..19db792bfb4 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/meshoptimizer/codecbench.patch +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/meshoptimizer/codecbench.patch @@ -1,8 +1,8 @@ diff --git a/CMakeLists.txt b/CMakeLists.txt -index b13d946..4254003 100644 +index 612cf3b..22a365a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt -@@ -149,3 +149,43 @@ install(FILES +@@ -158,3 +158,43 @@ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/meshoptimizerConfigVersion.cmake COMPONENT meshoptimizer DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/meshoptimizer) @@ -47,10 +47,10 @@ index b13d946..4254003 100644 + +add_dependencies(codecbench.opt codecbench) diff --git a/src/vertexcodec.cpp b/src/vertexcodec.cpp -index 821c467..b7d30b1 100644 +index 4bd1112..257c258 100644 --- a/src/vertexcodec.cpp +++ b/src/vertexcodec.cpp -@@ -83,13 +83,13 @@ +@@ -89,13 +89,13 @@ #endif #ifdef SIMD_WASM @@ -71,7 +71,7 @@ index 821c467..b7d30b1 100644 #endif namespace meshopt -@@ -691,7 +691,7 @@ static v128_t decodeShuffleMask(unsigned char mask0, unsigned char mask1) +@@ -757,7 +757,7 @@ static v128_t decodeShuffleMask(unsigned char mask0, unsigned char mask1) v128_t sm1 = wasm_v128_load(&kDecodeBytesGroupShuffle[mask1]); v128_t sm1off = wasm_v128_load(&kDecodeBytesGroupCount[mask0]); @@ -80,7 +80,7 @@ index 821c467..b7d30b1 100644 v128_t sm1r = wasm_i8x16_add(sm1, sm1off); -@@ -741,7 +741,7 @@ static const unsigned char* decodeBytesGroupSimd(const unsigned char* data, unsi +@@ -807,7 +807,7 @@ static const unsigned char* decodeBytesGroupSimd(const unsigned char* data, unsi v128_t shuf = decodeShuffleMask(mask0, mask1); @@ -89,7 +89,7 @@ index 821c467..b7d30b1 100644 wasm_v128_store(buffer, result); -@@ -763,7 +763,7 @@ static const unsigned char* decodeBytesGroupSimd(const unsigned char* data, unsi +@@ -829,7 +829,7 @@ static const unsigned char* decodeBytesGroupSimd(const unsigned char* data, unsi v128_t shuf = decodeShuffleMask(mask0, mask1); @@ -99,7 +99,7 @@ index 821c467..b7d30b1 100644 wasm_v128_store(buffer, result); diff --git a/src/vertexfilter.cpp b/src/vertexfilter.cpp -index 14a73b1..8f4b3c1 100644 +index 5c7589c..c79cad4 100644 --- a/src/vertexfilter.cpp +++ b/src/vertexfilter.cpp @@ -57,10 +57,10 @@ @@ -116,4 +116,4 @@ index 14a73b1..8f4b3c1 100644 +#define wasmx_unziphi_v32x4(a, b) wasm_i32x4_shuffle(a, b, 1, 3, 5, 7) #endif - namespace meshopt + #ifndef __has_builtin diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/preparation.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/preparation.sh similarity index 93% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/preparation.sh rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/preparation.sh index 3f49f0cf644..47b11ac567a 100755 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/preparation.sh +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/preparation.sh @@ -5,13 +5,13 @@ # readonly BUILD_CONTENT="/tmp/build_content" -readonly WABT_VER=1.0.23 +readonly WABT_VER=1.0.31 readonly WABT_FILE="wabt-${WABT_VER}-ubuntu.tar.gz" -readonly CMAKE_VER=3.16.2 +readonly CMAKE_VER=3.25.1 readonly CMAKE_FILE="cmake-${CMAKE_VER}-Linux-x86_64.sh" -readonly BINARYEN_VER=version_101 +readonly BINARYEN_VER=version_111 readonly BINARYEN_FILE="binaryen-${BINARYEN_VER}-x86_64-linux.tar.gz" -readonly BAZEL_VER=3.7.0 +readonly BAZEL_VER=6.0.0 readonly BAZEL_FILE=bazel-${BAZEL_VER}-installer-linux-x86_64.sh function DEBUG() { @@ -57,8 +57,8 @@ function install_emsdk() { git clone https://github.com/emscripten-core/emsdk.git cd emsdk git pull - ./emsdk install 2.0.26 - ./emsdk activate 2.0.26 + ./emsdk install 3.1.28 + ./emsdk activate 3.1.28 echo "source /opt/emsdk/emsdk_env.sh" >> "${HOME}"/.bashrc } diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/tensorflow/README.md b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/tensorflow/README.md similarity index 56% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/tensorflow/README.md rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/tensorflow/README.md index 164b6bb09a5..7bc7dd2597e 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/tensorflow/README.md +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/tensorflow/README.md @@ -1,29 +1,19 @@ "tensorflow" sample introduction ============== -This sample demonstrates how to build [tensorflow](https://github.com/tensorflow/tensorflow) into WebAssembly with emsdk toolchain and run it with iwasm. Please first install [emsdk](https://github.com/emscripten-core/emsdk): -```bash -git clone https://github.com/emscripten-core/emsdk.git -cd emsdk -./emsdk install 2.0.26 -./emsdk activate 2.0.26 -``` -And set up ensdk environment: -```bash -source emsdk_env.sh -``` -Then run +This sample demonstrates how to build [tensorflow](https://github.com/tensorflow/tensorflow) into WebAssembly with emsdk toolchain and run it with iwasm.: ```bash ./build.sh # for linux platform, or -./build.sh --sgx -# for linux-sgx platform or ./build.sh --threads -# for multi-thread execution (on linux platform) +# for multi-threading on linux platform +./build.sh --sgx +# for linux-sgx platform ``` to build tensorflow and run it with iwasm, which basically contains the following steps: +- clone emsdk under `/core/deps`, install and activate 2.0.26 - hack emcc to delete some objects in libc.a - build tf-lite with emcc compiler -- build iwasm with pthread enable and include libiary under libc-emcc +- build iwasm with lib-pthread and libc-emcc enabled - run benchmark model with iwasm: --max-secs 300: means the max training time cost is 5 minutes, you can adjust it by yourself diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/tensorflow/build.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/tensorflow/build.sh similarity index 59% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/tensorflow/build.sh rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/tensorflow/build.sh index 7289e617b6c..6df8db423bd 100755 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/tensorflow/build.sh +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/tensorflow/build.sh @@ -8,24 +8,20 @@ #################################### # build tensorflow-lite sample # #################################### -if [ ! -d "${EMSDK}" ]; then - echo "can not find emsdk. " - echo "please refer to https://emscripten.org/docs/getting_started/downloads.html " - echo "to install it, or active it by 'source emsdk_env.sh'" - exit -fi +BUILD_SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -set -xe +WAMR_DIR="${BUILD_SCRIPT_DIR}/../../.." +WAMR_PLATFORM_DIR="${WAMR_DIR}/product-mini/platforms" +WAMRC_DIR="${WAMR_DIR}/wamr-compiler" +CORE_DEPS_DIR="${WAMR_DIR}/core/deps" +EMSDK_DIR="${CORE_DEPS_DIR}/emsdk" -EMSDK_WASM_DIR="${EMSDK}/upstream/emscripten/cache/sysroot/lib/wasm32-emscripten" -BUILD_SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +EMSDK_WASM_DIR="${EMSDK_DIR}/upstream/emscripten/cache/sysroot/lib/wasm32-emscripten" OUT_DIR="${BUILD_SCRIPT_DIR}/out" TENSORFLOW_DIR="${BUILD_SCRIPT_DIR}/tensorflow" TF_LITE_BUILD_DIR="${TENSORFLOW_DIR}/tensorflow/lite/tools/make" -WAMR_PLATFORM_DIR="${BUILD_SCRIPT_DIR}/../../../product-mini/platforms" -WAMRC_DIR="${BUILD_SCRIPT_DIR}/../../../wamr-compiler" -function Clear_Before_Exit +function Clear_Before_Exit() { [[ -f ${TENSORFLOW_DIR}/tf_lite.patch ]] && rm -f ${TENSORFLOW_DIR}/tf_lite.patch @@ -34,7 +30,18 @@ function Clear_Before_Exit mv libc.a.bak libc.a } -# 1.hack emcc +set -xe + +# 1.clone emsdk +cd ${CORE_DEPS_DIR} +rm -fr emsdk +git clone https://github.com/emscripten-core/emsdk.git +cd emsdk +./emsdk install 2.0.26 +./emsdk activate 2.0.26 +source emsdk_env.sh + +# 2.hack emcc cd ${EMSDK_WASM_DIR} # back up libc.a cp libc.a libc.a.bak @@ -42,11 +49,13 @@ cp libc.a libc.a.bak emar d libc.a open.o emar d libc.a mmap.o emar d libc.a munmap.o +emar d libc.a library_pthread_stub.o +emar d libc.a pthread_self.o emranlib libc.a -# 2. build tf-lite +# 3. build tf-lite cd ${BUILD_SCRIPT_DIR} -# 2.1 clone tf repo from Github and checkout to 2303ed commit +# 3.1 clone tf repo from Github and checkout to 2303ed commit if [ ! -d "tensorflow" ]; then git clone https://github.com/tensorflow/tensorflow.git fi @@ -54,7 +63,7 @@ fi cd ${TENSORFLOW_DIR} git checkout 2303ed4bdb344a1fc4545658d1df6d9ce20331dd -# 2.2 copy the tf-lite.patch to tensorflow_root_dir and apply +# 3.2 copy the tf-lite.patch to tensorflow_root_dir and apply it cd ${TENSORFLOW_DIR} cp ${BUILD_SCRIPT_DIR}/tf_lite.patch . git checkout tensorflow/lite/tools/make/Makefile @@ -67,12 +76,12 @@ if [[ $(git apply tf_lite.patch 2>&1) =~ "error" ]]; then fi cd ${TF_LITE_BUILD_DIR} -# 2.3 download dependencies +# 3.3 download dependencies if [ ! -d "${TF_LITE_BUILD_DIR}/downloads" ]; then source download_dependencies.sh fi -# 2.4 build tf-lite target +# 3.4 build tf-lite target if [ -d "${TF_LITE_BUILD_DIR}/gen" ]; then rm -fr ${TF_LITE_BUILD_DIR}/gen fi @@ -82,56 +91,54 @@ make -j 4 -C "${TENSORFLOW_DIR}" -f ${TF_LITE_BUILD_DIR}/Makefile # remove patch file and recover emcc libc.a after building Clear_Before_Exit -# 2.5 copy /make/gen target files to out/ +# 3.5 copy /make/gen target files to out/ rm -rf ${OUT_DIR} mkdir ${OUT_DIR} cp -r ${TF_LITE_BUILD_DIR}/gen/linux_x86_64/bin/. ${OUT_DIR}/ -# 3. compile tf-model.wasm to tf-model.aot with wamrc -# 3.1 build wamr-compiler +# 4. compile tf-model.wasm to tf-model.aot with wamrc +# 4.1 build wamr-compiler cd ${WAMRC_DIR} ./build_llvm.sh rm -fr build && mkdir build cd build && cmake .. make -# 3.2 compile tf-mode.wasm to tf-model.aot +# 4.2 compile tf-mode.wasm to tf-model.aot WAMRC_CMD="$(pwd)/wamrc" cd ${OUT_DIR} if [[ $1 == '--sgx' ]]; then - ${WAMRC_CMD} --enable-simd -sgx -o benchmark_model.aot benchmark_model.wasm + ${WAMRC_CMD} -sgx -o benchmark_model.aot benchmark_model.wasm elif [[ $1 == '--threads' ]]; then - ${WAMRC_CMD} --enable-simd --enable-multi-thread -o benchmark_model.aot benchmark_model.wasm + ${WAMRC_CMD} --enable-multi-thread -o benchmark_model.aot benchmark_model.wasm else - ${WAMRC_CMD} --enable-simd -o benchmark_model.aot benchmark_model.wasm + ${WAMRC_CMD} -o benchmark_model.aot benchmark_model.wasm fi -# 4. build iwasm with pthread and libc_emcc enable +# 5. build iwasm with pthread and libc_emcc enable # platform: # linux by default # linux-sgx if $1 equals '--sgx' if [[ $1 == '--sgx' ]]; then cd ${WAMR_PLATFORM_DIR}/linux-sgx rm -fr build && mkdir build - cd build && cmake .. -DWAMR_BUILD_SIMD=1 -DWAMR_BUILD_LIB_PTHREAD=1 -DWAMR_BUILD_LIBC_EMCC=1 + cd build && cmake .. -DWAMR_BUILD_LIBC_EMCC=1 make cd ../enclave-sample make else cd ${WAMR_PLATFORM_DIR}/linux rm -fr build && mkdir build - cd build && cmake .. -DWAMR_BUILD_SIMD=1 -DWAMR_BUILD_LIB_PTHREAD=1 -DWAMR_BUILD_LIBC_EMCC=1 + cd build && cmake .. -DWAMR_BUILD_LIB_PTHREAD=1 -DWAMR_BUILD_LIBC_EMCC=1 make fi -# 5. run tensorflow with iwasm -cd ${BUILD_SCRIPT_DIR} -# 5.1 download tf-lite model -if [ ! -f mobilenet_quant_v1_224.tflite ]; then - wget "https://storage.googleapis.com/download.tensorflow.org/models/tflite/mobilenet_v1_224_android_quant_2017_11_08.zip" - unzip mobilenet_v1_224_android_quant_2017_11_08.zip -fi +# 6. run tensorflow with iwasm +cd ${OUT_DIR} +# 6.1 download tf-lite model +wget "https://storage.googleapis.com/download.tensorflow.org/models/tflite/mobilenet_v1_224_android_quant_2017_11_08.zip" +unzip mobilenet_v1_224_android_quant_2017_11_08.zip -# 5.2 run tf-lite model with iwasm +# 6.2 run tf-lite model with iwasm echo "---> run tensorflow benchmark model with iwasm" if [[ $1 == '--sgx' ]]; then IWASM_CMD="${WAMR_PLATFORM_DIR}/linux-sgx/enclave-sample/iwasm" @@ -139,13 +146,12 @@ else IWASM_CMD="${WAMR_PLATFORM_DIR}/linux/build/iwasm" fi -if [[ $1 == '--threads' ]]; then +if [[ $1 == '--threads' ]]; then ${IWASM_CMD} --heap-size=10475860 \ - ${OUT_DIR}/benchmark_model.aot --num_threads=4 \ + benchmark_model.aot --num_threads=4 \ --graph=mobilenet_quant_v1_224.tflite --max_secs=300 else ${IWASM_CMD} --heap-size=10475860 \ - ${OUT_DIR}/benchmark_model.aot \ + benchmark_model.aot \ --graph=mobilenet_quant_v1_224.tflite --max_secs=300 fi - diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/tensorflow/tf_lite.patch b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/tensorflow/tf_lite.patch similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/tensorflow/tf_lite.patch rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/tensorflow/tf_lite.patch diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/wasm-av1/.gitignore b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/wasm-av1/.gitignore similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/wasm-av1/.gitignore rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/wasm-av1/.gitignore diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/wasm-av1/CMakeLists.avx_wasm.txt b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/wasm-av1/CMakeLists.avx_wasm.txt similarity index 84% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/wasm-av1/CMakeLists.avx_wasm.txt rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/wasm-av1/CMakeLists.avx_wasm.txt index d1149612366..409665b3c6f 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/wasm-av1/CMakeLists.avx_wasm.txt +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/wasm-av1/CMakeLists.avx_wasm.txt @@ -1,14 +1,14 @@ # Copyright (C) 2019 Intel Corporation. All rights reserved. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -cmake_minimum_required (VERSION 2.8...3.16) +cmake_minimum_required (VERSION 3.14) project(testavx) -include(${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/preparation.cmake) +list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../../cmake) -# a workaround to let aom find our non-public headers -include_directories(${WASI_SDK_HOME}/share/wasi-sysroot/include/libc/musl) +################ dependencies ################ +find_package(Binaryen 111 REQUIRED) ################ AOM ################ set(ENABLE_CCACHE ON) @@ -62,7 +62,7 @@ add_dependencies(${PROJECT_NAME} aom) add_custom_target(${PROJECT_NAME}_opt ALL COMMAND - ${WASM_OPT} -Oz --enable-simd -o ${PROJECT_NAME}.opt.wasm ${PROJECT_NAME}.wasm + ${Binaryen_WASM_OPT} -Oz --enable-simd -o ${PROJECT_NAME}.opt.wasm ${PROJECT_NAME}.wasm BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.opt.wasm WORKING_DIRECTORY diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/wasm-av1/CMakeLists.txt b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/wasm-av1/CMakeLists.txt new file mode 100644 index 00000000000..3d263bfbe40 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/wasm-av1/CMakeLists.txt @@ -0,0 +1,44 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +cmake_minimum_required (VERSION 3.14) + +project(av1_wasm) + +list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../cmake) + +################ dependencies ################ +find_package(Python3 REQUIRED) +find_package(WASISDK 16.0 REQUIRED) +execute_process( + COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_LIST_DIR}/../../../test-tools/pick-up-emscripten-headers/collect_files.py --install ../include --loglevel=ERROR + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} +) + +####################################### +include(ExternalProject) + +################ av1 ################ +ExternalProject_Add(av1 + PREFIX av1 + GIT_REPOSITORY https://github.com/GoogleChromeLabs/wasm-av1.git + GIT_TAG master + GIT_PROGRESS ON + GIT_SHALLOW ON + SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/av1 + UPDATE_COMMAND git clean -fd && git checkout -- * + && ${CMAKE_COMMAND} -E echo "Copying pre-installed CMakeLists.txt" + && ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.avx_wasm.txt CMakeLists.txt + && git apply ../av1-clang.patch + CONFIGURE_COMMAND ${CMAKE_COMMAND} + -DWASI_SDK_PREFIX=${WASISDK_HOME} + -DCMAKE_TOOLCHAIN_FILE=${WASISDK_TOOLCHAIN} + -DCMAKE_SYSROOT=${WASISDK_SYSROOT} + -DCMAKE_C_FLAGS=-isystem\ ${CMAKE_CURRENT_SOURCE_DIR}/../include/sse\ -isystem\ ${CMAKE_CURRENT_SOURCE_DIR}/../include/libc/musl + ${CMAKE_CURRENT_SOURCE_DIR}/av1 + BUILD_COMMAND make testavx_opt -j 4 + INSTALL_COMMAND ${CMAKE_COMMAND} -E copy_if_different + testavx.opt.wasm + ${CMAKE_CURRENT_SOURCE_DIR}/av1/third_party/samples/elephants_dream_480p24.ivf + ${CMAKE_CURRENT_BINARY_DIR} +) diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/wasm-av1/README.md b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/wasm-av1/README.md similarity index 90% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/wasm-av1/README.md rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/wasm-av1/README.md index e7a92f2af6a..2166fe6aec9 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/wasm-av1/README.md +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/wasm-av1/README.md @@ -39,7 +39,7 @@ Firstly please build iwasm with simd support: ``` shell $ cd /product-mini/platforms/linux/ $ mkdir build && cd build -$ cmake .. -DWAMR_BUILD_SIMD=1 -DWAMR_BUILD_LIBC_EMCC=1 +$ cmake .. -DWAMR_BUILD_LIBC_EMCC=1 $ make ``` @@ -47,7 +47,7 @@ Then compile wasm file to aot file and run: ``` shell $ cd

-$ /wamr-compiler/build/wamrc --enable-simd -o testavx.aot testavx.wasm +$ /wamr-compiler/build/wamrc -o testavx.aot testavx.wasm # copy sample data like /samples/workload/wasm-av1/av1/third_party/samples/elephants_dream_480p24.ivf # make sure you declare the access priority of the directory in which the sample data is $ /product-mini/platforms/linux/build/iwasm --dir=. testavx.aot elephants_dream_480p24.ivf diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/wasm-av1/av1-clang.patch b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/wasm-av1/av1-clang.patch similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/wasm-av1/av1-clang.patch rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/wasm-av1/av1-clang.patch diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/wasm-av1/build.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/wasm-av1/build.sh similarity index 94% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/wasm-av1/build.sh rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/wasm-av1/build.sh index 7f82c6c524f..efa17eca6d7 100755 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/wasm-av1/build.sh +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/wasm-av1/build.sh @@ -85,12 +85,12 @@ cd build && cmake .. make # 3.2 compile wasm-av1.wasm to wasm-av1.aot cd ${OUT_DIR} -${WAMRC_CMD} --enable-simd -o testavx.aot testavx.wasm +${WAMRC_CMD} -o testavx.aot testavx.wasm # 4. build iwasm with pthread and libc_emcc enable cd ${WAMR_PLATFORM_DIR}/linux rm -fr build && mkdir build -cd build && cmake .. -DWAMR_BUILD_SIMD=1 -DWAMR_BUILD_LIB_PTHREAD=1 -DWAMR_BUILD_LIBC_EMCC=1 +cd build && cmake .. -DWAMR_BUILD_LIB_PTHREAD=1 -DWAMR_BUILD_LIBC_EMCC=1 make # 5. run wasm-av1 with iwasm diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/wasm-av1/wasm-av1.patch b/lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/wasm-av1/wasm-av1.patch similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/samples/workload/wasm-av1/wasm-av1.patch rename to lib/wasm-micro-runtime-WAMR-1.2.2/samples/workload/wasm-av1/wasm-av1.patch diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/.gitignore b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/.gitignore similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/.gitignore rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/.gitignore diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/README.md b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/README.md similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/README.md rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/README.md diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/docker-compose.yml b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/docker-compose.yml similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/docker-compose.yml rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/docker-compose.yml diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/Dockerfile b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/Dockerfile new file mode 100644 index 00000000000..a796725fa33 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/Dockerfile @@ -0,0 +1,9 @@ +FROM python:3.5 + +WORKDIR /app +COPY . /app + +# hadolint ignore=DL3013 +RUN pip install django --no-cache-dir + +ENTRYPOINT ["python", "manage.py", "runserver", "0.0.0.0:80"] diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/db.sqlite3 b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/db.sqlite3 similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/db.sqlite3 rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/db.sqlite3 diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/harness/__init__.py b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/devices/__init__.py old mode 100644 new mode 100755 similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/harness/__init__.py rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/devices/__init__.py diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/devices/admin.py b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/devices/admin.py similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/devices/admin.py rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/devices/admin.py diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/devices/apps.py b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/devices/apps.py similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/devices/apps.py rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/devices/apps.py diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/__init__.py b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/devices/migrations/__init__.py old mode 100644 new mode 100755 similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/__init__.py rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/devices/migrations/__init__.py diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/devices/models.py b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/devices/models.py similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/devices/models.py rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/devices/models.py diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/devices/templates/application.html b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/devices/templates/application.html similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/devices/templates/application.html rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/devices/templates/application.html diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/devices/templates/appstore.html b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/devices/templates/appstore.html similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/devices/templates/appstore.html rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/devices/templates/appstore.html diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/devices/templates/empty.html b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/devices/templates/empty.html similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/devices/templates/empty.html rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/devices/templates/empty.html diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/devices/templates/help.html b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/devices/templates/help.html similarity index 94% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/devices/templates/help.html rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/devices/templates/help.html index 9e9d63c9a3d..4ad7427ba44 100755 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/devices/templates/help.html +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/devices/templates/help.html @@ -33,7 +33,7 @@

2. In the terminal: cd ~/Download && ./simple -a 82.156.57.236 @@ -44,7 +44,7 @@

Notes:
We also have a UI-enabled runtime, please download here and enjoy. It may require + href="../static/upload/wasm_runtime_wgl">download here and enjoy. It may require a few more setups.

Before running the UI-enabled runtime, please install some required softwares:

sudo apt-get install libsdl2-2.0-0:i386

diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/devices/templates/mysite.html b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/devices/templates/mysite.html similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/devices/templates/mysite.html rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/devices/templates/mysite.html diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/devices/tests.py b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/devices/tests.py similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/devices/tests.py rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/devices/tests.py diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/devices/views.py b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/devices/views.py similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/devices/views.py rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/devices/views.py diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/manage.py b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/manage.py similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/manage.py rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/manage.py diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/cases/01-install/__init__.py b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/mysite/__init__.py old mode 100644 new mode 100755 similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/cases/01-install/__init__.py rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/mysite/__init__.py diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/mysite/settings.py b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/mysite/settings.py similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/mysite/settings.py rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/mysite/settings.py diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/mysite/urls.py b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/mysite/urls.py similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/mysite/urls.py rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/mysite/urls.py diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/mysite/wsgi.py b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/mysite/wsgi.py similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/mysite/wsgi.py rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/mysite/wsgi.py diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/server/Dockerfile b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/server/Dockerfile new file mode 100644 index 00000000000..371fa45b092 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/server/Dockerfile @@ -0,0 +1,6 @@ +FROM python:3.5 + +WORKDIR /app +COPY server/wasm_server.py /app/server/ + +ENTRYPOINT ["python", "server/wasm_server.py"] diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/server/wasm_server.py b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/server/wasm_server.py similarity index 96% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/server/wasm_server.py rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/server/wasm_server.py index 5edeb90aa07..970ec6f6015 100755 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/server/wasm_server.py +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/server/wasm_server.py @@ -16,14 +16,18 @@ import os attr_type_list = [ - "ATTR_NONE", - "ATTR_TYPE_SHORT", - "ATTR_TYPE_INT", + "ATTR_TYPE_BYTE", # = ATTR_TYPE_INT8 + "ATTR_TYPE_SHORT",# = ATTR_TYPE_INT16 + "ATTR_TYPE_INT", # = ATTR_TYPE_INT32 "ATTR_TYPE_INT64", - "ATTR_TYPE_BYTE", + "ATTR_TYPE_UINT8", "ATTR_TYPE_UINT16", + "ATTR_TYPE_UINT32", + "ATTR_TYPE_UINT64", "ATTR_TYPE_FLOAT", "ATTR_TYPE_DOUBLE", + "ATTR_NONE", + "ATTR_NONE", "ATTR_TYPE_BOOLEAN", "ATTR_TYPE_STRING", "ATTR_TYPE_BYTEARRAY" @@ -140,26 +144,38 @@ def decode_attr_container(msg): attr_type = attr_type_list[int(type_index[0])] buf = buf[1 : ] - if attr_type == "ATTR_TYPE_SHORT": + if attr_type == "ATTR_TYPE_BYTE": # = ATTR_TYPE_INT8 + (attr_value, ) = struct.unpack('@c', buf[0 : 1]) + buf = buf[1 : ] + # continue + elif attr_type == "ATTR_TYPE_SHORT": # = ATTR_TYPE_INT16 (attr_value, ) = struct.unpack('@h', buf[0 : 2]) buf = buf[2 : ] # continue - elif attr_type == "ATTR_TYPE_INT": - (attr_value, ) = struct.unpack('@I', buf[0 : 4]) + elif attr_type == "ATTR_TYPE_INT": # = ATTR_TYPE_INT32 + (attr_value, ) = struct.unpack('@i', buf[0 : 4]) buf = buf[4 : ] # continue elif attr_type == "ATTR_TYPE_INT64": (attr_value, ) = struct.unpack('@q', buf[0 : 8]) buf = buf[8 : ] # continue - elif attr_type == "ATTR_TYPE_BYTE": - (attr_value, ) = struct.unpack('@c', buf[0 : 1]) + elif attr_type == "ATTR_TYPE_UINT8": + (attr_value, ) = struct.unpack('@B', buf[0 : 1]) buf = buf[1 : ] # continue elif attr_type == "ATTR_TYPE_UINT16": (attr_value, ) = struct.unpack('@H', buf[0 : 2]) buf = buf[2 : ] # continue + elif attr_type == "ATTR_TYPE_UINT32": + (attr_value, ) = struct.unpack('@I', buf[0 : 4]) + buf = buf[4 : ] + # continue + elif attr_type == "ATTR_TYPE_UINT64": + (attr_value, ) = struct.unpack('@Q', buf[0 : 8]) + buf = buf[8 : ] + # continue elif attr_type == "ATTR_TYPE_FLOAT": (attr_value, ) = struct.unpack('@f', buf[0 : 4]) buf = buf[4 : ] diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/static/css/application.css b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/static/css/application.css similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/static/css/application.css rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/static/css/application.css diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/static/css/appstore.css b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/static/css/appstore.css similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/static/css/appstore.css rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/static/css/appstore.css diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/static/css/index.css b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/static/css/index.css similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/static/css/index.css rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/static/css/index.css diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/static/js/application.js b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/static/js/application.js similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/static/js/application.js rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/static/js/application.js diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/static/js/appstore.js b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/static/js/appstore.js similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/static/js/appstore.js rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/static/js/appstore.js diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/static/js/index.js b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/static/js/index.js similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/static/js/index.js rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/static/js/index.js diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/static/photo/app(1).png b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/static/photo/app(1).png similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/static/photo/app(1).png rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/static/photo/app(1).png diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/static/photo/application.png b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/static/photo/application.png similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/static/photo/application.png rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/static/photo/application.png diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/static/photo/delete.png b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/static/photo/delete.png similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/static/photo/delete.png rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/static/photo/delete.png diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/static/photo/download(1).png b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/static/photo/download(1).png similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/static/photo/download(1).png rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/static/photo/download(1).png diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/static/photo/menu.png b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/static/photo/menu.png similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/static/photo/menu.png rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/static/photo/menu.png diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/static/photo/milky-way-2695569_1280.jpg b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/static/photo/milky-way-2695569_1280.jpg similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/static/photo/milky-way-2695569_1280.jpg rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/static/photo/milky-way-2695569_1280.jpg diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/static/photo/net_device.png b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/static/photo/net_device.png similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/static/photo/net_device.png rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/static/photo/net_device.png diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/static/photo/software-icon-32081.png b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/static/photo/software-icon-32081.png similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/static/photo/software-icon-32081.png rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/static/photo/software-icon-32081.png diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/static/photo/totalblack.png b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/static/photo/totalblack.png similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/IoT-APP-Store-Demo/wasm_django/static/photo/totalblack.png rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/static/photo/totalblack.png diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/connection.wasm b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/connection.wasm new file mode 100644 index 0000000000000000000000000000000000000000..936e80cf6191552616e15ce1906c350b25964bd6 GIT binary patch literal 6280 zcma)AOKc=p6@BkjRsX6zQyxMX%`AA`Gb6m2IElasGZ0(}`4NeaVBhI!*Lb?R-Q81N zb}$<|fj}UHKu8D)5Cz2l|Jfi`0kQ}J!7LJq1xNu!2n80v0tpEb&bhCu-JY?c*mC=Q z?>+b2&wKq;ceTZoc!-gkae(D{L;8XL%=Q{jX_;Z`sQRZpyYA+dW zRW_21X_70y?DQtvMQ4)rNBMabaK@i(=2KN+vo;+SGga9$&9h-La&wi9?r=EnxsHE6 zOA@8Is0u9`;)&BnxauDSe}YS zS$DN;$&&T{G*7Y)c8xc)USaPchi>y+C)r9yxl`gST~G4PbbAU^y+LPVs%li@^h3sE zJc6+_3o1{YtkeVFuT-_~RkhI-{AfS$F&Oy9Xr*FQQXYGaR1l_6F+2k$vQL*1CCDz40&x z0dYFc3iIAt#YlhD&(#f-xCU|Acw61r=*W%^%<**C>0C&evy#@``t{9a61o)xA|4U=aJ;jo3>ItPN}g6bv=* zB7+ul7xPvFJPMFTJWUT7r31jENR!H(4VKXH(ZRTFKpG%uz!IG{ymLW?A!rguv_r0} zi##KGxENeQ6UIwbrch-RK4X$iCQwwMeh5}sSFh7-a?C+6`AqpXF}VgJw7a` zfR@iopt-=HPk&t6TiIa7xZ0qnbqpLg4*RFynmIRMAKtUzUZ2Qt-s-PhF7-kI^SdRt4cXZ6U zq(xGIC5dA3S4Bx6UlgQ4QIW2o&-#oM5m=);qL0%HG6bs02?gJI9EhQpv4G%J5|vcU zg5sA21#>7Uewjpm5w$+*G(j;d7_u-=3JS-eprve;NnCXWrQ!;T32)MR=LEp)syISO zpOhwI&79STuu;bW()SQN5k1aD5aY#BS}arH^#Ez<`QNb)&({v_T|fYs+2P?NgtSXe zm;YR`1s(zZ@Iehw;M3@xh~xP`h9QeeU0^Zt&9}vz?t&wLn4!&_a$3U4^VO3IAnzh4n$yqKlhd!EC)7Y6_9vn z@N7aT!P=I#Udw<$1&^a-Lxu0Kfe%q;^>I1O80^ZWR2VLzjg>IgM2P2I6%Mq)LAr>NY3&DYMZ zj-AwlC_N0VLTU6c1&41(P+g8t2-Pz}!4kM!l)DIdLl5yL6rF^$_-KxgS|0E2{29}=hWC*R>p~7a?lydcT&W) zOR9z-!y&d}uHtMtbrc;Rt__Z_mG-UYV?tX|d*Afq;#F zMgbc@=vwr3LO-h^moqB*D*G;R(Z8zfqhKOdi^(QHL@Cz;dvOdSmKl~zU(^zF5P6Z1 zw*>MWUm`^4Dye~vebfk5S5m{gLcI_MN@|2BpaMHS*a0v{3$hF&T#Q7WRiYYtLY@kb zG7V`unU~g4vaZ8FYVGeplcE2YZ^Jdj1%z2eS<&y7Bgh>IE<~15n6QFFv2KA*Udtd7 z0pRZNMOl_hFoeLpm}*xT9`Q1xrqaT}&FeH(*Z@PYhEZf04BDMwJg_h+TvA4Pu3--^ z#uWCx^w6Tx`+pQK=@3Ow5-*2H3=D~WNRNll??pVT#Pd>7Vj(RbJf&ws;3 zv8=bnF;5zPBQ(g3g$GWHCyny3S*qM^IDHs7ZAb{i_{W#afDR9QK^e{qeszi-rMi}; z=t~qW6XaD7;s@T8MqlAP1E^dOeVHRXURK-=Uhpu9a7Okm-p5%?wonyHw7il-r7llO zsi<;NGAcdVP@a^2ECwQD#15%FMFq4bwyC2l{5KQ&3KpqR!lbzJJ3_xjL?HBq%gG=M z4jGuN#T7Zm9W^!QLyY@K82q~X3(4`L?+XFQH{7a7BftFOo*PO`@*GCkyxLCnt_8+> zu@i23Xg@OWiOFVh0)gH=yYJd}QPXAc0HKbXY4mL(Ys+_Pj6g>87)Oo)|2Nq{p3d%V z;ZsP*lEX`C&<;vz3`WqvGQlsYxWNZ3uK4Cdw?Bgr!8J90$6d$WSNmgb8lcO<8^{Qg z<6pd%BZnj^j)A23iMeY8!|KvppNcN2(#OA?^D*%i)&kdaDs>sFfo9gcan`za)>@ji ztZUJPCG&epA|z_M;@VbI;8FK4vdBZJy{z8PsQ5l&M78^fkVyf5kW?X=!l;Xm=qX3G zo-<;w$1$?KFu|S0IL+TV zyTH9j8S>q2mUzXD82&>7MJ|g(sN8>-T&m)#8~!TLD&DPyKMy8jye@Xv*6<8BRd_DT z5_y0-W0Mc|^K0yAY^O=K)$b+tLU*(_#M>pFDo5kop6`#=Y8w0 z=4gTkJ6p)I=ezx3vbHzs9u~{tI}*Io+EZ)l1Gl_aU3dKr*IbL=>(t)+tL;y%$hGIT z1x=E*%4wTBfJr9eS}Mu1adyV81L5XqFdE-8vhwO_^X*B}YPHmf6DMqU(k~wuR#@cu^+`eXEwr{qjKicXJ*KB`; zH*4F?);Bls1Utpb+o54k3P|pEhy4#F7SGq~`Gx)a`v(a)7^3KV)%7#c@;Z(;Y3rV2 zi*Z1^#gRh$`P5w)>bwXN_^5u+wi3`x0bZAdGK(kIIqAbbC=d^Ip?W&)u7lxhyixep bp1#SRnl=vb@N~1+!}?Ycif8PpNkjb~Wl}=) literal 0 HcmV?d00001 diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/event_publisher.wasm b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/event_publisher.wasm new file mode 100644 index 0000000000000000000000000000000000000000..31dc1018fee8b100fa7d9ddbfd0b40148a465fa7 GIT binary patch literal 4958 zcma)AO>ZPe8Lq1C`KkB~+==ib@Q)#Q`d+*=-7tzmzTsC0 z^`^WKr1?>ERu139cqTvUnlkNR`z7gIn(o_h_Ta$D$ znI5G}qbB>lap@`8FxXAY!R+2_P!6|8gUL)Z>-DLv#m1@|w_T)3nPS)^E&O~hcY?uo zl5eMDzvP-5@8v~0E0dxW@bLYTNq#g|R(qw;dCz+*z>a?V=QpdXr2VJJVii42X&hkS?_R)L^bFfqthlI6V1-f97u*14o0*X}B_x>o50PzxBrNdw z3M96j8DV7fMK@O)rPoB=DWYd7)%uTZ*`C{feFcqv!=vM5v93hiCabgnyDjhz8`Q3vGZP0n4pv^b;#!2F!sXctLYy$LUjU9S#P)SPAlaDOD|{wCR{I z<5KMN4Jx2}JC$R*0Q>S;$2LtX>-S98XkyXyD(y280?&narP1g$>IT^0$i6qVg2wo$ zz*UZa06=ZRn{GC=2PQljXwb9idcx%%ZF;mPgau8|@=ZsJ4-EPQXu(F-4=RqlPqgQX zaJ1)20SbJH2!$ej!dE~gfuoE=OaSk&4b~J{Lu`-Yz;tdi9Klbg1{|_C#8A^1nGU>$ zZUv93Q7oe8h|-Ac+=Q0tWN~Q!CbFe8TlPjT00vrWnxk0z#bQ{I)yf-QhG1M$Zm{~M zB81TX)n%e-`YeM!hqDHWkXzVbm>i}}<71#@kjjkC>H4`=UgTtlSuSB#XCkPFxKqH~ zAm+-WNGZ5+X{`o|LvuDze{~z$=2Na+E)<4 zk`S;42rLOR3qDCk2$3F{;ZtEdf8x(SL|!H|V{ zuAoqk1^U9Yn8Yn#P@2A=DE$GfV(7YOSa6pLCuT{z0uQRih7f&&s5ODP9pklgQ$Q&I z=tpSlEDg3E|>7*l))pM z2W!a;BAq57A{-C;&r*hStgGmQja#Vs-YE(xZRMw2zWe<1ZrZrD5Lwx0;lLgUrEr2j zL)9V469<%lVsyn#y2x(O$4%__2u+?57#a}4HhR*~A<~x%RtI!CW~rktBA5f~oU+ek z7gmKl{U>-Lf+~V?J{!Z=P^2QHFV0v}ZP{Lx9y|xW!V}f0Lhxbn!2ol3dIN24Hu%Cc zF#Q^tj@`}+rRc?eYLGNeZiL?TAuShU`;0pkMyT4y0?<{>i2#cM+C1l>EQ9{OGy#Sq zkwFNLKh|rNSE&MvV5R!hcoFYV3$6eNMe0L{g|i5QEvzRwiV8si-rK7fek{0Gpan~~ zl72%0_I1}|%_vrnxK~$?J#|0iB#`yu5?NJ6rlr4dthmjE_BcamoQHS|#?gQn8nm{r zKM!3M;ZBD^cmg261{ei?B8;G?sQOn_?K%J+#}NDcqgnJ*_G9j1K=czzm<*eK2KQpj zj`--Uy2Cs=`^f7WEq#b3rKud@=x~l;Ob4`~c0_2Mfyh2*$Fd`E3N@LhOaGh2;T(%x z@z*q>I-Pk!e?Yt-^gn0GAPZH9z+l^SQR1m-`vM7u!#>=PV1SZiM@|^M>pv~g=4l~8aSC}o;Ot|U(X=LCNoxLi2K<|m&cMy9gW`~{)ZtRvPILwQF zL~vJNMTp9JEsMU#cI-ZqP@&eiHN?>Uz`dS+Mz|<)`us|Mx$6(OGta{Kz@yr zSm31XW%fThq!ob~p z7=H`nhV1nFeIq`bmL@67VtD7UOslCkmL#}ZD3f6hBtQfmJJWo8@3ED|yv3AZew2)N z%rM8@j!BB$!wK#kW*B)JE1YNnAH!rk{CsL~HMCpqot{5@kb(z8bnCt2_=ReB^MrdJ qhf*2pX$1+quzJw68qi_^Tt7L=46ad5wEqw4%?2v~ literal 0 HcmV?d00001 diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/event_subscriber.wasm b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/event_subscriber.wasm new file mode 100644 index 0000000000000000000000000000000000000000..1dce622f416ba3c81f8ac96d89e613269e5946c2 GIT binary patch literal 4015 zcmaJ^O^h5z6@FFSJu{x(UH5K&WNdzF#ZK150+I2g%72nl2fAr4%e3nxVQUUkn*FUI!DJze#_ z`rcRXr@EW`WGIM8Tsm=0Oz4`N;9^bq>fp-1Vj?DH3O_L8O8lSX2V%tv!UKCWP7|{E zwv?ptAPDop&>swmj58)??u~8C-HL7RC)6D0SW^y-3TghS4O1tfTYnV`(ovs>F z+8u(a?T77PkS$p&%)>+K$0-Txi8Zoq$8kuIBSeWR6)9~;jD(bqB}kN>uqHy^-*6|S z|Fq0k+?QV$)e?3c#fOsIC}hQ>C`e*R&ALTtsv}J!fmzo0)N!n_LIPp zC(44faK)MGU!Pigvn-s+*(v^!K9c>qIA`wVmZHncq<{BA7(6p|S_wtE(yPm+oJ#%P zk6=+kPi4=$$;(eGS|?ezunf3TuR&C|c_5XIMVOPly4_dS^E}4`Qu86eHA~+vc!L5< zfB2!bUw2pt%oa2OrwD9VegR8tqe=Ff@`2E=y__j}Am)mswt6*^TaWuwwsEs^l7zHu zr&L~EuAHd4OUo{kZxA)5(tms<<5qKOgb>s@3bLB=qQ04tvol#r**E#AA z6<{{QTm$Z@pLfnyRu&^KSrw)<8Q zX9#VBLn5@;Z^}DD-<}1q2sK-_3>3xDly?!i-1Xf8E-N4)5JzdyCM)-azLg8OUqHi# za?AEFfYyH~H{~h(-unU6HszDJ{X6HWDLwrr&tbxwr&Z{8m{e2NA!q`rC%s`)l72h$ zmbZ?JS{J=~R`ANXx=gOCtKRoaU$NgK*~=Q!J;&X3D#fLe>gn{~<^7oN5A^gu);^mK z;@DkdP{n`_VpHDkZ-uZX+(vTCRJ9ggK_3de_EqlJ1}%9a_~n#_WUa0)G+Ge?xYB-~ke8&~F2THv6{&I@2Cy_!Ku@7r07alBy> zLIYF1#G%y<&P}Q2sM6(S0~X4`6f|)L6bDjx-{s|JPI3`DCL+v{%^F4o)sTI&x3Ws& z_&-85JD}o2%*1*(s}7-QUEbl^tZ@pZ?V*RJM&C>(VPh8bu1n&>9ucVtWdUv}f<`{W zv|&)<3{#*tkbmzx%;UNzxfYOO;lT+ez9hs%Zq2>c1>9I$h=*Vl6JmR~udD(-CF1R} zXThG_dyArGir=&F?4e`V97E$^sgg{CI}m!`XBr-IsV!*%LRhHoFd>w9-b;)yPaWla z8Ama&c$E@?8@K^C0Fdne-4+ zmIeL_QpRbig8`?^JN(ova=?d$c)^(k6w=}0xJ5mf(s-Y#je+AT`ugQh_Pn379sW55 z2H^dSXEgqr*@TPIgwf;6(yFO@7;9+!b(yKfL#T z%{P?ws-=)9PP9>HI*Getu@SeAtYl?+?;(=B;dw1Wil0i&hFpnYSz2;EVQcoPIZ6zz z#@WE7b!>7TG}nFK!K?1H;@)xmK@g{n=pcykCY+K|{ors@olgia&2eB}!#7oMqnkdX z!bl}Se9&zNYR?ZlSV;Ih2%}W(biIDUA{uy+`K%MVU zV=o#8jX`g}G4Qt=qqvpg?Z0u|AI7awjNfFqG3>VEXd@nn{B_Z2M{&^bN286M*dGSh zqquKIp`UgSf{g?pU_qzhrzyUNqA>O0CVr+(8WY{^aT>sJl5Q5pbCl|ghoeopNEcLk zI0`luKJA*HyPyvI!5E{9H_i_RH>z`MvKPf^(OR%!p literal 0 HcmV?d00001 diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/request_handler.wasm b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/request_handler.wasm new file mode 100644 index 0000000000000000000000000000000000000000..85959790f665e373fcb998e8c554a47d09ab47d6 GIT binary patch literal 6776 zcma)BO^h5z6|So8p1+>8drgF_Adx^E2oOu4fJ8+2-mC7JUjGDa zdAh6W)q7uk@29HEBAg7Q5JE23?vh*LF13XpXN!J4{L&L$atnj_5%@=gc-T?u6Y3eY z$BBj;rAeA}24mrJV-WWHqmJ12bu zcyKaZU5PfLVQOc%<7qmvdamK|(^0xI*_^DTz0TUoU?NJny?!*zj1QtgXS^xO78V-7 zIBQIz)HW7bUD_J}NGBY2qQ14br_c|8X_%x!k}5lZuJLF%iB=}juxpoIhQYyTBg%}7 zlin~rl??%Y=S-LYSwnmHBg$^M;+BOJZdpp<2{b%W6{4z?>&dZn9M6$LmfqxSNptRq zza`AsMf$~i`C(Zr!PqF-RKgz(i9iM;nl)~%PXSo$TSOyYSiip-cGkpO_Mopb8V;jQ z+QVx%Oha*GH{P(0$tcMCy zs#=l4NM9X1RQvi3`g);-*_-00lA7)9*UIY&y>FQ9|2XS3w2>tK|0T4CG*wvBMq*xn z-C6gq&{cy}@QLm1ZQ=h&N@vT6hNF&YaZmu%%?m6)z=3NTHPCfQaMdTR+~RkT%|+DpQxgHoz1kryy|OCZnk z#Y&j2oEq5JK@C%NIW>}K$Qa0}VV-~r?6_bDz$`5qbXs9S0PAQe@&UX_s}%lTyz$bB zd4AhVtV{oQQo38Pq{#oR6LCY?fKbN}2=dkifu>tWw1RUhGV3z30o6vv@S;QjG+0Un zXW1Vf{DDbuFNT^W3J=qw_$oC#T{^zN!cu$a!fGgrGzEhU9-!&h?e@{#5l zNCVD>xT6Iy`oLpYgO=CLn9MWD-wg*qE#QBa6#MUy5@9;C+LSQk9D_YcQlt>e!+T{B z;@d*da>=qJOa3l$C+H8p!ODI;&r{O)8m*)0a=bS@*6Kl%R-_eg&>yf?YEl5yjf8%T zh^9yS0W8R}hPNqJcXd#p#wG?@C9QIq@X1D6d7o6r2LCi^8oQG z*UZ@);^1pE4*TQ+76_i89)rJa+u%XJJBqfI&;>mk2Kiee7~VHSq{Rgnz}9 zI2F(WH5Kba^t%lKJ;J6p4Y|QrnE+G?7qywlMx4}@?{iGjWb2!&&J-V5pe)U1!c7nC zbQAc*U_Hwb&^urEEl99z*}+;<=D|ZNHT5`njF2_Suhat_!9&z@E$}}|FOf>y)bMoHgn}w& z@Y$m2lUdQII>)q!PRwuCj1y;AYnTWq=&IjBq-u<cz-Uh5T}ns~FiE9~c??ww z4Hpe6GBs!e1PNGdQ~M`vCC>I3pCqfiFvWIA81%vt`g2n%Go^f8rM&^BXv{W90m#wS z%&|3qedtohmUKC8)OAh!gvBSX()zSS2c5H;zICPcF{%|EK}fQ}tOE~Gpb_XfxXkfa z0Em;tjXWFL9qrBqG2LzR2sX<3h_CCk9v3SpA)vm)v1bE=d;+v!1AAe{k@bmh0TCSE za-{$TzC?sVkw53lAteq|Mk2^Y+XicjSVL^DH62~G`&kVv+H+FfrBPJ0SbJ-_3a^1H zY~xz3HAV0_La9XzLU&Fm>nfck|0Lo{2Wscm+o#8K#2b<^=^~C@A)93L|b7wb+W-SCkbL zvRED$6zYe8hR|h7;<7C$C0kIGe-u_Ux$f^&NDGA%v!q#o2eX4MCI?UQ7DB*y$9RHj z^o}W@6mb2g%F@essdET@Ip3y;t$$^Q&@O?Zxvxid6nQ zH9w(j#7D4ske4g`) z?4DDxO-z4Dm>-Zu!-x0aJd2pexr;xDvM&F{!m<1CEV0es3g=ga;=s2QTv~AiHGkmm zJ{5eQ)RN&B_#pl*YEt6YF@?TIF;b7slWg@F`VGFzKy3db+<(54eil0j8yxxrd-7+}X#<;oB=~Fi;z6c^-1{z5 zf?b1l82V}e1$b2WY=pv&AW(!BYj79&{)^Qb345rYJ340{B)&Ec|+?&+n6^l+pnQL@qNMEXoP?DnHX;D&TKO7*GUu&dKEkxr9vI0^YK zQS95dPfsyH=l8k#Xg*JOa4Q^j#YgC-@}v54$s?CaPKRUMS3(sd(x<{6&7bw!`_8NJgXANStNh4xHJcc+8#vVcpDiqpo@+m#)6H>2%%tsi9MJ59WqtUb{r&zuHIa`_ z&Ww_@I9eFP%&Uy7jz;~f4Q-~;RfeWe_^vk?JJNoG!M7j1Wbn@LG-X0zDF~zC>6uh< m=oAuZzLx!`=99Xk>1uxtxHz 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 AyZ`_I literal 0 HcmV?d00001 diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/simple b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/simple new file mode 100755 index 0000000000000000000000000000000000000000..478a0f85f8674cde636b6f2f2d9d10b07f251560 GIT binary patch literal 387456 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 bp1#SRnl=vb@N~1+!}?Ycif8PpNkjb~Wl}=) literal 0 HcmV?d00001 diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/sys/event_publisher.wasm b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/sys/event_publisher.wasm new file mode 100644 index 0000000000000000000000000000000000000000..31dc1018fee8b100fa7d9ddbfd0b40148a465fa7 GIT binary patch literal 4958 zcma)AO>ZPe8Lq1C`KkB~+==ib@Q)#Q`d+*=-7tzmzTsC0 z^`^WKr1?>ERu139cqTvUnlkNR`z7gIn(o_h_Ta$D$ znI5G}qbB>lap@`8FxXAY!R+2_P!6|8gUL)Z>-DLv#m1@|w_T)3nPS)^E&O~hcY?uo zl5eMDzvP-5@8v~0E0dxW@bLYTNq#g|R(qw;dCz+*z>a?V=QpdXr2VJJVii42X&hkS?_R)L^bFfqthlI6V1-f97u*14o0*X}B_x>o50PzxBrNdw z3M96j8DV7fMK@O)rPoB=DWYd7)%uTZ*`C{feFcqv!=vM5v93hiCabgnyDjhz8`Q3vGZP0n4pv^b;#!2F!sXctLYy$LUjU9S#P)SPAlaDOD|{wCR{I z<5KMN4Jx2}JC$R*0Q>S;$2LtX>-S98XkyXyD(y280?&narP1g$>IT^0$i6qVg2wo$ zz*UZa06=ZRn{GC=2PQljXwb9idcx%%ZF;mPgau8|@=ZsJ4-EPQXu(F-4=RqlPqgQX zaJ1)20SbJH2!$ej!dE~gfuoE=OaSk&4b~J{Lu`-Yz;tdi9Klbg1{|_C#8A^1nGU>$ zZUv93Q7oe8h|-Ac+=Q0tWN~Q!CbFe8TlPjT00vrWnxk0z#bQ{I)yf-QhG1M$Zm{~M zB81TX)n%e-`YeM!hqDHWkXzVbm>i}}<71#@kjjkC>H4`=UgTtlSuSB#XCkPFxKqH~ zAm+-WNGZ5+X{`o|LvuDze{~z$=2Na+E)<4 zk`S;42rLOR3qDCk2$3F{;ZtEdf8x(SL|!H|V{ zuAoqk1^U9Yn8Yn#P@2A=DE$GfV(7YOSa6pLCuT{z0uQRih7f&&s5ODP9pklgQ$Q&I z=tpSlEDg3E|>7*l))pM z2W!a;BAq57A{-C;&r*hStgGmQja#Vs-YE(xZRMw2zWe<1ZrZrD5Lwx0;lLgUrEr2j zL)9V469<%lVsyn#y2x(O$4%__2u+?57#a}4HhR*~A<~x%RtI!CW~rktBA5f~oU+ek z7gmKl{U>-Lf+~V?J{!Z=P^2QHFV0v}ZP{Lx9y|xW!V}f0Lhxbn!2ol3dIN24Hu%Cc zF#Q^tj@`}+rRc?eYLGNeZiL?TAuShU`;0pkMyT4y0?<{>i2#cM+C1l>EQ9{OGy#Sq zkwFNLKh|rNSE&MvV5R!hcoFYV3$6eNMe0L{g|i5QEvzRwiV8si-rK7fek{0Gpan~~ zl72%0_I1}|%_vrnxK~$?J#|0iB#`yu5?NJ6rlr4dthmjE_BcamoQHS|#?gQn8nm{r zKM!3M;ZBD^cmg261{ei?B8;G?sQOn_?K%J+#}NDcqgnJ*_G9j1K=czzm<*eK2KQpj zj`--Uy2Cs=`^f7WEq#b3rKud@=x~l;Ob4`~c0_2Mfyh2*$Fd`E3N@LhOaGh2;T(%x z@z*q>I-Pk!e?Yt-^gn0GAPZH9z+l^SQR1m-`vM7u!#>=PV1SZiM@|^M>pv~g=4l~8aSC}o;Ot|U(X=LCNoxLi2K<|m&cMy9gW`~{)ZtRvPILwQF zL~vJNMTp9JEsMU#cI-ZqP@&eiHN?>Uz`dS+Mz|<)`us|Mx$6(OGta{Kz@yr zSm31XW%fThq!ob~p z7=H`nhV1nFeIq`bmL@67VtD7UOslCkmL#}ZD3f6hBtQfmJJWo8@3ED|yv3AZew2)N z%rM8@j!BB$!wK#kW*B)JE1YNnAH!rk{CsL~HMCpqot{5@kb(z8bnCt2_=ReB^MrdJ qhf*2pX$1+quzJw68qi_^Tt7L=46ad5wEqw4%?2v~ literal 0 HcmV?d00001 diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/sys/event_subscriber.wasm b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/sys/event_subscriber.wasm new file mode 100644 index 0000000000000000000000000000000000000000..1dce622f416ba3c81f8ac96d89e613269e5946c2 GIT binary patch literal 4015 zcmaJ^O^h5z6@FFSJu{x(UH5K&WNdzF#ZK150+I2g%72nl2fAr4%e3nxVQUUkn*FUI!DJze#_ z`rcRXr@EW`WGIM8Tsm=0Oz4`N;9^bq>fp-1Vj?DH3O_L8O8lSX2V%tv!UKCWP7|{E zwv?ptAPDop&>swmj58)??u~8C-HL7RC)6D0SW^y-3TghS4O1tfTYnV`(ovs>F z+8u(a?T77PkS$p&%)>+K$0-Txi8Zoq$8kuIBSeWR6)9~;jD(bqB}kN>uqHy^-*6|S z|Fq0k+?QV$)e?3c#fOsIC}hQ>C`e*R&ALTtsv}J!fmzo0)N!n_LIPp zC(44faK)MGU!Pigvn-s+*(v^!K9c>qIA`wVmZHncq<{BA7(6p|S_wtE(yPm+oJ#%P zk6=+kPi4=$$;(eGS|?ezunf3TuR&C|c_5XIMVOPly4_dS^E}4`Qu86eHA~+vc!L5< zfB2!bUw2pt%oa2OrwD9VegR8tqe=Ff@`2E=y__j}Am)mswt6*^TaWuwwsEs^l7zHu zr&L~EuAHd4OUo{kZxA)5(tms<<5qKOgb>s@3bLB=qQ04tvol#r**E#AA z6<{{QTm$Z@pLfnyRu&^KSrw)<8Q zX9#VBLn5@;Z^}DD-<}1q2sK-_3>3xDly?!i-1Xf8E-N4)5JzdyCM)-azLg8OUqHi# za?AEFfYyH~H{~h(-unU6HszDJ{X6HWDLwrr&tbxwr&Z{8m{e2NA!q`rC%s`)l72h$ zmbZ?JS{J=~R`ANXx=gOCtKRoaU$NgK*~=Q!J;&X3D#fLe>gn{~<^7oN5A^gu);^mK z;@DkdP{n`_VpHDkZ-uZX+(vTCRJ9ggK_3de_EqlJ1}%9a_~n#_WUa0)G+Ge?xYB-~ke8&~F2THv6{&I@2Cy_!Ku@7r07alBy> zLIYF1#G%y<&P}Q2sM6(S0~X4`6f|)L6bDjx-{s|JPI3`DCL+v{%^F4o)sTI&x3Ws& z_&-85JD}o2%*1*(s}7-QUEbl^tZ@pZ?V*RJM&C>(VPh8bu1n&>9ucVtWdUv}f<`{W zv|&)<3{#*tkbmzx%;UNzxfYOO;lT+ez9hs%Zq2>c1>9I$h=*Vl6JmR~udD(-CF1R} zXThG_dyArGir=&F?4e`V97E$^sgg{CI}m!`XBr-IsV!*%LRhHoFd>w9-b;)yPaWla z8Ama&c$E@?8@K^C0Fdne-4+ zmIeL_QpRbig8`?^JN(ova=?d$c)^(k6w=}0xJ5mf(s-Y#je+AT`ugQh_Pn379sW55 z2H^dSXEgqr*@TPIgwf;6(yFO@7;9+!b(yKfL#T z%{P?ws-=)9PP9>HI*Getu@SeAtYl?+?;(=B;dw1Wil0i&hFpnYSz2;EVQcoPIZ6zz z#@WE7b!>7TG}nFK!K?1H;@)xmK@g{n=pcykCY+K|{ors@olgia&2eB}!#7oMqnkdX z!bl}Se9&zNYR?ZlSV;Ih2%}W(biIDUA{uy+`K%MVU zV=o#8jX`g}G4Qt=qqvpg?Z0u|AI7awjNfFqG3>VEXd@nn{B_Z2M{&^bN286M*dGSh zqquKIp`UgSf{g?pU_qzhrzyUNqA>O0CVr+(8WY{^aT>sJl5Q5pbCl|ghoeopNEcLk zI0`luKJA*HyPyvI!5E{9H_i_RH>z`MvKPf^(OR%!p literal 0 HcmV?d00001 diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/sys/request_handler.wasm b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/IoT-APP-Store-Demo/wasm_django/static/upload/sys/request_handler.wasm new file mode 100644 index 0000000000000000000000000000000000000000..85959790f665e373fcb998e8c554a47d09ab47d6 GIT binary patch literal 6776 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 m=oAuZzLx!`=99Xk>1uxtxHz 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%0A`)r(itM@ai@ujv!?99jPmtt22w2mE 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 P&QY|ZS5&WNKL7s$13(Z} literal 0 HcmV?d00001 diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/binarydump-tool/CMakeLists.txt b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/binarydump-tool/CMakeLists.txt similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/binarydump-tool/CMakeLists.txt rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/binarydump-tool/CMakeLists.txt diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/binarydump-tool/binarydump.c b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/binarydump-tool/binarydump.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/binarydump-tool/binarydump.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/binarydump-tool/binarydump.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/README.md b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/README.md similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/README.md rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/README.md diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/__init__.py b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/__init__.py similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/__init__.py rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/__init__.py diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/framework/__init__.py b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/framework/__init__.py similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/framework/__init__.py rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/framework/__init__.py diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/framework/case_base.py b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/framework/case_base.py similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/framework/case_base.py rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/framework/case_base.py diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/framework/engine.py b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/framework/engine.py similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/framework/engine.py rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/framework/engine.py diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/framework/framework.py b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/framework/framework.py similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/framework/framework.py rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/framework/framework.py diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/framework/suite.py b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/framework/suite.py similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/framework/suite.py rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/framework/suite.py diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/framework/test_api.py b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/framework/test_api.py similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/framework/test_api.py rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/framework/test_api.py diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/framework/test_utils.py b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/framework/test_utils.py similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/framework/test_utils.py rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/framework/test_utils.py diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/cases/02-request/__init__.py b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/harness/__init__.py similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/cases/02-request/__init__.py rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/harness/__init__.py diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/harness/harness_api.py b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/harness/harness_api.py similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/harness/harness_api.py rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/harness/harness_api.py diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/host-clients/src/host_app_sample.c b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/host-clients/src/host_app_sample.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/host-clients/src/host_app_sample.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/host-clients/src/host_app_sample.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/host-clients/src/makefile b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/host-clients/src/makefile similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/host-clients/src/makefile rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/host-clients/src/makefile diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/set_dev_env.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/set_dev_env.sh similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/set_dev_env.sh rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/set_dev_env.sh diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/start.py b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/start.py similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/start.py rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/start.py diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/cases/03-event/__init__.py b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/__init__.py similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/cases/03-event/__init__.py rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/__init__.py diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/cases/04-request-internal/__init__.py b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/cases/01-install/__init__.py similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/cases/04-request-internal/__init__.py rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/cases/01-install/__init__.py diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/cases/01-install/case.py b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/cases/01-install/case.py similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/cases/01-install/case.py rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/cases/01-install/case.py diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/cases/05-event-internal/__init__.py b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/cases/02-request/__init__.py similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/cases/05-event-internal/__init__.py rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/cases/02-request/__init__.py diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/cases/02-request/case.py b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/cases/02-request/case.py similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/cases/02-request/case.py rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/cases/02-request/case.py diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/cases/06-timer/__init__.py b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/cases/03-event/__init__.py similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/cases/06-timer/__init__.py rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/cases/03-event/__init__.py diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/cases/03-event/case.py b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/cases/03-event/case.py similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/cases/03-event/case.py rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/cases/03-event/case.py diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/cases/07-sensor/__init__.py b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/cases/04-request-internal/__init__.py similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/cases/07-sensor/__init__.py rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/cases/04-request-internal/__init__.py diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/cases/04-request-internal/case.py b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/cases/04-request-internal/case.py similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/cases/04-request-internal/case.py rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/cases/04-request-internal/case.py diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/cases/08-on-destroy/__init__.py b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/cases/05-event-internal/__init__.py similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/cases/08-on-destroy/__init__.py rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/cases/05-event-internal/__init__.py diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/cases/05-event-internal/case.py b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/cases/05-event-internal/case.py similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/cases/05-event-internal/case.py rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/cases/05-event-internal/case.py diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/cases/__init__.py b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/cases/06-timer/__init__.py similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/cases/__init__.py rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/cases/06-timer/__init__.py diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/cases/06-timer/case.py b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/cases/06-timer/case.py similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/cases/06-timer/case.py rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/cases/06-timer/case.py diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/__init__.py b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/cases/07-sensor/__init__.py similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/__init__.py rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/cases/07-sensor/__init__.py diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/cases/07-sensor/case.py b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/cases/07-sensor/case.py similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/cases/07-sensor/case.py rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/cases/07-sensor/case.py diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/debug/osx/.placeholder b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/cases/08-on-destroy/__init__.py similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/debug/osx/.placeholder rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/cases/08-on-destroy/__init__.py diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/cases/08-on-destroy/case.py b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/cases/08-on-destroy/case.py similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/cases/08-on-destroy/case.py rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/cases/08-on-destroy/case.py diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/debug/windows/.placeholder b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/cases/__init__.py similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/debug/windows/.placeholder rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/cases/__init__.py diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/suite_setup.py b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/suite_setup.py similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/suite_setup.py rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/suite_setup.py diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/test-app/01_install.c b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/test-app/01_install.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/test-app/01_install.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/test-app/01_install.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/test-app/02_request.c b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/test-app/02_request.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/test-app/02_request.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/test-app/02_request.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/test-app/03_event.c b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/test-app/03_event.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/test-app/03_event.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/test-app/03_event.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/test-app/04_request_internal_req.c b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/test-app/04_request_internal_req.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/test-app/04_request_internal_req.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/test-app/04_request_internal_req.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/test-app/04_request_internal_resp.c b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/test-app/04_request_internal_resp.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/test-app/04_request_internal_resp.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/test-app/04_request_internal_resp.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/test-app/05_event_internal_provider.c b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/test-app/05_event_internal_provider.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/test-app/05_event_internal_provider.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/test-app/05_event_internal_provider.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/test-app/05_event_internal_subscriber.c b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/test-app/05_event_internal_subscriber.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/test-app/05_event_internal_subscriber.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/test-app/05_event_internal_subscriber.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/test-app/06_timer.c b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/test-app/06_timer.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/test-app/06_timer.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/test-app/06_timer.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/test-app/07_sensor.c b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/test-app/07_sensor.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/test-app/07_sensor.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/test-app/07_sensor.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/test-app/08_on_destroy.c b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/test-app/08_on_destroy.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/test-app/08_on_destroy.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/test-app/08_on_destroy.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/test-app/build.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/test-app/build.sh similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/test-app/build.sh rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/test-app/build.sh diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/tools/product/start.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/tools/product/start.sh similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/tools/product/start.sh rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/tools/product/start.sh diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/tools/product/stop.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/tools/product/stop.sh similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/01-life-cycle/tools/product/stop.sh rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/01-life-cycle/tools/product/stop.sh diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/__init__.py b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/readme.txt b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/readme.txt similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/component-test/suites/readme.txt rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/component-test/suites/readme.txt diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/host-tool/CMakeLists.txt b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/host-tool/CMakeLists.txt similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/host-tool/CMakeLists.txt rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/host-tool/CMakeLists.txt diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/host-tool/external/cJSON/LICENSE b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/host-tool/external/cJSON/LICENSE similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/host-tool/external/cJSON/LICENSE rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/host-tool/external/cJSON/LICENSE diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/host-tool/external/cJSON/cJSON.c b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/host-tool/external/cJSON/cJSON.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/host-tool/external/cJSON/cJSON.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/host-tool/external/cJSON/cJSON.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/host-tool/external/cJSON/cJSON.h b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/host-tool/external/cJSON/cJSON.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/host-tool/external/cJSON/cJSON.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/host-tool/external/cJSON/cJSON.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/host-tool/external/cJSON/cjson.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/host-tool/external/cJSON/cjson.cmake similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/host-tool/external/cJSON/cjson.cmake rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/host-tool/external/cJSON/cjson.cmake diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/host-tool/src/host_tool_utils.c b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/host-tool/src/host_tool_utils.c similarity index 79% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/host-tool/src/host_tool_utils.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/host-tool/src/host_tool_utils.c index 2b9051bbf47..9ea3d6ca98d 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/host-tool/src/host_tool_utils.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/host-tool/src/host_tool_utils.c @@ -15,11 +15,14 @@ typedef union jvalue { bool z; - int8_t b; - uint16_t c; - int16_t s; - int32_t i; - int64_t j; + int8_t i8; + uint8_t u8; + int16_t i16; + uint16_t u16; + int32_t i32; + uint32_t u32; + int64_t i64; + uint64_t u64; float f; double d; } jvalue; @@ -90,43 +93,64 @@ attr2json(const attr_container_t *attr_cont) type = *p++; switch (type) { - case ATTR_TYPE_SHORT: - bh_memcpy_s(&value.s, sizeof(int16_t), p, sizeof(int16_t)); - if (NULL == (obj = cJSON_CreateNumber(value.s))) + case ATTR_TYPE_BYTE: /* = ATTR_TYPE_INT8 */ + bh_memcpy_s(&value.i8, 1, p, 1); + if (NULL == (obj = cJSON_CreateNumber(value.i8))) + goto fail; + cJSON_AddItemToObject(root, key, obj); + p++; + break; + case ATTR_TYPE_SHORT: /* = ATTR_TYPE_INT16 */ + bh_memcpy_s(&value.i16, sizeof(int16_t), p, sizeof(int16_t)); + if (NULL == (obj = cJSON_CreateNumber(value.i16))) goto fail; cJSON_AddItemToObject(root, key, obj); /* another approach: cJSON_AddNumberToObject(root, key, value.s) */ p += 2; break; - case ATTR_TYPE_INT: - bh_memcpy_s(&value.i, sizeof(int32_t), p, sizeof(int32_t)); - if (NULL == (obj = cJSON_CreateNumber(value.i))) + case ATTR_TYPE_INT: /* = ATTR_TYPE_INT32 */ + bh_memcpy_s(&value.i32, sizeof(int32_t), p, sizeof(int32_t)); + if (NULL == (obj = cJSON_CreateNumber(value.i32))) goto fail; cJSON_AddItemToObject(root, key, obj); p += 4; break; case ATTR_TYPE_INT64: - bh_memcpy_s(&value.j, sizeof(uint64_t), p, sizeof(uint64_t)); - if (NULL == (obj = cJSON_CreateNumber(value.j))) + bh_memcpy_s(&value.i64, sizeof(int64_t), p, sizeof(int64_t)); + if (NULL == (obj = cJSON_CreateNumber(value.i64))) goto fail; cJSON_AddItemToObject(root, key, obj); p += 8; break; - case ATTR_TYPE_BYTE: - bh_memcpy_s(&value.b, 1, p, 1); - if (NULL == (obj = cJSON_CreateNumber(value.b))) + case ATTR_TYPE_UINT8: + bh_memcpy_s(&value.u8, 1, p, 1); + if (NULL == (obj = cJSON_CreateNumber(value.u8))) goto fail; cJSON_AddItemToObject(root, key, obj); p++; break; case ATTR_TYPE_UINT16: - bh_memcpy_s(&value.c, sizeof(uint16_t), p, sizeof(uint16_t)); - if (NULL == (obj = cJSON_CreateNumber(value.c))) + bh_memcpy_s(&value.u16, sizeof(uint16_t), p, sizeof(uint16_t)); + if (NULL == (obj = cJSON_CreateNumber(value.u16))) goto fail; cJSON_AddItemToObject(root, key, obj); p += 2; break; + case ATTR_TYPE_UINT32: + bh_memcpy_s(&value.u32, sizeof(uint32_t), p, sizeof(uint32_t)); + if (NULL == (obj = cJSON_CreateNumber(value.u32))) + goto fail; + cJSON_AddItemToObject(root, key, obj); + p += 4; + break; + case ATTR_TYPE_UINT64: + bh_memcpy_s(&value.u64, sizeof(uint64_t), p, sizeof(uint64_t)); + if (NULL == (obj = cJSON_CreateNumber(value.u64))) + goto fail; + cJSON_AddItemToObject(root, key, obj); + p += 8; + break; case ATTR_TYPE_FLOAT: bh_memcpy_s(&value.f, sizeof(float), p, sizeof(float)); if (NULL == (obj = cJSON_CreateNumber(value.f))) diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/host-tool/src/host_tool_utils.h b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/host-tool/src/host_tool_utils.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/host-tool/src/host_tool_utils.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/host-tool/src/host_tool_utils.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/host-tool/src/main.c b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/host-tool/src/main.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/host-tool/src/main.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/host-tool/src/main.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/host-tool/src/transport.c b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/host-tool/src/transport.c similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/host-tool/src/transport.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/host-tool/src/transport.c diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/host-tool/src/transport.h b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/host-tool/src/transport.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/host-tool/src/transport.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/host-tool/src/transport.h diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/pick-up-emscripten-headers/collect_files.py b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/pick-up-emscripten-headers/collect_files.py new file mode 100755 index 00000000000..7e832145f7c --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/pick-up-emscripten-headers/collect_files.py @@ -0,0 +1,245 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# + +""" +The script operates on such directories and files +|-- core +| `-- deps +| |-- emscripten +|-- samples +| `-- workloads +| |-- include +`-- test-tools + |-- pick-up-emscripten_headers + | |-- collect_files.py +""" + +import argparse +import hashlib +import logging +import os +import pathlib +import shutil +import sys +import tarfile +import tempfile +import urllib +import urllib.request + +logger = logging.getLogger("pick-up-emscripten-headers") + +external_repos = { + "emscripten": { + "sha256": "c5524755b785d8f4b83eb3214fdd3ac4b2e1b1a4644df4c63f06e5968f48f90e", + "store_dir": "core/deps/emscripten", + "strip_prefix": "emscripten-3.0.0", + "url": "https://github.com/emscripten-core/emscripten/archive/refs/tags/3.0.0.tar.gz", + } +} + +# TOOD: can we use headers from wasi-libc and clang directly ? +emscripten_headers_src_dst = [ + ("include/compat/emmintrin.h", "sse/emmintrin.h"), + ("include/compat/immintrin.h", "sse/immintrin.h"), + ("include/compat/smmintrin.h", "sse/smmintrin.h"), + ("include/compat/xmmintrin.h", "sse/xmmintrin.h"), + ("lib/libc/musl/include/pthread.h", "libc/musl/pthread.h"), + ("lib/libc/musl/include/signal.h", "libc/musl/signal.h"), + ("lib/libc/musl/include/netdb.h", "libc/musl/netdb.h"), + ("lib/libc/musl/include/sys/wait.h", "libc/musl/sys/wait.h"), + ("lib/libc/musl/include/sys/socket.h", "libc/musl/sys/socket.h"), + ("lib/libc/musl/include/setjmp.h", "libc/musl/setjmp.h"), + ("lib/libc/musl/arch/emscripten/bits/setjmp.h", "libc/musl/bits/setjmp.h"), +] + + +def checksum(name, local_file): + sha256 = hashlib.sha256() + with open(local_file, "rb") as f: + bytes = f.read(4096) + while bytes: + sha256.update(bytes) + bytes = f.read(4096) + + return sha256.hexdigest() == external_repos[name]["sha256"] + + +def download(url, local_file): + logger.debug(f"download from {url}") + urllib.request.urlretrieve(url, local_file) + return local_file.exists() + + +def unpack(tar_file, strip_prefix, dest_dir): + # extract .tar.gz to /tmp, then move back without strippred prefix directories + with tempfile.TemporaryDirectory() as tmp: + with tarfile.open(tar_file) as tar: + logger.debug(f"extract to {tmp}") + + def is_within_directory(directory, target): + + abs_directory = os.path.abspath(directory) + abs_target = os.path.abspath(target) + + prefix = os.path.commonprefix([abs_directory, abs_target]) + + return prefix == abs_directory + + def safe_extract(tar, path=".", members=None, *, numeric_owner=False): + + for member in tar.getmembers(): + member_path = os.path.join(path, member.name) + if not is_within_directory(path, member_path): + raise Exception("Attempted Path Traversal in Tar File") + + tar.extractall(path, members, numeric_owner=numeric_owner) + + safe_extract(tar, tmp) + + strip_prefix_dir = ( + pathlib.Path(tmp).joinpath(strip_prefix + os.path.sep).resolve() + ) + if not strip_prefix_dir.exists(): + logger.error(f"extract {tar_file.name} failed") + return False + + # mv /tmp/${strip_prefix} dest_dir/* + logger.debug(f"move {strip_prefix_dir} to {dest_dir}") + shutil.copytree( + str(strip_prefix_dir), + str(dest_dir), + copy_function=shutil.move, + dirs_exist_ok=True, + ) + + return True + + +def download_repo(name, root): + if not name in external_repos: + logger.error(f"{name} is not a known repository") + return False + + store_dir = root.joinpath(f'{external_repos[name]["store_dir"]}').resolve() + download_flag = store_dir.joinpath("DOWNLOADED") + if store_dir.exists() and download_flag.exists(): + logger.info( + f"bypass downloading '{store_dir.relative_to(root)}'. Or to remove it and try again if needs a new release" + ) + return True + + # download only when the target is neither existed nor broken + download_dir = pathlib.Path("/tmp/pick-up-emscripten-headers/") + download_dir.mkdir(exist_ok=True) + + tar_name = pathlib.Path(external_repos[name]["url"]).name + tar_file = download_dir.joinpath(tar_name) + if tar_file.exists(): + if checksum(name, tar_file): + logger.debug(f"use pre-downloaded {tar_file}") + else: + logger.debug(f"{tar_file} is broken, remove it") + tar_file.unlink() + + if not tar_file.exists(): + if not download(external_repos[name]["url"], tar_file) or not checksum( + name, tar_file + ): + logger.error(f"download {name} failed") + return False + + # unpack and removing *strip_prefix* + if not unpack(tar_file, external_repos[name]["strip_prefix"], store_dir): + return False + + # leave a FLAG + download_flag.touch() + + # leave download files in /tmp + logger.info(f"Has downloaed and stored in {store_dir.relative_to(root)}") + return True + + +def collect_headers(root, install_location): + if not install_location.exists(): + logger.error(f"{install_location} does not found") + return False + + install_flag = install_location.joinpath("INSTALLED").resolve() + if install_flag.exists(): + logger.info( + f"bypass downloading '{install_location}'. Or to remove it and try again if needs a new one" + ) + return True + + emscripten_home = root.joinpath( + f'{external_repos["emscripten"]["store_dir"]}' + ).resolve() + if not emscripten_home.exists(): + logger.error(f"{emscripten_home} does not found") + return False + + emscripten_headers = emscripten_home.joinpath("system").resolve() + for (src, dst) in emscripten_headers_src_dst: + src = emscripten_headers.joinpath(src) + dst = install_location.joinpath(dst) + dst.parent.mkdir(parents=True, exist_ok=True) + shutil.copy(src, dst) + + install_flag.touch() + logger.info(f"Has installed in {install_location}") + return True + + +def main(): + parser = argparse.ArgumentParser( + description="collect headers from emscripten for workload compilation" + ) + parser.add_argument( + "--install", + type=str, + required=True, + help="identify installation location", + ) + parser.add_argument( + "--loglevel", + type=str, + default="INFO", + choices=[ + "ERROR", + "WARNING", + "INFO", + ], + help="the logging level", + ) + options = parser.parse_args() + + console = logging.StreamHandler() + console.setFormatter(logging.Formatter("%(asctime)s - %(message)s")) + logger.setLevel(getattr(logging, options.loglevel)) + logger.addHandler(console) + logger.propagate = False + + # locate the root of WAMR + current_file = pathlib.Path(__file__) + if current_file.is_symlink(): + current_file = pathlib.Path(os.readlink(current_file)) + root = current_file.parent.joinpath("../..").resolve() + logger.info(f"The root of WAMR is {root}") + + # download repos + for repo in external_repos.keys(): + if not download_repo(repo, root): + return False + + if not collect_headers(root, pathlib.Path(options.install)): + return False + + return True + + +if __name__ == "__main__": + sys.exit(0 if main() else 1) diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/.gitattributes b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/.gitattributes similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/.gitattributes rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/.gitattributes diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/Media/Config_building_target.png b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/Media/Config_building_target.png similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/Media/Config_building_target.png rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/Media/Config_building_target.png diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/Media/build_folder.png b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/Media/build_folder.png similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/Media/build_folder.png rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/Media/build_folder.png diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/Media/build_terminal.png b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/Media/build_terminal.png similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/Media/build_terminal.png rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/Media/build_terminal.png diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/Media/change_workspace_dialog.png b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/Media/change_workspace_dialog.png similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/Media/change_workspace_dialog.png rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/Media/change_workspace_dialog.png diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/Media/compilation_config.png b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/Media/compilation_config.png similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/Media/compilation_config.png rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/Media/compilation_config.png diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/Media/compilation_config_2.png b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/Media/compilation_config_2.png similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/Media/compilation_config_2.png rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/Media/compilation_config_2.png diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/Media/debug.png b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/Media/debug.png similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/Media/debug.png rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/Media/debug.png diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/Media/decoration_for_files.png b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/Media/decoration_for_files.png similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/Media/decoration_for_files.png rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/Media/decoration_for_files.png diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/Media/docker_config.jpg b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/Media/docker_config.jpg similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/Media/docker_config.jpg rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/Media/docker_config.jpg diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/Media/docker_engine_config.png b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/Media/docker_engine_config.png similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/Media/docker_engine_config.png rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/Media/docker_engine_config.png diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/Media/docker_images.png b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/Media/docker_images.png similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/Media/docker_images.png rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/Media/docker_images.png diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/Media/install_from_vsix.png b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/Media/install_from_vsix.png similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/Media/install_from_vsix.png rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/Media/install_from_vsix.png diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/Media/new_project_page.png b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/Media/new_project_page.png similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/Media/new_project_page.png rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/Media/new_project_page.png diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/Media/open_project_page.png b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/Media/open_project_page.png similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/Media/open_project_page.png rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/Media/open_project_page.png diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/Media/project_template.png b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/Media/project_template.png similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/Media/project_template.png rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/Media/project_template.png diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/Media/right_click_menus_1.png b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/Media/right_click_menus_1.png similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/Media/right_click_menus_1.png rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/Media/right_click_menus_1.png diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/Media/right_click_menus_2.png b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/Media/right_click_menus_2.png similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/Media/right_click_menus_2.png rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/Media/right_click_menus_2.png diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/Media/run.png b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/Media/run.png similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/Media/run.png rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/Media/run.png diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/Media/save_configuration.png b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/Media/save_configuration.png similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/Media/save_configuration.png rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/Media/save_configuration.png diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/Media/set_up_workspace_message.png b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/Media/set_up_workspace_message.png similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/Media/set_up_workspace_message.png rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/Media/set_up_workspace_message.png diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/Media/wamr_ide_main_menu.png b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/Media/wamr_ide_main_menu.png similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/Media/wamr_ide_main_menu.png rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/Media/wamr_ide_main_menu.png diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/README.md b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/README.md similarity index 62% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/README.md rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/README.md index d5adbad9679..8a6e1509f59 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/README.md +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/README.md @@ -14,17 +14,17 @@ The WAMR-IDE is an Integrated Development Environment to develop WebAssembly app ## How to setup WAMR IDE -Note: Please ensure that the scripts under `resource` directories have -execution permission. While on git they have x bits, you might have dropped -them eg. by copying them from Windows. -Similarly, do not drop execution permission when copying `lldb` binaries -under `resource/debug/bin`. +Now, we have same version tagged docker images, lldb binaries and VS Code installation file(.vsix file) packed for each GitHub release. So if you simply want to use WAMR debugging features in VS Code, the ideal(and effortless) way is following the tutorial in [this section](#21-download-wamr-vs-code-extension-from-the-github-releaserecommended-approach). -#### 1. Install `VSCode` on host. +Alternatively, if you want to build lldb, docker images, or .vsix file locally so that you can try the effect of your modification, you could refer to the tutorial in [this section](#22-build-wamr-vs-code-extension-locallyalternative-approach). + +### 1. Preparation + +#### 1.1. Install `VSCode` on host - make sure the version of [vscode](https://code.visualstudio.com/Download) you installed is at least _1.59.0_ -#### 2. Install `Docker` on host. +#### 1.2. Install `Docker` on host 1. [Windows: Docker Desktop](https://docs.docker.com/desktop/windows/install/) 2. [Ubuntu: Docker Engine](https://docs.docker.com/engine/install/ubuntu) @@ -37,7 +37,56 @@ under `resource/debug/bin`. - Ubuntu Bionic 18.04(LTS) ``` -#### 3. Build docker images +### 2. WAMR VS Code extension: download from the GitHub release or build locally + +#### 2.1 Download WAMR VS Code extension from the GitHub release(Recommended approach) + +##### 2.1.1 Load docker images from the GitHub release tar file + +From now on, for each GitHub release, we have the same version tagged docker image saved as a tar file, which you can find and download in the GitHub release. + +You could download the tar archive files for docker images from the release, and then load them using the following commands: + +```sh +# download the zip or tar.gz from release depending on your platform +# decompress and get the tar file + +# on Linux/MacOS, you could use tar +tar xf wasm-toolchain-{version number}.tar.gz +tar xf wasm-debug-server-{version number}.tar.gz +# or you could use unzip +unzip wasm-toolchain-{version number}.zip +unzip wasm-debug-server-{version number}.zip +# load wasm-toolchain +docker load --input wasm-toolchain.tar +# load wasm-debug-server +docker load --input wasm-debug-server.tar + +# on Windows, you could use any unzip software you like +# then loading docker images using powershell or git bash +# load wasm-toolchain +docker load --input ./wasm-toolchain.tar +# load wasm-debug-server +docker load --input ./wasm-debug-server.tar +``` + +##### 2.1.2 Download the VS Code extension installation file from the GitHub release + +From now on, for each GitHub release, we have the same version tagged zip/tar.gz file. For example, in release version 1.1.2, you can easily download and decompress `wamr-ide-1.1.2.tar.gz` `wamr-ide-1.1.2.zip`, which contains `wamr-ide.vsix` VS Code extension installation file. As you can imagine, in the future, when new releases are available, you can freely choose whichever version(for example, 1.2.0, 1.3.0, etc.) you prefer. It should work as long as you download the same version tagged docker image and .vsix file. + +##### 2.1.3 Install extension from vsix + +![install_from_vsix](./Media/install_from_vsix.png "install wamr-ide from vsix") + +select `wamr-ide.vsix` which you have decompressed from `.tar.gz` or `.zip` file. + +#### 2.2 Build WAMR VS Code extension locally(Alternative approach) + +You could also build the VS Code extension locally, the following instruction provides a thorough tutorial. It's worth noting that in the local build tutorial we use hard-coded tag version 1.0 other than the semantic version of WAMR. + +Note: Please ensure that the scripts under `resource` directories have execution permission. While on git they have x bits, you might have dropped them eg. by copying them from Windows. Similarly, do not drop execution permission when copying `lldb` binaries under `resource/debug/bin`. + +##### 2.2.1 Build docker images on host We have 2 docker images which should be built or loaded on your host, `wasm-toolchain` and `wasm-debug-server`. To build these 2 images, please enter the `WASM-Debug-Server/Docker` & `WASM-Toolchain/Docker`, then execute the `build_docker_image` script respectively. @@ -59,11 +108,11 @@ $ cd ./WASM-Debug-Server/Docker $ ./build_docker_image.sh ``` -#### After building, you can find `wasm-toolchain` and `wasm-debug-server` docker images on your local +##### 2.2.2 After building, you can find `wasm-toolchain` and `wasm-debug-server` docker images on your local ![docker-images](./Media/docker_images.png) -#### If building docker images fail during the process +##### 2.2.3 If building docker images fail during the process Sometimes building the Docker images may fail due to bad network conditions. If the `wasm-toolchain` and `wasm-debug-server` images do not exist after building, please build them manually. Fix the proxy setting if needed and execute the following command to build docker images. @@ -83,15 +132,15 @@ $ docker build --no-cache --build-arg http_proxy=http://proxy.example.com:1234 --build-arg https_proxy=http://proxy.example.com:1234 -t wasm-toolchain:1.0 . ``` -#### If you encounter the problem `failed to solve with frontend dockerfile.v0: failed to create LLB definition`, please config your docker desktop +##### 2.2.4 If you encounter the problem `failed to solve with frontend dockerfile.v0: failed to create LLB definition`, please config your docker desktop ![docker-engine-config](./Media/docker_engine_config.png) -#### Points To Remember +##### 2.2.5 Points To Remember - Make sure that the `wasm-toolchain:1.0` and `wasm-debug-server:1.0` docker images are both successfully built before using `WAMR IDE`, otherwise `Build`, `Run` and `Debug` will not work. -#### 4. Generate wamride extension package file +##### 2.2.6 Generate wamride extension package file `wamride-1.0.0.vsix` can be packaged by [`npm vsce`](https://code.visualstudio.com/api/working-with-extensions/publishing-extension). @@ -103,14 +152,29 @@ $ npm install $ vsce package ``` -Note that patched `lldb` should be built and put into the `VSCode-Extension/resource/debug` folder before your package or extension debug process if you want to enable `source debugging` feature. -Please follow this [instruction](../../doc/source_debugging.md#debugging-with-interpreter) to build `lldb`. -Please follow this [instruction](./VSCode-Extension/resource/debug/README.md) -to copy the binaries. +##### 2.2.7 Enable VS Code debugging feature + +By default, when you build .vsix locally, the debugging feature is off. Suppose you want to enable the source debugging feature. In that case, you could download `lldb` binaries from our GitHub release (for example, `wamr-lldb-1.1.2-x86_64-ubuntu-20.04.tar.gz`), decompress and put every subdirectory and file to the installed directory of your VS Code extension. + +For example, let's say you are on an Ubuntu 20.04 machine. You first download and decompress `wamr-lldb-1.1.2-x86_64-ubuntu-20.04.tar.gz`, and you will get a `wamr-lldb` folder (or `inst` folder in our earlier release). Then, you can simply copy the files and directory inside that folder to the relative path `resource/debug/linux/` under your VS Code extension installation directory. + +Example commands on an Ubuntu 20.04 machine: + +```shell +# decompress .tar.gz file and get the folder +$ ls wamr-lldb +bin lib package.json syntaxes +# copy everything to the vscode extension installation path(in this case, it's /home/{usrname}/.vscode-server/extensions/wamr.wamride-1.0.0/) +$ cp inst/* /home/{usrname}/.vscode-server/extensions/wamr.wamride-1.0.0/resource/debug/linux/ +``` + +If you want to use your own patched `lldb`, you could follow this [instruction](../../doc/source_debugging.md#debugging-with-interpreter) to build `lldb`. And follow this [instruction](./VSCode-Extension/resource/debug/README.md) +to copy the binaries to replace the existing ones. + > **You can also debug the extension directly follow this [instruction](./VSCode-Extension/README.md) without packing the extension.** -#### 5. Install extension from vsix +##### 2.2.7 Install extension from vsix ![install_from_vsix](./Media/install_from_vsix.png "install wamr-ide from vsix") @@ -184,7 +248,7 @@ Click `Change workspace` button, a dialog will show as following. You can select ![right click menus](./Media/right_click_menus_2.png "right click menus") - #### After setting up `include path` and `exclude files`, the corresponding folder and files will be decorated with color and icon as following picture shows. +#### After setting up `include path` and `exclude files`, the corresponding folder and files will be decorated with color and icon as following picture shows ![decoration for files](./Media/decoration_for_files.png "decoration for files") diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/Script/build.bat b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/Script/build.bat similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/Script/build.bat rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/Script/build.bat diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/Script/build.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/Script/build.sh similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/Script/build.sh rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/Script/build.sh diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/.eslintrc.json b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/.eslintrc.json similarity index 66% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/.eslintrc.json rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/.eslintrc.json index f9b22b793c2..5c1fd464cc7 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/.eslintrc.json +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/.eslintrc.json @@ -1,13 +1,12 @@ { "root": true, "parser": "@typescript-eslint/parser", + "extends": ["plugin:@typescript-eslint/recommended"], "parserOptions": { - "ecmaVersion": 6, + "ecmaVersion": "latest", "sourceType": "module" }, - "plugins": [ - "@typescript-eslint" - ], + "plugins": ["@typescript-eslint"], "rules": { "@typescript-eslint/naming-convention": "warn", "@typescript-eslint/semi": "warn", @@ -16,9 +15,5 @@ "no-throw-literal": "warn", "semi": "off" }, - "ignorePatterns": [ - "out", - "dist", - "**/*.d.ts" - ] + "ignorePatterns": ["out", "dist", "**/*.d.ts"] } diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/.gitignore b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/.gitignore similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/.gitignore rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/.gitignore diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/.prettierrc.json b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/.prettierrc.json similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/.prettierrc.json rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/.prettierrc.json diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/.vscode/extensions.json b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/.vscode/extensions.json similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/.vscode/extensions.json rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/.vscode/extensions.json diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/.vscode/launch.json b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/.vscode/launch.json similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/.vscode/launch.json rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/.vscode/launch.json diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/.vscode/tasks.json b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/.vscode/tasks.json similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/.vscode/tasks.json rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/.vscode/tasks.json diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/.vscodeignore b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/.vscodeignore similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/.vscodeignore rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/.vscodeignore diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/CONTRIBUTING.md b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/CONTRIBUTING.md new file mode 100644 index 00000000000..f70a959ebc7 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/CONTRIBUTING.md @@ -0,0 +1,34 @@ +# CONTRIBUTING + +## Pull requests + +To submit your change: + +- Make sure your code is in line with our + [coding conventions](##Coding-conventions). +- Create an [issue] describing the bug the PR fixes or the feature you intend + to implement. +- Submit a [pull request] into the main branch. + +## Coding conventions + +#### Format + +The codebase is formatted by `Prettier` and the `.prettierrc.json` has been +configured. + +- VSCode along with `Format on Save` configuration could easily format your + code during development. +- You can run `prettier-format-check` and `prettier-format-apply` to check and + format your codebase with `prettier` in terminal. + +#### Lint + +`ESlint` is used as linter for the codebase and the `.eslintrc.json` has been +configured. + +- It's suggested to run `npm run lint` then fix errors and warnings before + committing. + +[issue]: https://github.com/bytecodealliance/wasm-micro-runtime/issues +[pull request]: https://github.com/bytecodealliance/wasm-micro-runtime/pulls diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/LICENSE b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/LICENSE similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/LICENSE rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/LICENSE diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/README.md b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/README.md similarity index 54% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/README.md rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/README.md index 21786f8c71c..739e39a726b 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/README.md +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/README.md @@ -3,10 +3,16 @@ ### An integrated development environment for WASM. # How to debug this extension - -> Note that please build `lldb` firstly follow this -> [instruction](./resource/debug/README.md) if you want to enable -> `source debugging` feature of this extension +> Note that when you download and +> decompress to get .vsix file from [our release](https://github.com/bytecodealliance/wasm-micro-runtime/releases). +> It's by default that the `source debugging` feature is not enabled. +> If you want to enable the `source debugging` feature of this extension, +> you could download `lldb` from [our release](https://github.com/bytecodealliance/wasm-micro-runtime/releases) +> (This is the recommended way, and you could do it with a single click in VS Code). +> Then if you want to use your customized lldb patch, +> you could build your own version of `lldb` +> and then follow this [instruction](./resource/debug/README.md) +> to put them in the correct path ### 1. open `VSCode_Extension` directory with the `vscode` diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/package.json b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/package.json similarity index 96% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/package.json rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/package.json index 4550452373b..dfe37961bd7 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/package.json +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/package.json @@ -1,12 +1,12 @@ { "name": "wamride", - "publisher": "wamr", + "publisher": "wamr-ide", "repository": { "url": "https://github.com/bytecodealliance/wasm-micro-runtime/tree/main/test-tools/wamr-ide" }, "displayName": "WAMR-IDE", "description": "An Integrated Development Environment for WASM", - "version": "1.0.0", + "version": "1.2.1", "engines": { "vscode": "^1.59.0" }, @@ -129,7 +129,7 @@ "program": "./resource/debug/windows/bin/lldb-vscode.exe" }, "osx": { - "program": "./resource/debug/osx/bin/lldb-vscode" + "program": "./resource/debug/darwin/bin/lldb-vscode" }, "linux": { "program": "./resource/debug/linux/bin/lldb-vscode" @@ -229,6 +229,7 @@ "watch": "tsc -watch -p ./", "pretest": "npm run compile && npm run lint", "lint": "eslint src --ext ts", + "lint-fix": "eslint --fix src --ext ts", "test": "node ./out/test/runTest.js", "prettier-format-check": "prettier --config .prettierrc.json 'src/**/*.ts' --check", "prettier-format-apply": "prettier --config .prettierrc.json 'src/**/*.ts' --write" @@ -237,7 +238,9 @@ "@types/glob": "^7.1.3", "@types/mocha": "^8.2.2", "@types/node": "14.x", + "@types/request": "^2.48.8", "@types/vscode": "^1.54.0", + "@types/yauzl": "^2.10.0", "@typescript-eslint/eslint-plugin": "^4.26.0", "@typescript-eslint/parser": "^4.26.0", "eslint": "^7.32.0", @@ -248,6 +251,8 @@ "vscode-test": "^1.5.2" }, "dependencies": { - "@vscode/webview-ui-toolkit": "^0.8.4" + "@vscode/webview-ui-toolkit": "^0.8.4", + "request": "^2.88.2", + "yauzl": "^2.10.0" } } diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/debug/README.md b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/debug/README.md new file mode 100644 index 00000000000..403e35ae9cf --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/debug/README.md @@ -0,0 +1,15 @@ +### If you want to enable `source debugging` for this extension and use your own patched `lldb`, please build `lldb` firstly following this [instruction](../../../../../doc/source_debugging.md#debugging-with-interpreter) + +### After building(`linux` for example), create `bin` folder and `lib` folder respectively in `linux` directory, add following necessary target files into the folders + +```shell +/llvm/build-lldb/bin/lldb # move this file to {VS Code directory}/resource/debug/linux/bin/ +/llvm/build-lldb/bin/lldb-vscode # move this file to {VS Code directory}/resource/debug/linux/bin/ +/llvm/build-lldb/lib/liblldb.so.13 # move this file to {VS Code directory}/resource/debug/linux/lib/ +``` + +> If you are debugging this extension following this [tutorial](../../README.md), {VS Code directory} will be `{WAMR root directory}/test-tools/wamr-ide/VSCode-Extension`. If you want to replace the current lldb with your own patched version so that you can use your patched lldb in VS Code, {VS Code directory} will be `~/.vscode/extensions/wamr.wamride-1.1.2` or `~/.vscode-server/extensions/wamr.wamride-1.1.2`. + +Note: For macOS, the library is named like `liblldb.13.0.1.dylib`. + +### Then you can start the extension and run the execute source debugging by clicking the `debug` button in the extension panel. diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/debug/darwin/.placeholder b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/debug/darwin/.placeholder new file mode 100644 index 00000000000..e69de29bb2d diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/debug/linux/.placeholder b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/debug/linux/.placeholder new file mode 100644 index 00000000000..e69de29bb2d diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/debug/windows/.placeholder b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/debug/windows/.placeholder new file mode 100644 index 00000000000..e69de29bb2d diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/scripts/CMakeLists.txt b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/scripts/CMakeLists.txt similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/scripts/CMakeLists.txt rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/scripts/CMakeLists.txt diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/scripts/boot_debugger_server.bat b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/scripts/boot_debugger_server.bat similarity index 88% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/scripts/boot_debugger_server.bat rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/scripts/boot_debugger_server.bat index 343049716f8..7fd1f024aad 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/scripts/boot_debugger_server.bat +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/scripts/boot_debugger_server.bat @@ -6,5 +6,5 @@ docker run --rm -it --name=wasm-debug-server-ctr ^ -v "%cd%":/mnt ^ -p 1234:1234 ^ - wasm-debug-server:1.0 ^ + wasm-debug-server:%2 ^ /bin/bash -c "./debug.sh %1" diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/scripts/boot_debugger_server.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/scripts/boot_debugger_server.sh similarity index 89% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/scripts/boot_debugger_server.sh rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/scripts/boot_debugger_server.sh index 97e290fcea7..169fb7e5f43 100755 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/scripts/boot_debugger_server.sh +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/scripts/boot_debugger_server.sh @@ -8,5 +8,5 @@ set -e docker run --rm -it --name=wasm-debug-server-ctr \ -v "$(pwd)":/mnt \ -p 1234:1234 \ - wasm-debug-server:1.0 \ + wasm-debug-server:$2 \ /bin/bash -c "./debug.sh $1" diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/scripts/build.bat b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/scripts/build.bat similarity index 90% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/scripts/build.bat rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/scripts/build.bat index 1fe6ca41cc7..de415107ab9 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/scripts/build.bat +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/scripts/build.bat @@ -7,5 +7,5 @@ docker run --rm --name=wasm-toolchain-ctr ^ -it -v "%cd%":/mnt ^ --env=PROJ_PATH="%cd%" ^ - wasm-toolchain:1.0 ^ + wasm-toolchain:%2 ^ /bin/bash -c "./build_wasm.sh %1" diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/scripts/build.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/scripts/build.sh similarity index 89% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/scripts/build.sh rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/scripts/build.sh index 04892b4eea5..a8a42cc899d 100755 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/scripts/build.sh +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/scripts/build.sh @@ -8,5 +8,5 @@ set -e docker run --rm --name=wasm-toolchain-ctr \ -it -v "$(pwd)":/mnt \ --env=PROJ_PATH="$(pwd)" \ - wasm-toolchain:1.0 \ + wasm-toolchain:$2 \ /bin/bash -c "./build_wasm.sh $1" diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/scripts/destroy.bat b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/scripts/destroy.bat similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/scripts/destroy.bat rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/scripts/destroy.bat diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/scripts/destroy.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/scripts/destroy.sh similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/scripts/destroy.sh rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/scripts/destroy.sh diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/scripts/project.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/scripts/project.cmake similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/scripts/project.cmake rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/scripts/project.cmake diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/scripts/run.bat b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/scripts/run.bat similarity index 87% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/scripts/run.bat rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/scripts/run.bat index 45d86bdaba6..af47f35baeb 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/scripts/run.bat +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/scripts/run.bat @@ -5,5 +5,5 @@ docker run --rm -it --name=wasm-debug-server-ctr ^ -v "%cd%":/mnt ^ - wasm-debug-server:1.0 ^ + wasm-debug-server:%2 ^ /bin/bash -c "./run.sh %1" diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/scripts/run.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/scripts/run.sh similarity index 88% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/scripts/run.sh rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/scripts/run.sh index 31961847f15..670e57c1e78 100755 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/scripts/run.sh +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/scripts/run.sh @@ -7,5 +7,5 @@ set -e docker run --rm -it --name=wasm-debug-server-ctr \ -v "$(pwd)":/mnt \ - wasm-debug-server:1.0 \ + wasm-debug-server:$2 \ /bin/bash -c "./run.sh $1" diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/assert.h b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/assert.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/assert.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/assert.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/ctype.h b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/ctype.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/ctype.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/ctype.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/errno.h b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/errno.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/errno.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/errno.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/fcntl.h b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/fcntl.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/fcntl.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/fcntl.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/inttypes.h b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/inttypes.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/inttypes.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/inttypes.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/limits.h b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/limits.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/limits.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/limits.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/pthread.h b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/pthread.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/pthread.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/pthread.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/stdarg.h b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/stdarg.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/stdarg.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/stdarg.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/stdbool.h b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/stdbool.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/stdbool.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/stdbool.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/stdint.h b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/stdint.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/stdint.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/stdint.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/stdio.h b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/stdio.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/stdio.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/stdio.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/stdlib.h b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/stdlib.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/stdlib.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/stdlib.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/string.h b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/string.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/string.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/string.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/strings.h b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/strings.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/strings.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/wamr-sdk/libc-builtin-sysroot/include/strings.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/webview/css/style.css b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/webview/css/style.css similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/webview/css/style.css rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/webview/css/style.css diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/webview/js/configbuildtarget.js b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/webview/js/configbuildtarget.js similarity index 77% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/webview/js/configbuildtarget.js rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/webview/js/configbuildtarget.js index 58b5afe23d6..837f384bcd5 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/webview/js/configbuildtarget.js +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/webview/js/configbuildtarget.js @@ -3,7 +3,6 @@ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception */ - const vscode = acquireVsCodeApi(); document.getElementById('btn_submit').onclick = () => { @@ -12,16 +11,16 @@ document.getElementById('btn_submit').onclick = () => { function submitFunc() { let outputFileName = document.getElementById('output_file_name').value; - let initmemSize = document.getElementById('initial_mem_size').value; - let maxmemSize = document.getElementById('max_mem_size').value; + let initMemSize = document.getElementById('initial_mem_size').value; + let maxMemSize = document.getElementById('max_mem_size').value; let stackSize = document.getElementById('stack_size').value; let exportedSymbols = document.getElementById('exported_symbols').value; vscode.postMessage({ command: 'config_build_target', outputFileName: outputFileName, - initmemSize: initmemSize, - maxmemSize: maxmemSize, + initMemSize: initMemSize, + maxMemSize: maxMemSize, stackSize: stackSize, exportedSymbols: exportedSymbols, }); diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/webview/js/newproj.js b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/webview/js/newproj.js similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/webview/js/newproj.js rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/webview/js/newproj.js diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/webview/page/configBuildTarget.html b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/webview/page/configBuildTarget.html similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/webview/page/configBuildTarget.html rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/webview/page/configBuildTarget.html diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/webview/page/newProject.html b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/webview/page/newProject.html similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/resource/webview/page/newProject.html rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/resource/webview/page/newProject.html diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/src/constants.ts b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/src/constants.ts new file mode 100644 index 00000000000..cf8bb710329 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/src/constants.ts @@ -0,0 +1,7 @@ +export const enum SelectionOfPrompt { + skip = 'skip', + setUp = 'setup', +} +export const enum Status { + done = 'done', +} diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/src/debugConfigurationProvider.ts b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/src/debugConfigurationProvider.ts new file mode 100644 index 00000000000..e7b42bf031a --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/src/debugConfigurationProvider.ts @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +import * as vscode from 'vscode'; +import * as os from 'os'; + +export class WasmDebugConfigurationProvider + implements vscode.DebugConfigurationProvider { + private wasmDebugConfig = { + type: 'wamr-debug', + name: 'Attach', + request: 'attach', + stopOnEntry: true, + initCommands: os.platform() === 'win32' || os.platform() === 'darwin' ? + /* linux and windows has different debug configuration */ + ['platform select remote-linux'] : + undefined, + attachCommands: [ + /* default port 1234 */ + 'process connect -p wasm connect://127.0.0.1:1234', + ] + }; + + public resolveDebugConfiguration( + _: vscode.WorkspaceFolder | undefined, + debugConfiguration: vscode.DebugConfiguration, + ): vscode.ProviderResult { + + this.wasmDebugConfig = { + ...this.wasmDebugConfig, + ...debugConfiguration + }; + + return this.wasmDebugConfig; + } + + public getDebugConfig(): vscode.DebugConfiguration { + return this.wasmDebugConfig; + } +} diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/src/decorationProvider.ts b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/src/decorationProvider.ts similarity index 62% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/src/decorationProvider.ts rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/src/decorationProvider.ts index db636913e08..46efcc90c5c 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/src/decorationProvider.ts +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/src/decorationProvider.ts @@ -4,7 +4,7 @@ */ import * as vscode from 'vscode'; -import { ReadFromFile } from './utilities/directoryUtilities'; +import { readFromFile } from './utilities/directoryUtilities'; import * as path from 'path'; import * as os from 'os'; @@ -26,11 +26,11 @@ export class DecorationProvider implements vscode.FileDecorationProvider { public onDidChangeFileDecorations: vscode.Event< vscode.Uri | vscode.Uri[] | undefined >; - private _eventEmiter: vscode.EventEmitter; + private eventEmitter: vscode.EventEmitter; constructor() { - this._eventEmiter = new vscode.EventEmitter(); - this.onDidChangeFileDecorations = this._eventEmiter.event; + this.eventEmitter = new vscode.EventEmitter(); + this.onDidChangeFileDecorations = this.eventEmitter.event; this.disposables.push( vscode.window.registerFileDecorationProvider(this) ); @@ -39,34 +39,27 @@ export class DecorationProvider implements vscode.FileDecorationProvider { public provideFileDecoration( uri: vscode.Uri ): vscode.ProviderResult { - let currentPrjDir, - prjConfigDir, - configFilePath, - configData, - includePathArr = new Array(), - excludeFileArr = new Array(), - pathRelative; - - /* Read include_paths and exclude_fils from the config file */ - currentPrjDir = + const currentPrjDir = os.platform() === 'win32' ? (vscode.workspace.workspaceFolders?.[0].uri.fsPath as string) : os.platform() === 'linux' || os.platform() === 'darwin' - ? (currentPrjDir = vscode.workspace.workspaceFolders?.[0].uri - .path as string) + ? (vscode.workspace.workspaceFolders?.[0].uri.path as string) : ''; - pathRelative = (uri.fsPath ? uri.fsPath : uri.toString()).replace( + const pathRelative = (uri.fsPath ? uri.fsPath : uri.toString()).replace( currentPrjDir, '..' ); - prjConfigDir = path.join(currentPrjDir, '.wamr'); - configFilePath = path.join(prjConfigDir, 'compilation_config.json'); - if (ReadFromFile(configFilePath) !== '') { - configData = JSON.parse(ReadFromFile(configFilePath)); - includePathArr = configData['include_paths']; - excludeFileArr = configData['exclude_files']; + const prjConfigDir = path.join(currentPrjDir, '.wamr'); + const configFilePath = path.join( + prjConfigDir, + 'compilation_config.json' + ); + if (readFromFile(configFilePath) !== '') { + const configData = JSON.parse(readFromFile(configFilePath)); + const includePathArr = configData['includePaths']; + const excludeFileArr = configData['excludeFiles']; if (includePathArr.indexOf(pathRelative) > -1) { return DECORATION_INCLUDE_PATHS; @@ -81,7 +74,7 @@ export class DecorationProvider implements vscode.FileDecorationProvider { } public updateDecorationsForSource(uri: vscode.Uri): void { - this._eventEmiter.fire(uri); + this.eventEmitter.fire(uri); } } diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/src/extension.ts b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/src/extension.ts similarity index 69% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/src/extension.ts rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/src/extension.ts index 57f2aa09bd2..523b26b831f 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/src/extension.ts +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/src/extension.ts @@ -12,22 +12,41 @@ import { WasmTaskProvider } from './taskProvider'; import { TargetConfigPanel } from './view/TargetConfigPanel'; import { NewProjectPanel } from './view/NewProjectPanel'; import { - CheckIfDirectoryExist, - WriteIntoFile, - ReadFromFile, + checkIfDirectoryExists, + writeIntoFile, + readFromFile, } from './utilities/directoryUtilities'; import { decorationProvider } from './decorationProvider'; import { WasmDebugConfigurationProvider } from './debugConfigurationProvider'; +import { + isLLDBInstalled, + promptInstallLLDB, + getWAMRExtensionVersion, +} from './utilities/lldbUtilities'; + +import { + checkIfDockerStarted, + checkIfDockerImagesExist, + promptSetupDockerImages, +} from './utilities/dockerUtilities'; +import { SelectionOfPrompt } from './constants'; let wasmTaskProvider: WasmTaskProvider; let wasmDebugConfigProvider: WasmDebugConfigurationProvider; -var currentPrjDir = ''; -var extensionPath = ''; -var isWasmProject = false; +let currentPrjDir = ''; +let isWasmProject = false; +// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types export async function activate(context: vscode.ExtensionContext) { - var OS_PLATFORM = '', - buildScript = '', + const extensionPath = context.extensionPath; + const osPlatform = os.platform(); + const wamrVersion = getWAMRExtensionVersion(context); + const typeMap = new Map(); + const scriptMap = new Map(); + /* set relative path of build.bat|sh script */ + const scriptPrefix = 'resource/scripts/'; + + let buildScript = '', runScript = '', debugScript = '', destroyScript = '', @@ -35,38 +54,27 @@ export async function activate(context: vscode.ExtensionContext) { runScriptFullPath = '', debugScriptFullPath = '', destroyScriptFullPath = '', - typeMap = new Map(), /* include paths array used for written into config file */ - includePathArr = new Array(), + includePathArr = new Array(), /* exclude files array used for written into config file */ - excludeFileArr = new Array(), - scriptMap = new Map(); - - /** - * Get OS platform information for differ windows and linux execution script - */ - OS_PLATFORM = os.platform(); + excludeFileArr = new Array(); /** * Provide Build & Run Task with Task Provider instead of "tasks.json" */ - /* set relative path of build.bat|sh script */ - let scriptPrefix = 'resource/scripts/'; - if (OS_PLATFORM === 'win32') { + if (osPlatform === 'win32') { buildScript = scriptPrefix.concat('build.bat'); runScript = scriptPrefix.concat('run.bat'); debugScript = scriptPrefix.concat('boot_debugger_server.bat'); destroyScript = scriptPrefix.concat('destroy.bat'); - } else if (OS_PLATFORM === 'linux' || OS_PLATFORM === 'darwin') { + } else if (osPlatform === 'linux' || osPlatform === 'darwin') { buildScript = scriptPrefix.concat('build.sh'); runScript = scriptPrefix.concat('run.sh'); debugScript = scriptPrefix.concat('boot_debugger_server.sh'); destroyScript = scriptPrefix.concat('destroy.sh'); } - extensionPath = context.extensionPath; - buildScriptFullPath = path.join(extensionPath, buildScript); runScriptFullPath = path.join(extensionPath, runScript); debugScriptFullPath = path.join(extensionPath, debugScript); @@ -82,15 +90,15 @@ export async function activate(context: vscode.ExtensionContext) { typeMap.set('Debug', 'Debug'); typeMap.set('Destroy', 'Destroy'); - wasmTaskProvider = new WasmTaskProvider(typeMap, scriptMap); + wasmTaskProvider = new WasmTaskProvider(typeMap, scriptMap, wamrVersion); vscode.tasks.registerTaskProvider('wasm', wasmTaskProvider); if (vscode.workspace.workspaceFolders?.[0]) { - if (OS_PLATFORM === 'win32') { + if (osPlatform === 'win32') { currentPrjDir = vscode.workspace.workspaceFolders?.[0].uri .fsPath as string; - } else if (OS_PLATFORM === 'linux' || OS_PLATFORM === 'darwin') { + } else if (osPlatform === 'linux' || osPlatform === 'darwin') { currentPrjDir = vscode.workspace.workspaceFolders?.[0].uri .path as string; } @@ -100,7 +108,7 @@ export async function activate(context: vscode.ExtensionContext) { * it not, `build`, `run` and `debug` will be disabled */ if (currentPrjDir !== '') { - let wamrFolder = fileSystem + const wamrFolder = fileSystem .readdirSync(currentPrjDir, { withFileTypes: true, }) @@ -126,7 +134,7 @@ export async function activate(context: vscode.ExtensionContext) { .getConfiguration() .get('C_Cpp.default.systemIncludePath'); - let LibcBuiltinHeaderPath = path.join( + const libcBuiltinHeaderPath = path.join( extensionPath, 'resource/wamr-sdk/libc-builtin-sysroot/include' ); @@ -134,17 +142,17 @@ export async function activate(context: vscode.ExtensionContext) { if (newIncludeInCppArr !== undefined) { /* in case the configuration has not been set up, push directly */ if (newIncludeInCppArr === null) { - newIncludeInCppArr = new Array(); - newIncludeInCppArr.push(LibcBuiltinHeaderPath); + newIncludeInCppArr = []; + newIncludeInCppArr.push(libcBuiltinHeaderPath); } else { /* if the configuration has been set up, check the condition */ if ( /* include libc-builtin-sysroot */ newIncludeInCppArr.indexOf( - LibcBuiltinHeaderPath + libcBuiltinHeaderPath ) < 0 ) { - newIncludeInCppArr.push(LibcBuiltinHeaderPath); + newIncludeInCppArr.push(libcBuiltinHeaderPath); } } @@ -163,7 +171,6 @@ export async function activate(context: vscode.ExtensionContext) { /* register debug configuration */ wasmDebugConfigProvider = new WasmDebugConfigurationProvider(); - wasmDebugConfigProvider.setDebugConfig(currentPrjDir, 1234); vscode.debug.registerDebugConfigurationProvider( 'wamr-debug', @@ -178,21 +185,21 @@ export async function activate(context: vscode.ExtensionContext) { ]); if (readFromConfigFile() !== '') { - let configData = JSON.parse(readFromConfigFile()); - includePathArr = configData['include_paths']; - excludeFileArr = configData['exclude_files']; + const configData = JSON.parse(readFromConfigFile()); + includePathArr = configData['includePaths']; + excludeFileArr = configData['excludeFiles']; - if (Object.keys(configData['build_args']).length !== 0) { - TargetConfigPanel.BUILD_ARGS = configData['build_args']; + if (Object.keys(configData['buildArgs']).length !== 0) { + TargetConfigPanel.buildArgs = configData['buildArgs']; } } - let disposableNewProj = vscode.commands.registerCommand( + const disposableNewProj = vscode.commands.registerCommand( 'wamride.newProject', () => { - let _ok = 'Set up now'; - let _cancle = 'Maybe later'; - let curWorkspace = vscode.workspace + const okStr = 'Set up now'; + const cancelStr = 'Maybe later'; + const curWorkspace = vscode.workspace .getConfiguration() .get('WAMR-IDE.configWorkspace'); @@ -201,11 +208,11 @@ export async function activate(context: vscode.ExtensionContext) { vscode.window .showWarningMessage( 'Please setup your workspace firstly.', - _ok, - _cancle + okStr, + cancelStr ) .then(item => { - if (item === _ok) { + if (item === okStr) { vscode.commands.executeCommand( 'wamride.changeWorkspace' ); @@ -213,7 +220,7 @@ export async function activate(context: vscode.ExtensionContext) { return; } }); - } else if (!CheckIfDirectoryExist(curWorkspace as string)) { + } else if (!checkIfDirectoryExists(curWorkspace as string)) { vscode.window .showWarningMessage( 'Invalid workspace:', @@ -226,10 +233,10 @@ export async function activate(context: vscode.ExtensionContext) { .get('WAMR-IDE.configWorkspace') + '', }, - _ok + okStr ) .then(item => { - if (item === _ok) { + if (item === okStr) { vscode.commands.executeCommand( 'wamride.changeWorkspace' ); @@ -243,7 +250,7 @@ export async function activate(context: vscode.ExtensionContext) { } ); - let disposableTargetConfig = vscode.commands.registerCommand( + const disposableTargetConfig = vscode.commands.registerCommand( 'wamride.targetConfig', () => { if (currentPrjDir !== '') { @@ -257,16 +264,16 @@ export async function activate(context: vscode.ExtensionContext) { } ); - let disposableChangeWorkspace = vscode.commands.registerCommand( + const disposableChangeWorkspace = vscode.commands.registerCommand( 'wamride.changeWorkspace', async () => { - let options: vscode.OpenDialogOptions = { + const options: vscode.OpenDialogOptions = { canSelectFiles: false, canSelectFolders: true, openLabel: 'Select Workspace', }; - let Workspace = await vscode.window + const workSpace = await vscode.window .showOpenDialog(options) .then(res => { if (res) { @@ -277,21 +284,21 @@ export async function activate(context: vscode.ExtensionContext) { }); /* update workspace value to vscode global settings */ - if (Workspace !== '' && Workspace !== undefined) { + if (workSpace !== '' && workSpace !== undefined) { await vscode.workspace .getConfiguration() .update( 'WAMR-IDE.configWorkspace', - Workspace.trim(), + workSpace.trim(), vscode.ConfigurationTarget.Global ) .then( - success => { + () => { vscode.window.showInformationMessage( 'Workspace has been set up successfully!' ); }, - error => { + () => { vscode.window.showErrorMessage( 'Set up Workspace failed!' ); @@ -301,9 +308,9 @@ export async function activate(context: vscode.ExtensionContext) { } ); - let disposableBuild = vscode.commands.registerCommand( + const disposableBuild = vscode.commands.registerCommand( 'wamride.build', - () => { + async () => { if (!isWasmProject) { vscode.window.showErrorMessage('Build failed', { modal: true, @@ -312,6 +319,28 @@ export async function activate(context: vscode.ExtensionContext) { return; } + try { + /* check if docker images are ready before building */ + if ( + (await checkIfDockerStarted()) && + !(await checkIfDockerImagesExist(context)) + ) { + /**NOTE - if users select to skip install, + * we should return rather than continue + * the execution + */ + if ( + (await promptSetupDockerImages(context)) === + SelectionOfPrompt.skip + ) { + return; + } + } + } catch (e) { + vscode.window.showWarningMessage((e as Error).message); + return; + } + generateCMakeFile(includePathArr, excludeFileArr); /* destroy the wasm-toolchain-ctr if it exists */ vscode.commands @@ -320,7 +349,7 @@ export async function activate(context: vscode.ExtensionContext) { 'Destroy: Wasm-Container-Before-Build' ) .then(() => { - let disposable = vscode.tasks.onDidEndTaskProcess(t => { + const disposable = vscode.tasks.onDidEndTaskProcess(t => { if ( t.execution.task.name === 'Wasm-Container-Before-Build' @@ -338,7 +367,7 @@ export async function activate(context: vscode.ExtensionContext) { ) .then(() => { /* destroy the wasm-toolchain-ctr after building */ - let disposable_aft = + const disposableAft = vscode.tasks.onDidEndTask(a => { if ( a.execution.task.name === @@ -354,7 +383,7 @@ export async function activate(context: vscode.ExtensionContext) { .then(() => { /* dispose the event after this building process */ - disposable_aft.dispose(); + disposableAft.dispose(); }); } }); @@ -367,9 +396,9 @@ export async function activate(context: vscode.ExtensionContext) { } ); - let disposableDebug = vscode.commands.registerCommand( + const disposableDebug = vscode.commands.registerCommand( 'wamride.debug', - () => { + async () => { if (!isWasmProject) { vscode.window.showErrorMessage('debug failed', { modal: true, @@ -378,6 +407,40 @@ export async function activate(context: vscode.ExtensionContext) { return; } + /* we should check again whether the user installed lldb, as this can be skipped during activation */ + try { + if (!isLLDBInstalled(context)) { + /**NOTE - if users select to skip install, + * we should return rather than continue + * the execution + */ + if ( + (await promptInstallLLDB(context)) === + SelectionOfPrompt.skip + ) { + return; + } + } + + if ( + (await checkIfDockerStarted()) && + !(await checkIfDockerImagesExist(context)) + ) { + /**NOTE - save as above lldb, should return if + * users select to skip set up + */ + if ( + (await promptSetupDockerImages(context)) === + SelectionOfPrompt.skip + ) { + return; + } + } + } catch (e) { + vscode.window.showWarningMessage((e as Error).message); + return; + } + /* refuse to debug if build process failed */ if (!checkIfBuildSuccess()) { vscode.window.showErrorMessage('Debug failed', { @@ -398,7 +461,7 @@ export async function activate(context: vscode.ExtensionContext) { ) .then(() => { /* execute the debug task when destroy task finish */ - let disposable_bfr = vscode.tasks.onDidEndTask(t => { + const disposableBfr = vscode.tasks.onDidEndTask(t => { if ( t.execution.task.name === 'Wasm-Container-Before-Debug' @@ -416,7 +479,7 @@ export async function activate(context: vscode.ExtensionContext) { ) .then(() => { /* register to listen debug session finish event */ - let dispose_aft = + const disposableAft = vscode.debug.onDidTerminateDebugSession( s => { if ( @@ -439,69 +502,91 @@ export async function activate(context: vscode.ExtensionContext) { 'Debug: Wasm' ); - dispose_aft.dispose(); + disposableAft.dispose(); } ); }); }); } - disposable_bfr.dispose(); + disposableBfr.dispose(); }); }); } ); - let disposableRun = vscode.commands.registerCommand('wamride.run', () => { - if (!isWasmProject) { - vscode.window.showErrorMessage('run failed', { - modal: true, - detail: 'Current project is not wasm project, please open wasm project and try again.', - }); - return; - } - /* refuse to debug if build process failed */ - if (!checkIfBuildSuccess()) { - vscode.window.showErrorMessage('Debug failed', { - modal: true, - detail: 'Can not find WASM binary, please build WASM firstly.', - }); - return; - } - vscode.commands - .executeCommand( - 'workbench.action.tasks.runTask', - 'Destroy: Wasm-Container-Before-Run' - ) - .then(() => { - let dispose_bfr = vscode.tasks.onDidEndTaskProcess(e => { - if (e.execution.task.name === 'Wasm-Container-Before-Run') { - /* make sure that run wasm task will be executed after destroy task finish */ - vscode.commands - .executeCommand( - 'workbench.action.tasks.runTask', - 'Run: Wasm' - ) - .then(() => { - if (e.exitCode !== 0) { - dispose_bfr.dispose(); - return; - } - }); - dispose_bfr.dispose(); - } + const disposableRun = vscode.commands.registerCommand( + 'wamride.run', + async () => { + if (!isWasmProject) { + vscode.window.showErrorMessage('run failed', { + modal: true, + detail: 'Current project is not wasm project, please open wasm project and try again.', }); - }); - }); + return; + } + + try { + /* check if docker images are set up before building */ + if ( + (await checkIfDockerStarted()) && + !(await checkIfDockerImagesExist(context)) + ) { + await promptSetupDockerImages(context); + } + } catch (e) { + vscode.window.showWarningMessage((e as Error).message); + return; + } + + /* refuse to debug if build process failed */ + if (!checkIfBuildSuccess()) { + vscode.window.showErrorMessage('Debug failed', { + modal: true, + detail: 'Can not find WASM binary, please build WASM firstly.', + }); + return; + } + + vscode.commands + .executeCommand( + 'workbench.action.tasks.runTask', + 'Destroy: Wasm-Container-Before-Run' + ) + .then(() => { + const disposableAft = vscode.tasks.onDidEndTaskProcess( + e => { + if ( + e.execution.task.name === + 'Wasm-Container-Before-Run' + ) { + /* make sure that run wasm task will be executed when destroy task finish */ + vscode.commands + .executeCommand( + 'workbench.action.tasks.runTask', + 'Run: Wasm' + ) + .then(() => { + if (e.exitCode !== 0) { + disposableAft.dispose(); + return; + } + }); + disposableAft.dispose(); + } + } + ); + }); + } + ); - let disposableToggleIncludePath = vscode.commands.registerCommand( + const disposableToggleIncludePath = vscode.commands.registerCommand( 'wamride.build.toggleStateIncludePath', fileUri => { - let pathRelative: string; - let path = + const path = fileUri._fsPath !== null && fileUri._fsPath !== undefined ? fileUri._fsPath : vscode.Uri.parse(fileUri.path as string).fsPath; - pathRelative = path.replace(currentPrjDir, '..'); + const pathRelative = path.replace(currentPrjDir, '..'); if (includePathArr.indexOf(pathRelative) > -1) { /* this folder has been added to include path, remove it */ @@ -515,25 +600,23 @@ export async function activate(context: vscode.ExtensionContext) { writeIntoConfigFile( includePathArr, excludeFileArr, - TargetConfigPanel.BUILD_ARGS + TargetConfigPanel.buildArgs ); decorationProvider.updateDecorationsForSource(fileUri); } ); - let disposableToggleExcludeFile = vscode.commands.registerCommand( + const disposableToggleExcludeFile = vscode.commands.registerCommand( 'wamride.build.toggleStateExclude', fileUri => { - let pathRelative: string; - - let path = + const path = fileUri._fsPath !== null && fileUri._fsPath !== undefined ? fileUri._fsPath : vscode.Uri.parse(fileUri.path as string).fsPath; /* replace the current project absolute path with .. to change to relative path */ - pathRelative = path.replace(currentPrjDir, '..'); + const pathRelative = path.replace(currentPrjDir, '..'); if (excludeFileArr.indexOf(pathRelative) > -1) { excludeFileArr = excludeFileArr.filter(val => { @@ -546,7 +629,7 @@ export async function activate(context: vscode.ExtensionContext) { writeIntoConfigFile( includePathArr, excludeFileArr, - TargetConfigPanel.BUILD_ARGS + TargetConfigPanel.buildArgs ); /* update decoration for this source file */ @@ -554,14 +637,14 @@ export async function activate(context: vscode.ExtensionContext) { } ); - let disposableOpenFolder = vscode.commands.registerCommand( + const disposableOpenFolder = vscode.commands.registerCommand( 'wamride.openFolder', () => { /* get projects list under current workspace */ - let _ok = 'Set up now'; - let _cancle = 'Maybe later'; - let _create = 'Create now'; - let curWorkspace = vscode.workspace + const okStr = 'Set up now'; + const cancelStr = 'Maybe later'; + const createStr = 'Create now'; + const curWorkspace = vscode.workspace .getConfiguration() .get('WAMR-IDE.configWorkspace') as string; @@ -570,11 +653,11 @@ export async function activate(context: vscode.ExtensionContext) { vscode.window .showWarningMessage( 'Please setup your workspace firstly.', - _ok, - _cancle + okStr, + cancelStr ) .then(item => { - if (item === _ok) { + if (item === okStr) { vscode.commands.executeCommand( 'wamride.changeWorkspace' ); @@ -582,7 +665,7 @@ export async function activate(context: vscode.ExtensionContext) { return; } }); - } else if (!CheckIfDirectoryExist(curWorkspace as string)) { + } else if (!checkIfDirectoryExists(curWorkspace as string)) { vscode.window .showWarningMessage( 'Invalid workspace:', @@ -595,10 +678,10 @@ export async function activate(context: vscode.ExtensionContext) { .get('WAMR-IDE.configWorkspace') + '', }, - _ok + okStr ) .then(item => { - if (item === _ok) { + if (item === okStr) { vscode.commands.executeCommand( 'wamride.changeWorkspace' ); @@ -624,7 +707,7 @@ export async function activate(context: vscode.ExtensionContext) { .filter(dirent => dirent.isDirectory()) .map(dirent => dirent.name); - let projFilesArr = directoryArr.filter(obj => { + const projFilesArr = directoryArr.filter(obj => { if (checkIfWasmProj(path.join(curWorkspace, obj))) { return true; } @@ -634,11 +717,11 @@ export async function activate(context: vscode.ExtensionContext) { vscode.window .showWarningMessage( 'Current workspace is empty, please create your project firstly.', - _create, - _cancle + createStr, + cancelStr ) .then(item => { - if (item === _create) { + if (item === createStr) { vscode.commands.executeCommand( 'wamride.newProject' ); @@ -657,17 +740,18 @@ export async function activate(context: vscode.ExtensionContext) { return; } - let _path = curWorkspace.concat( - OS_PLATFORM === 'win32' + const path = curWorkspace.concat( + osPlatform === 'win32' ? '\\' - : OS_PLATFORM === 'linux' || OS_PLATFORM === 'darwin' + : osPlatform === 'linux' || + osPlatform === 'darwin' ? '/' : '', option ); /* open the selected wasm project */ - openWindoWithSituation(vscode.Uri.file(_path)); + openWindowWithSituation(vscode.Uri.file(path)); }); } } @@ -686,15 +770,31 @@ export async function activate(context: vscode.ExtensionContext) { disposableToggleExcludeFile, disposableDebug ); + + try { + if (!isLLDBInstalled(context)) { + await promptInstallLLDB(context); + } + + if ( + (await checkIfDockerStarted()) && + !(await checkIfDockerImagesExist(context)) + ) { + await promptSetupDockerImages(context); + } + } catch (e) { + vscode.window.showWarningMessage((e as Error).message); + } } -function openWindoWithSituation(uri: vscode.Uri) { +function openWindowWithSituation(uri: vscode.Uri) { /** * check if the workspace folder is empty, * if yes, open new window, else open in current window */ - let isWorkspaceEmpty: boolean; - isWorkspaceEmpty = !vscode.workspace.workspaceFolders?.[0] ? true : false; + const isWorkspaceEmpty = !vscode.workspace.workspaceFolders?.[0] + ? true + : false; isWorkspaceEmpty === false ? vscode.commands.executeCommand('vscode.openFolder', uri, { @@ -706,11 +806,11 @@ function openWindoWithSituation(uri: vscode.Uri) { } interface BuildArgs { - output_file_name: string; - init_memory_size: string; - max_memory_size: string; - stack_size: string; - exported_symbols: string; + outputFileName: string; + initMemorySize: string; + maxMemorySize: string; + stackSize: string; + exportedSymbols: string; } /** @@ -723,26 +823,26 @@ export function writeIntoConfigFile( includePathArr: string[], excludeFileArr: string[], buildArgs?: BuildArgs -) { - let jsonStr = JSON.stringify( +): void { + const jsonStr = JSON.stringify( { - include_paths: includePathArr, - exclude_files: excludeFileArr, - build_args: buildArgs ? buildArgs : '{}', + includePaths: includePathArr, + excludeFiles: excludeFileArr, + buildArgs: buildArgs ? buildArgs : '{}', }, null, '\t' ); - let prjConfigDir = path.join(currentPrjDir, '.wamr'); - let configFilePath = path.join(prjConfigDir, 'compilation_config.json'); - WriteIntoFile(configFilePath, jsonStr); + const prjConfigDir = path.join(currentPrjDir, '.wamr'); + const configFilePath = path.join(prjConfigDir, 'compilation_config.json'); + writeIntoFile(configFilePath, jsonStr); } export function readFromConfigFile(): string { - let prjConfigDir = path.join(currentPrjDir, '.wamr'); - let configFilePath = path.join(prjConfigDir, 'compilation_config.json'); - return ReadFromFile(configFilePath); + const prjConfigDir = path.join(currentPrjDir, '.wamr'); + const configFilePath = path.join(prjConfigDir, 'compilation_config.json'); + return readFromFile(configFilePath); } /** @@ -753,9 +853,9 @@ function generateCMakeFile( excludeFileArr: string[] ): void { // -Wl,--export=${EXPORT_SYMBOLS} - let srcFilePath = path.join(currentPrjDir, 'src'); - let prjConfigDir = path.join(currentPrjDir, '.wamr'); - let cmakeFilePath = path.join(prjConfigDir, 'project.cmake'); + const srcFilePath = path.join(currentPrjDir, 'src'); + const prjConfigDir = path.join(currentPrjDir, '.wamr'); + const cmakeFilePath = path.join(prjConfigDir, 'project.cmake'); let strIncludeList = 'set (PROJECT_INCLUDES'; let strSrcList = 'set (PROJECT_SRC_LIST'; @@ -770,17 +870,16 @@ function generateCMakeFile( let i, s, e: number; /* change the absolute path into relative path */ - let _re = currentPrjDir; - let _substr = '${CMAKE_CURRENT_SOURCE_DIR}/..'; + const _re = currentPrjDir; + const _substr = '${CMAKE_CURRENT_SOURCE_DIR}/..'; - let srcPathArr: Array<{ path: string }> | undefined; /** * set PROJECT_SRC_LIST * default ADD every c OR c++ OR cpp under the src/ path - * except the files saved in the exclude_files array + * except the files saved in the excludeFiles array */ - srcPathArr = getAllSrcFiles(srcFilePath); + const srcPathArr = getAllSrcFiles(srcFilePath); if (srcPathArr === undefined) { return; @@ -793,46 +892,46 @@ function generateCMakeFile( ) === -1 ) { /* replace currentPrjDir with ${CMAKE_CURRENT_SOURCE_DIR} */ - let _newStr = srcPathArr[s].path + const newStr = srcPathArr[s].path .replace(_re, _substr) .replace(/\\/g, '/'); - strSrcList = strSrcList.concat(' ', _newStr); + strSrcList = strSrcList.concat(' ', newStr); } } strSrcList = strSrcList.concat(' )'); for (i = 0; i < includePathArr.length; i++) { - let _newStr = includePathArr[i] + const newStr = includePathArr[i] .replace(/../, _substr) .replace(/\\/g, '/'); - strIncludeList = strIncludeList.concat(' ', _newStr); + strIncludeList = strIncludeList.concat(' ', newStr); } strIncludeList = strIncludeList.concat(' )'); /* set up user customized input in configBuildArgs webview */ strOutputFileName = strOutputFileName.concat( ' ', - TargetConfigPanel.BUILD_ARGS.output_file_name + ')' + TargetConfigPanel.buildArgs.outputFileName + ')' ); strInitMemSize = strInitMemSize.concat( ' ', - TargetConfigPanel.BUILD_ARGS.init_memory_size + ')' + TargetConfigPanel.buildArgs.initMemorySize + ')' ); strMaxMemSize = strMaxMemSize.concat( ' ', - TargetConfigPanel.BUILD_ARGS.max_memory_size + ')' + TargetConfigPanel.buildArgs.maxMemorySize + ')' ); strStackSize = strStackSize.concat( ' ', - TargetConfigPanel.BUILD_ARGS.stack_size + ')' + TargetConfigPanel.buildArgs.stackSize + ')' ); - let exportedSymbolArr = - TargetConfigPanel.BUILD_ARGS.exported_symbols.split(','); + const exportedSymbolArr = + TargetConfigPanel.buildArgs.exportedSymbols.split(','); strExportedSymbols = strExportedSymbols.concat(' "'); @@ -854,7 +953,7 @@ function generateCMakeFile( .concat('\n', strSrcList) .concat('\n', strIncludeList); - WriteIntoFile(cmakeFilePath, fullStr); + writeIntoFile(cmakeFilePath, fullStr); } function getAllSrcFiles(_path: string) { @@ -876,7 +975,7 @@ function getAllSrcFiles(_path: string) { const folders = entries.filter(folder => folder.isDirectory()); for (const folder of folders) { - let fileArr = getAllSrcFiles(path.join(_path, folder.name)); + const fileArr = getAllSrcFiles(path.join(_path, folder.name)); fileArr ? files.push(...fileArr) : ''; } @@ -886,7 +985,7 @@ function getAllSrcFiles(_path: string) { } } -function checkIfBuildSuccess(): Boolean { +function checkIfBuildSuccess(): boolean { try { let wasmExist = false; const entries = fileSystem.readdirSync( @@ -908,10 +1007,10 @@ function checkIfBuildSuccess(): Boolean { } } -function checkIfWasmProj(_path: string): Boolean { +function checkIfWasmProj(path: string): boolean { try { let isWasmProj = false; - const entries = fileSystem.readdirSync(_path, { + const entries = fileSystem.readdirSync(path, { withFileTypes: true, }); diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/src/taskProvider.ts b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/src/taskProvider.ts similarity index 91% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/src/taskProvider.ts rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/src/taskProvider.ts index e5e1280eef4..9b9b75f9a02 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/src/taskProvider.ts +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/src/taskProvider.ts @@ -15,7 +15,8 @@ export interface OwnShellOption { export class WasmTaskProvider implements vscode.TaskProvider { constructor( public _type: Map, - public _script: Map + public _script: Map, + public _wamrVersion: string ) {} buildShellOption: OwnShellOption | undefined; @@ -28,10 +29,14 @@ export class WasmTaskProvider implements vscode.TaskProvider { public provideTasks(): Thenable | undefined { if (!this.wasmPromise) { /* target name is used for generated aot target */ - let targetName = - TargetConfigPanel.BUILD_ARGS.output_file_name.split('.')[0]; - - if (os.platform() === 'linux' || os.platform() === 'darwin' || os.platform() === 'win32') { + const targetName = + TargetConfigPanel.buildArgs.outputFileName.split('.')[0]; + + if ( + os.platform() === 'linux' || + os.platform() === 'darwin' || + os.platform() === 'win32' + ) { /* build */ this.buildShellOption = { cmd: @@ -40,7 +45,7 @@ export class WasmTaskProvider implements vscode.TaskProvider { : (this._script.get('buildScript') as string), options: { executable: this._script.get('buildScript'), - shellArgs: [targetName, os.platform()], + shellArgs: [targetName, this._wamrVersion], }, }; @@ -52,7 +57,7 @@ export class WasmTaskProvider implements vscode.TaskProvider { : (this._script.get('debugScript') as string), options: { executable: this._script.get('debugScript'), - shellArgs: [targetName], + shellArgs: [targetName, this._wamrVersion], }, }; @@ -64,7 +69,7 @@ export class WasmTaskProvider implements vscode.TaskProvider { : (this._script.get('runScript') as string), options: { executable: this._script.get('runScript'), - shellArgs: [targetName], + shellArgs: [targetName, this._wamrVersion], }, }; @@ -214,7 +219,10 @@ export class WasmTaskProvider implements vscode.TaskProvider { * @param _task * @returns */ - public resolveTask(_task: vscode.Task): vscode.Task | undefined { + public resolveTask(task: vscode.Task): vscode.Task | undefined { + if (task) { + return task; + } return undefined; } } diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/src/utilities/directoryUtilities.ts b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/src/utilities/directoryUtilities.ts new file mode 100644 index 00000000000..0efbea5d905 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/src/utilities/directoryUtilities.ts @@ -0,0 +1,211 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +import fileSystem = require('fs'); +import vscode = require('vscode'); +import path = require('path'); +import os = require('os'); +import request = require('request'); +import yauzl = require('yauzl'); + +/** + * + * @param path destination path + */ +export function createDirectory( + dest: string, + mode: string | number | null | undefined = undefined +): boolean { + try { + if (fileSystem.existsSync(dest)) { + if (fileSystem.lstatSync(dest).isDirectory()) { + return true; + } else { + return false; + } + } + + if (!path) { + return false; + } + + const parent = path.dirname(dest); + if (!createDirectory(parent, mode)) { + return false; + } + + fileSystem.mkdirSync(dest, mode); + return true; + } catch (error) { + vscode.window.showErrorMessage(error as string); + return false; + } +} + +// eslint-disable-next-line @typescript-eslint/no-unused-vars +export function copyFiles(src: string, dest: string, flags?: number): boolean { + try { + fileSystem.copyFileSync(src, dest); + return true; + } catch (error) { + vscode.window.showErrorMessage(error as string); + return false; + } +} + +export function writeIntoFile(path: string, data: string): void { + try { + fileSystem.writeFileSync(path, data, null); + } catch (err) { + vscode.window.showErrorMessage(err as string); + } +} + +export function readFromFile(path: string): string { + try { + const data = fileSystem.readFileSync(path, { encoding: 'utf-8' }); + return data as string; + } catch (err) { + vscode.window.showErrorMessage(err as string); + return ''; + } +} + +export function writeIntoFileAsync( + path: string, + data: string, + callback: fileSystem.NoParamCallback +): void { + try { + fileSystem.writeFile(path, data, callback); + } catch (err) { + vscode.window.showErrorMessage(err as string); + return; + } +} + +export function checkIfPathExists(path: string): boolean { + try { + if (fileSystem.existsSync(path)) { + return true; + } else { + return false; + } + } catch (err) { + vscode.window.showErrorMessage(err as string); + return false; + } +} + +export function checkIfDirectoryExists(path: string): boolean { + const doesPathExist = checkIfPathExists(path); + if (doesPathExist) { + return fileSystem.lstatSync(path).isDirectory(); + } + return false; +} + +export function checkIfFileExists(path: string): boolean { + const doesPathExist = checkIfPathExists(path); + if (doesPathExist) { + return fileSystem.lstatSync(path).isFile(); + } + return false; +} + +export function checkFolderName(folderName: string): boolean { + let invalidCharacterArr: string[] = []; + let valid = true; + + if (folderName.length > 255) { + valid = false; + } + + if (os.platform() === 'win32') { + invalidCharacterArr = ['\\', '/', ':', '?', '*', '"', '|', '<', '>']; + } else if (os.platform() === 'linux' || os.platform() === 'darwin') { + invalidCharacterArr = ['/']; + } + + invalidCharacterArr.forEach(function (c) { + if (folderName.indexOf(c) !== -1) { + valid = false; + } + }); + + return valid; +} + +export function downloadFile( + url: string, + destinationPath: string +): Promise { + return new Promise((resolve, reject) => { + const file = fileSystem.createWriteStream(destinationPath); + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const stream = request(url, undefined, (error, response, body) => { + if (response.statusCode !== 200) { + reject( + new Error( + `Download from ${url} failed with ${response.statusMessage}` + ) + ); + } + }).pipe(file); + stream.on('close', resolve); + stream.on('error', reject); + }); +} + +export function unzipFile( + sourcePath: string, + getDestinationFileName: (entryName: string) => string +): Promise { + return new Promise((resolve, reject) => { + const unzippedFilePaths: string[] = []; + yauzl.open( + sourcePath, + { lazyEntries: true }, + function (error, zipfile) { + if (error) { + reject(error); + return; + } + zipfile.readEntry(); + zipfile.on('entry', function (entry) { + // This entry is a directory so skip it + if (/\/$/.test(entry.fileName)) { + zipfile.readEntry(); + return; + } + + zipfile.openReadStream(entry, function (error, readStream) { + if (error) { + reject(error); + return; + } + readStream.on('end', () => zipfile.readEntry()); + const destinationFileName = getDestinationFileName( + entry.fileName + ); + fileSystem.mkdirSync( + path.dirname(destinationFileName), + { recursive: true } + ); + + const file = + fileSystem.createWriteStream(destinationFileName); + readStream.pipe(file).on('error', reject); + unzippedFilePaths.push(destinationFileName); + }); + }); + zipfile.on('end', function () { + zipfile.close(); + resolve(unzippedFilePaths); + }); + } + ); + }); +} diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/src/utilities/dockerUtilities.ts b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/src/utilities/dockerUtilities.ts new file mode 100644 index 00000000000..0a749ba19b0 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/src/utilities/dockerUtilities.ts @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +import * as vscode from 'vscode'; +import * as cp from 'child_process'; +import * as path from 'path'; +import * as fs from 'fs'; +import { getWAMRExtensionVersion } from './lldbUtilities'; +import { downloadFile, unzipFile } from './directoryUtilities'; +import { SelectionOfPrompt, Status } from '../constants'; + +const DOCKER_IMAGES_TEM_FOLDER_NAME = 'docker-resource'; + +type SelectionStatus = SelectionOfPrompt | Status; + +const execShell = (cmd: string) => + new Promise((resolve, reject) => { + cp.exec(cmd, (error, result) => { + if (error) { + return reject(error); + } + return resolve(result); + }); + }); + +export async function promptSetupDockerImages( + context: vscode.ExtensionContext +): Promise { + const extensionPath = context.extensionPath; + const response = await vscode.window.showWarningMessage( + 'Necessary docker images are not found. Setup now?', + SelectionOfPrompt.setUp, + SelectionOfPrompt.skip + ); + + if (response === SelectionOfPrompt.skip) { + return response; + } + + const downloadUrlArray = getDockerImagesDownloadUrl(context); + + const destinationFolder = path.resolve( + extensionPath, + 'resource', + DOCKER_IMAGES_TEM_FOLDER_NAME + ); + + if (!fs.existsSync(destinationFolder)) { + fs.mkdirSync(destinationFolder); + } + + vscode.window.showInformationMessage(`Downloading Docker Images...`); + + for (const url of downloadUrlArray) { + const imageZipName = path.basename(url); + const imageStorePath = path.join(destinationFolder, imageZipName); + await downloadFile(url, imageStorePath); + + /** + * extract docker image tar package to + * '${destinationFolder}' + */ + const dockerImageFile = await unzipFile(imageStorePath, filename => + path.join(destinationFolder, filename) + ); + /* give access before loading */ + dockerImageFile.forEach(file => fs.chmodSync(file, '0775')); + + /**NOTE - load docker image tar package to host + * right now there are just one file + * `docker-image-name.tar` inside so we can + * directly use files[0] here, should be modified + * if the package's files change + */ + await execShell(`docker load -i ${dockerImageFile[0]}`); + } + + /* remove the DOCKER_IMAGES_TEM_FOLDER */ + fs.rmSync(destinationFolder, { recursive: true, force: true }); + + vscode.window.showInformationMessage( + `Docker images are ready, please run '$docker images' to check.` + ); + + return Status.done; +} + +export async function checkIfDockerStarted(): Promise { + try { + await execShell('docker images'); + return true; + } catch (e) { + vscode.window.showWarningMessage((e as Error).message); + return false; + } +} + +export async function checkIfDockerImagesExist( + context: vscode.ExtensionContext +): Promise { + try { + /* the tag of images is equal to extension's version */ + const imageTag = getWAMRExtensionVersion(context); + await execShell( + `docker image inspect wasm-debug-server:${imageTag} wasm-toolchain:${imageTag}` + ); + return true; + } catch (e) { + return false; + } +} + +function getDockerImagesDownloadUrl( + context: vscode.ExtensionContext +): string[] { + const wamrVersion = getWAMRExtensionVersion(context); + const wamrReleaseUrl = `https://github.com/bytecodealliance/wasm-micro-runtime/releases/download/WAMR`; + + return [ + `${wamrReleaseUrl}-${wamrVersion}/wasm-debug-server-${wamrVersion}.zip`, + `${wamrReleaseUrl}-${wamrVersion}/wasm-toolchain-${wamrVersion}.zip`, + ]; +} diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/src/utilities/getUri.ts b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/src/utilities/getUri.ts similarity index 97% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/src/utilities/getUri.ts rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/src/utilities/getUri.ts index d897489d70a..93a7eef30e6 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/src/utilities/getUri.ts +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/src/utilities/getUri.ts @@ -9,6 +9,6 @@ export function getUri( webview: Webview, extensionUri: Uri, pathList: string[] -) { +): Uri { return webview.asWebviewUri(Uri.joinPath(extensionUri, ...pathList)); } diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/src/utilities/lldbUtilities.ts b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/src/utilities/lldbUtilities.ts new file mode 100644 index 00000000000..9170a75d380 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/src/utilities/lldbUtilities.ts @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2022 Amazon.com Inc. or its affiliates. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + */ + +import * as vscode from 'vscode'; +import * as os from 'os'; +import * as path from 'path'; +import * as fs from 'fs'; +import { + checkIfFileExists, + downloadFile, + unzipFile, +} from './directoryUtilities'; +import { SelectionOfPrompt } from '../constants'; + +const LLDB_RESOURCE_DIR = 'resource/debug'; +const LLDB_OS_DOWNLOAD_URL_SUFFIX_MAP: Partial< + Record +> = { + linux: 'x86_64-ubuntu-20.04', + darwin: 'universal-macos-latest', +}; + +const WAMR_LLDB_NOT_SUPPORTED_ERROR = new Error( + 'WAMR LLDB is not supported on this platform' +); + +function getLLDBUnzipFilePath(destinationFolder: string, filename: string) { + const dirs = filename.split('/'); + if (dirs[0] === 'wamr-lldb') { + dirs.shift(); + } + + return path.join(destinationFolder, ...dirs); +} + +export function getWAMRExtensionVersion( + context: vscode.ExtensionContext +): string { + // eslint-disable-next-line @typescript-eslint/no-var-requires + return require(path.join(context.extensionPath, 'package.json')).version; +} + +function getLLDBDownloadUrl(context: vscode.ExtensionContext): string { + const wamrVersion = getWAMRExtensionVersion(context); + const lldbOsUrlSuffix = LLDB_OS_DOWNLOAD_URL_SUFFIX_MAP[os.platform()]; + + if (!lldbOsUrlSuffix) { + throw WAMR_LLDB_NOT_SUPPORTED_ERROR; + } + + return `https://github.com/bytecodealliance/wasm-micro-runtime/releases/download/WAMR-${wamrVersion}/wamr-lldb-${wamrVersion}-${lldbOsUrlSuffix}.zip`; +} + +export function isLLDBInstalled(context: vscode.ExtensionContext): boolean { + const extensionPath = context.extensionPath; + const lldbOSDir = os.platform(); + const lldbBinaryPath = path.join( + extensionPath, + LLDB_RESOURCE_DIR, + lldbOSDir, + 'bin', + 'lldb' + ); + return checkIfFileExists(lldbBinaryPath); +} + +export async function promptInstallLLDB( + context: vscode.ExtensionContext +): Promise { + const extensionPath = context.extensionPath; + + const response = await vscode.window.showWarningMessage( + 'No LLDB instance found. Setup now?', + SelectionOfPrompt.setUp, + SelectionOfPrompt.skip + ); + + if (response === SelectionOfPrompt.skip) { + return response; + } + + const downloadUrl = getLLDBDownloadUrl(context); + const destinationDir = os.platform(); + + if (!downloadUrl) { + throw WAMR_LLDB_NOT_SUPPORTED_ERROR; + } + + const lldbDestinationFolder = path.join( + extensionPath, + LLDB_RESOURCE_DIR, + destinationDir + ); + const lldbZipPath = path.join(lldbDestinationFolder, 'bundle.zip'); + + vscode.window.showInformationMessage(`Downloading LLDB...`); + + await downloadFile(downloadUrl, lldbZipPath); + + vscode.window.showInformationMessage( + `LLDB downloaded to ${lldbZipPath}. Installing...` + ); + + const lldbFiles = await unzipFile(lldbZipPath, filename => + getLLDBUnzipFilePath(lldbDestinationFolder, filename) + ); + // Allow execution of lldb + lldbFiles.forEach(file => fs.chmodSync(file, '0775')); + + vscode.window.showInformationMessage( + `LLDB installed at ${lldbDestinationFolder}` + ); + + // Remove the bundle.zip + fs.unlinkSync(lldbZipPath); + return SelectionOfPrompt.setUp; +} diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/src/view/NewProjectPanel.ts b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/src/view/NewProjectPanel.ts similarity index 74% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/src/view/NewProjectPanel.ts rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/src/view/NewProjectPanel.ts index a7536564fc2..79671f68cdc 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/src/view/NewProjectPanel.ts +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/src/view/NewProjectPanel.ts @@ -8,42 +8,44 @@ import * as path from 'path'; import * as fs from 'fs'; import * as os from 'os'; import { - CreateDirectory, - CopyFiles, + createDirectory, + copyFiles, checkFolderName, } from '../utilities/directoryUtilities'; import { getUri } from '../utilities/getUri'; export class NewProjectPanel { - static USER_SET_WORKSPACE: string; + public static userSetWorkSpace: string; public static currentPanel: NewProjectPanel | undefined; - private readonly _panel: vscode.WebviewPanel; - private _disposables: vscode.Disposable[] = []; + private readonly viewPanel: vscode.WebviewPanel; + private disposableArr: vscode.Disposable[] = []; - static readonly EXCUTION_SUCCESS: number = 0; - static readonly DIR_EXSITED_ERR: number = -1; - static readonly USER_INTPUT_ERR: number = -2; - static readonly DIR_PATH_INVALID_ERR: number = -3; + private static readonly executionSuccess = 0; + private static readonly dirExistedError = -1; + private static readonly userInputError = -2; + private static readonly dirPathInvalidError = -3; constructor(extensionUri: vscode.Uri, panel: vscode.WebviewPanel) { - this._panel = panel; - this._panel.webview.html = this._getHtmlForWebview( - this._panel.webview, + this.viewPanel = panel; + this.viewPanel.webview.html = this.getHtmlForWebview( + this.viewPanel.webview, extensionUri, 'resource/webview/page/newProject.html' ); - this._setWebviewMessageListener(this._panel.webview, extensionUri); - this._panel.onDidDispose(this.dispose, null, this._disposables); + this._setWebviewMessageListener(this.viewPanel.webview, extensionUri); + this.viewPanel.onDidDispose(this.dispose, null, this.disposableArr); } - public static render(context: vscode.ExtensionContext) { - NewProjectPanel.USER_SET_WORKSPACE = vscode.workspace + public static render(context: vscode.ExtensionContext): void { + NewProjectPanel.userSetWorkSpace = vscode.workspace .getConfiguration() .get('WAMR-IDE.configWorkspace') as string; /* check if current panel is initialized */ if (NewProjectPanel.currentPanel) { - NewProjectPanel.currentPanel._panel.reveal(vscode.ViewColumn.One); + NewProjectPanel.currentPanel.viewPanel.reveal( + vscode.ViewColumn.One + ); } else { const panel = vscode.window.createWebviewPanel( 'newProject', @@ -62,50 +64,50 @@ export class NewProjectPanel { } } - private _creatNewProject( + private createNewProject( projName: string, template: string, extensionUri: vscode.Uri ): number { if (projName === '' || template === '') { - return NewProjectPanel.USER_INTPUT_ERR; + return NewProjectPanel.userInputError; } if (!checkFolderName(projName)) { - return NewProjectPanel.DIR_PATH_INVALID_ERR; + return NewProjectPanel.dirPathInvalidError; } - let ROOT_PATH = path.join(NewProjectPanel.USER_SET_WORKSPACE, projName); - let EXT_PATH = extensionUri.fsPath; + const ROOT_PATH = path.join(NewProjectPanel.userSetWorkSpace, projName); + const EXT_PATH = extensionUri.fsPath; if (fs.existsSync(ROOT_PATH)) { if (fs.lstatSync(ROOT_PATH).isDirectory()) { - return NewProjectPanel.DIR_EXSITED_ERR; + return NewProjectPanel.dirExistedError; } } - CreateDirectory(path.join(ROOT_PATH, '.wamr')); - CreateDirectory(path.join(ROOT_PATH, 'include')); - CreateDirectory(path.join(ROOT_PATH, 'src')); + createDirectory(path.join(ROOT_PATH, '.wamr')); + createDirectory(path.join(ROOT_PATH, 'include')); + createDirectory(path.join(ROOT_PATH, 'src')); - CopyFiles( + copyFiles( path.join(EXT_PATH, 'resource/scripts/CMakeLists.txt'), path.join(ROOT_PATH, '.wamr/CMakeLists.txt') ); - CopyFiles( + copyFiles( path.join(EXT_PATH, 'resource/scripts/project.cmake'), path.join(ROOT_PATH, '.wamr/project.cmake') ); - return NewProjectPanel.EXCUTION_SUCCESS; + return NewProjectPanel.executionSuccess; } - public _getHtmlForWebview( + public getHtmlForWebview( webview: vscode.Webview, extensionUri: vscode.Uri, templatePath: string - ) { + ): string { const toolkitUri = getUri(webview, extensionUri, [ 'node_modules', '@vscode', @@ -146,14 +148,14 @@ export class NewProjectPanel { message => { switch (message.command) { case 'create_new_project': - let createNewProjectStatus = this._creatNewProject( + const createNewProjectStatus = this.createNewProject( message.projectName, message.template, extensionUri ); if ( createNewProjectStatus === - NewProjectPanel.EXCUTION_SUCCESS + NewProjectPanel.executionSuccess ) { webview.postMessage({ command: 'proj_creation_finish', @@ -161,17 +163,17 @@ export class NewProjectPanel { }); } else if ( createNewProjectStatus === - NewProjectPanel.DIR_EXSITED_ERR + NewProjectPanel.dirExistedError ) { vscode.window.showErrorMessage( 'Project : ' + message.projectName + - ' exsits in your current root path, please change project name or root path!' + ' exists in your current root path, please change project name or root path!' ); return; } else if ( createNewProjectStatus === - NewProjectPanel.USER_INTPUT_ERR + NewProjectPanel.userInputError ) { vscode.window.showErrorMessage( 'Please fill chart before your submit!' @@ -179,7 +181,7 @@ export class NewProjectPanel { return; } else if ( createNewProjectStatus === - NewProjectPanel.DIR_PATH_INVALID_ERR + NewProjectPanel.dirPathInvalidError ) { if (os.platform() === 'win32') { vscode.window.showErrorMessage( @@ -203,19 +205,18 @@ export class NewProjectPanel { message.projectName + ' will be opened!' ); - let isWorkspaceEmpty: boolean; - let projPath = path.join( - NewProjectPanel.USER_SET_WORKSPACE, + const projPath = path.join( + NewProjectPanel.userSetWorkSpace, message.projectName ); - let uri = vscode.Uri.file(projPath); + const uri = vscode.Uri.file(projPath); /** * check if the vscode workspace folder is empty, * if yes, open new window, else open in current window */ - isWorkspaceEmpty = !vscode.workspace + const isWorkspaceEmpty = !vscode.workspace .workspaceFolders?.[0] ? true : false; @@ -233,7 +234,7 @@ export class NewProjectPanel { ); case 'close_webview': - this._panel.dispose(); + this.viewPanel.dispose(); return; default: @@ -241,16 +242,16 @@ export class NewProjectPanel { } }, undefined, - this._disposables + this.disposableArr ); } private dispose() { NewProjectPanel.currentPanel = undefined; - this._panel.dispose(); + this.viewPanel.dispose(); - while (this._disposables.length) { - const disposable = this._disposables.pop(); + while (this.disposableArr.length) { + const disposable = this.disposableArr.pop(); if (disposable) { disposable.dispose(); } diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/src/view/TargetConfigPanel.ts b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/src/view/TargetConfigPanel.ts similarity index 66% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/src/view/TargetConfigPanel.ts rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/src/view/TargetConfigPanel.ts index ccf0a0fe91b..f2e1343a590 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/VSCode-Extension/src/view/TargetConfigPanel.ts +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/src/view/TargetConfigPanel.ts @@ -11,19 +11,19 @@ import { getUri } from '../utilities/getUri'; export class TargetConfigPanel { public static currentPanel: TargetConfigPanel | undefined; - private readonly _panel: vscode.WebviewPanel; + private readonly viewPanel: vscode.WebviewPanel; private _disposables: vscode.Disposable[] = []; - public static BUILD_ARGS = { - output_file_name: 'main.wasm', - init_memory_size: '131072', - max_memory_size: '131072', - stack_size: '4096', - exported_symbols: 'main', + public static buildArgs = { + outputFileName: 'main.wasm', + initMemorySize: '131072', + maxMemorySize: '131072', + stackSize: '4096', + exportedSymbols: 'main', }; - static readonly USER_INTPUT_ERR: number = -2; - static readonly EXCUTION_SUCCESS: number = 0; + private static readonly userInputError: number = -2; + private static readonly executionSuccess: number = 0; /** * @@ -31,24 +31,26 @@ export class TargetConfigPanel { * @param panelName */ constructor(panel: vscode.WebviewPanel, extensionUri: vscode.Uri) { - this._panel = panel; - this._panel.webview.html = this._getHtmlForWebview( - this._panel.webview, + this.viewPanel = panel; + this.viewPanel.webview.html = this._getHtmlForWebview( + this.viewPanel.webview, extensionUri, 'resource/webview/page/configBuildTarget.html' ); - this._panel.onDidDispose(this.dispose, null, this._disposables); - this._setWebviewMessageListener(this._panel.webview); + this.viewPanel.onDidDispose(this.dispose, null, this._disposables); + this._setWebviewMessageListener(this.viewPanel.webview); } /** * * @param context */ - public static render(context: vscode.ExtensionContext) { + public static render(context: vscode.ExtensionContext): void { /* check if current panel is initialized */ if (TargetConfigPanel.currentPanel) { - TargetConfigPanel.currentPanel._panel.reveal(vscode.ViewColumn.One); + TargetConfigPanel.currentPanel.viewPanel.reveal( + vscode.ViewColumn.One + ); } else { const panel = vscode.window.createWebviewPanel( 'targetConfig', @@ -67,59 +69,56 @@ export class TargetConfigPanel { } } - private _configBuildArgs( + private configBuildArgs( outputFileName: string, - initmemSize: string, - maxmemSize: string, + initMemSize: string, + maxMemSize: string, stackSize: string, exportedSymbols: string ): number { if ( outputFileName === '' || - initmemSize === '' || - maxmemSize === '' || + initMemSize === '' || + maxMemSize === '' || stackSize === '' || exportedSymbols === '' ) { - return TargetConfigPanel.USER_INTPUT_ERR; + return TargetConfigPanel.userInputError; } - let _configStr: string; - let includePathArr = new Array(); - let excludeFileArr = new Array(); - let configJson: any; - - let _configObj = { - output_file_name: outputFileName, - init_memory_size: initmemSize, - max_memory_size: maxmemSize, - stack_size: stackSize, - exported_symbols: exportedSymbols, - }; + let includePathArr = []; + let excludeFileArr = []; - TargetConfigPanel.BUILD_ARGS = _configObj; + const configObj = { + outputFileName: outputFileName, + initMemorySize: initMemSize, + maxMemorySize: maxMemSize, + stackSize: stackSize, + exportedSymbols: exportedSymbols, + }; + const configStr = readFromConfigFile(); - _configStr = readFromConfigFile(); + TargetConfigPanel.buildArgs = configObj; - if (_configStr !== '' && _configStr !== undefined) { - configJson = JSON.parse(_configStr); + if (configStr !== '' && configStr !== undefined) { + const configJson = JSON.parse(configStr); includePathArr = - configJson['include_paths'] === undefined + configJson['includePaths'] === undefined ? [] - : configJson['include_paths']; + : configJson['includePaths']; excludeFileArr = - configJson['exclude_files'] === undefined + configJson['excludeFiles'] === undefined ? [] - : configJson['exclude_files']; + : configJson['excludeFiles']; } writeIntoConfigFile( includePathArr, excludeFileArr, - TargetConfigPanel.BUILD_ARGS + TargetConfigPanel.buildArgs ); - return TargetConfigPanel.EXCUTION_SUCCESS; + return TargetConfigPanel.executionSuccess; } private _getHtmlForWebview( @@ -158,23 +157,23 @@ export class TargetConfigPanel { .replace(/(\${styleUri})/, styleUri.toString()) .replace( /(\${output_file_val})/, - TargetConfigPanel.BUILD_ARGS.output_file_name + TargetConfigPanel.buildArgs.outputFileName ) .replace( /(\${initial_mem_size_val})/, - TargetConfigPanel.BUILD_ARGS.init_memory_size + TargetConfigPanel.buildArgs.initMemorySize ) .replace( /(\${max_mem_size_val})/, - TargetConfigPanel.BUILD_ARGS.max_memory_size + TargetConfigPanel.buildArgs.maxMemorySize ) .replace( /(\${stack_size_val})/, - TargetConfigPanel.BUILD_ARGS.stack_size + TargetConfigPanel.buildArgs.stackSize ) .replace( /(\${exported_symbols_val})/, - TargetConfigPanel.BUILD_ARGS.exported_symbols + TargetConfigPanel.buildArgs.exportedSymbols ); return html; @@ -187,8 +186,8 @@ export class TargetConfigPanel { case 'config_build_target': if ( message.outputFileName === '' || - message.initmemSize === '' || - message.maxmemSize === '' || + message.initMemSize === '' || + message.maxMemSize === '' || message.stackSize === '' || message.exportedSymbols === '' ) { @@ -197,13 +196,13 @@ export class TargetConfigPanel { ); return; } else if ( - this._configBuildArgs( + this.configBuildArgs( message.outputFileName, - message.initmemSize, - message.maxmemSize, + message.initMemSize, + message.maxMemSize, message.stackSize, message.exportedSymbols - ) === TargetConfigPanel.EXCUTION_SUCCESS + ) === TargetConfigPanel.executionSuccess ) { vscode.window .showInformationMessage( @@ -211,7 +210,7 @@ export class TargetConfigPanel { 'OK' ) .then(() => { - this._panel.dispose(); + this.viewPanel.dispose(); return; }); } @@ -227,7 +226,7 @@ export class TargetConfigPanel { private dispose() { TargetConfigPanel.currentPanel = undefined; - this._panel.dispose(); + this.viewPanel.dispose(); while (this._disposables.length) { const disposable = this._disposables.pop(); diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/tsconfig.json b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/tsconfig.json new file mode 100644 index 00000000000..c75039eee91 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/VSCode-Extension/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "es6", + "outDir": "out", + "lib": ["es6"], + "sourceMap": true, + "rootDir": "src", + "strict": true /* enable all strict type-checking options */ + /* Additional Checks */ + // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ + // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ + // "noUnusedParameters": true, /* Report errors on unused parameters. */ + }, + "exclude": ["node_modules", ".vscode-test"] +} diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/WASM-Debug-Server/Docker/Dockerfile b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/WASM-Debug-Server/Docker/Dockerfile new file mode 100644 index 00000000000..8165bd5f5f8 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/WASM-Debug-Server/Docker/Dockerfile @@ -0,0 +1,30 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +FROM gcc:12.2.0 AS BASE + +## set work directory +WORKDIR /root/ +COPY resource /root/ + +# hadolint ignore=DL3008 +RUN apt-get update \ + && apt-get -y install make cmake --no-install-recommends + +## -clone wamr-repo and build iwasm +RUN git clone -b main --depth=1 https://github.com/bytecodealliance/wasm-micro-runtime.git \ + && mkdir -p /root/wasm-micro-runtime/product-mini/platforms/linux/build + +WORKDIR /root/wasm-micro-runtime/product-mini/platforms/linux/build +RUN cmake .. -DWAMR_BUILD_DEBUG_INTERP=1 \ + && make \ + && cp /root/wasm-micro-runtime/product-mini/platforms/linux/build/iwasm /root/iwasm \ + && rm -fr /root/wasm-micro-runtime + +FROM ubuntu:22.04 +# COPY files from BASE image +COPY --from=BASE /root/iwasm /root +COPY --from=BASE /root/debug.sh /root +COPY --from=BASE /root/run.sh /root + +WORKDIR /root/ \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/WASM-Debug-Server/Docker/README.md b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/WASM-Debug-Server/Docker/README.md similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/WASM-Debug-Server/Docker/README.md rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/WASM-Debug-Server/Docker/README.md diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/WASM-Debug-Server/Docker/build_docker_image.bat b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/WASM-Debug-Server/Docker/build_docker_image.bat similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/WASM-Debug-Server/Docker/build_docker_image.bat rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/WASM-Debug-Server/Docker/build_docker_image.bat diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/WASM-Debug-Server/Docker/build_docker_image.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/WASM-Debug-Server/Docker/build_docker_image.sh similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/WASM-Debug-Server/Docker/build_docker_image.sh rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/WASM-Debug-Server/Docker/build_docker_image.sh diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/WASM-Debug-Server/Docker/resource/debug.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/WASM-Debug-Server/Docker/resource/debug.sh similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/WASM-Debug-Server/Docker/resource/debug.sh rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/WASM-Debug-Server/Docker/resource/debug.sh diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/WASM-Debug-Server/Docker/resource/run.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/WASM-Debug-Server/Docker/resource/run.sh similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/WASM-Debug-Server/Docker/resource/run.sh rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/WASM-Debug-Server/Docker/resource/run.sh diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/WASM-Toolchain/Docker/.dockerignore b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/WASM-Toolchain/Docker/.dockerignore similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/WASM-Toolchain/Docker/.dockerignore rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/WASM-Toolchain/Docker/.dockerignore diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/WASM-Toolchain/Docker/Dockerfile b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/WASM-Toolchain/Docker/Dockerfile new file mode 100644 index 00000000000..cd8da38d917 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/WASM-Toolchain/Docker/Dockerfile @@ -0,0 +1,71 @@ +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +## Build docker image that consists of gcc, cmake, wasi-sdk & zephyr sdk +FROM gcc:12.2.0 AS BASE + +## set work directory +WORKDIR /root/ + +COPY resource /root/ + +# - download cmake with wget and set up +# hadolint ignore=DL3008 +RUN apt-get update \ + && apt-get -y install ccache ninja-build make cmake python3-pip --no-install-recommends + +# set compilation environment for wamrc +# - wamr repo +# - cmake +# - wasi-sdk +# - wamr-sdk + +# - download wasi-sdk with wget and set up to /opt/wasi-sdk +RUN wget --progress=dot:giga https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-19/wasi-sdk-19.0-linux.tar.gz \ + && tar -zxf wasi-sdk-*-linux.tar.gz \ + && mv wasi-sdk-19.0 /opt/wasi-sdk/ \ + && rm -f wasi-sdk-*-linux.tar.gz + +## - clone wamr repo +RUN git clone -b main --depth=1 https://github.com/bytecodealliance/wasm-micro-runtime.git + +WORKDIR /root/wasm-micro-runtime/build-scripts +RUN pip3 install --no-cache-dir --user -r requirements.txt + +WORKDIR /root/wasm-micro-runtime/wamr-compiler +RUN ./build_llvm.sh \ + && mkdir build + +WORKDIR /root/wasm-micro-runtime/wamr-compiler/build +RUN cmake .. \ + && make \ + # - copy the wamrc to /root + && cp /root/wasm-micro-runtime/wamr-compiler/build/wamrc /root/wamrc \ + && mkdir -p /opt/wamr-sdk \ + && cp -r /root/wasm-micro-runtime/wamr-sdk/app /opt/wamr-sdk/ \ + && mv /root/wamr_toolchain.cmake /opt/wamr-sdk/app \ + # - remove the wamr repo to save the size + && rm -fr /root/wasm-micro-runtime + +# ## STAGE 2 +FROM ubuntu:22.04 +ENV HOME_DIR=/home/wasm-toolchain + +RUN mkdir -p /opt/wasi-sdk \ + && mkdir -p /opt/wamr-sdk/app \ + && mkdir -p /home/wasm-toolchain + +# COPY files from BASE image +COPY --from=BASE /opt/wamr-sdk/app/ /opt/wamr-sdk/app/ +COPY --from=BASE /opt/wasi-sdk /opt/wasi-sdk/ +COPY --from=BASE /root/wamrc ${HOME_DIR} +COPY --from=BASE /root/build_wasm.sh ${HOME_DIR} + +RUN ln -s ${HOME_DIR}/wamrc /usr/bin/wamrc + +# hadolint ignore=DL3008 +RUN apt-get update && apt-get install -y cmake make --no-install-recommends \ + && apt-get clean -y \ + && rm -rf /var/lib/apt/lists/* + +WORKDIR ${HOME_DIR} diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/WASM-Toolchain/Docker/README.md b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/WASM-Toolchain/Docker/README.md similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/WASM-Toolchain/Docker/README.md rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/WASM-Toolchain/Docker/README.md diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/WASM-Toolchain/Docker/build_docker_image.bat b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/WASM-Toolchain/Docker/build_docker_image.bat similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/WASM-Toolchain/Docker/build_docker_image.bat rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/WASM-Toolchain/Docker/build_docker_image.bat diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/WASM-Toolchain/Docker/build_docker_image.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/WASM-Toolchain/Docker/build_docker_image.sh similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/WASM-Toolchain/Docker/build_docker_image.sh rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/WASM-Toolchain/Docker/build_docker_image.sh diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/WASM-Toolchain/Docker/resource/build_wasm.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/WASM-Toolchain/Docker/resource/build_wasm.sh similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/WASM-Toolchain/Docker/resource/build_wasm.sh rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/WASM-Toolchain/Docker/resource/build_wasm.sh diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/WASM-Toolchain/Docker/resource/wamr_toolchain.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/WASM-Toolchain/Docker/resource/wamr_toolchain.cmake similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/test-tools/wamr-ide/WASM-Toolchain/Docker/resource/wamr_toolchain.cmake rename to lib/wasm-micro-runtime-WAMR-1.2.2/test-tools/wamr-ide/WASM-Toolchain/Docker/resource/wamr_toolchain.cmake diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/tests/benchmarks/coremark/README.md b/lib/wasm-micro-runtime-WAMR-1.2.2/tests/benchmarks/coremark/README.md similarity index 92% rename from lib/wasm-micro-runtime-WAMR-1.1.1/tests/benchmarks/coremark/README.md rename to lib/wasm-micro-runtime-WAMR-1.2.2/tests/benchmarks/coremark/README.md index 2a36e9de3dd..1631cc5c00c 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/tests/benchmarks/coremark/README.md +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/tests/benchmarks/coremark/README.md @@ -8,7 +8,7 @@ Please build iwasm and wamrc, refer to: - [Build iwasm on Linux](../../../doc/build_wamr.md#linux), or [Build iwasm on MacOS](../../../doc/build_wamr.md#macos) -- [build wamrc AOT compiler](../../../README.md#build-wamrc-aot-compiler) +- [Build wamrc AOT compiler](../../../README.md#build-wamrc-aot-compiler) And install WASI SDK, please download the [wasi-sdk release](https://github.com/CraneStation/wasi-sdk/releases) and extract the archive to default path `/opt/wasi-sdk`. diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/tests/benchmarks/coremark/build.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/tests/benchmarks/coremark/build.sh similarity index 85% rename from lib/wasm-micro-runtime-WAMR-1.1.1/tests/benchmarks/coremark/build.sh rename to lib/wasm-micro-runtime-WAMR-1.2.2/tests/benchmarks/coremark/build.sh index df6b9a30532..14c179ce576 100755 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/tests/benchmarks/coremark/build.sh +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/tests/benchmarks/coremark/build.sh @@ -13,7 +13,7 @@ cd coremark echo "Build coremark with gcc .." gcc -O3 -Iposix -I. -DFLAGS_STR=\""-O3 -DPERFORMANCE_RUN=1 -lrt"\" \ - -DITERATIONS=0 -DPERFORMANCE_RUN=1 \ + -DITERATIONS=400000 -DSEED_METHOD=SEED_VOLATILE -DPERFORMANCE_RUN=1 \ core_list_join.c core_main.c core_matrix.c core_state.c \ core_util.c posix/core_portme.c \ -o ../coremark.exe -lrt @@ -21,7 +21,7 @@ gcc -O3 -Iposix -I. -DFLAGS_STR=\""-O3 -DPERFORMANCE_RUN=1 -lrt"\" \ echo "Build coremark with wasi-sdk .." /opt/wasi-sdk/bin/clang -O3 -Iposix -I. -DFLAGS_STR=\""-O3 -DPERFORMANCE_RUN=1"\" \ -Wl,--export=main \ - -DITERATIONS=0 -DPERFORMANCE_RUN=1 \ + -DITERATIONS=400000 -DSEED_METHOD=SEED_VOLATILE -DPERFORMANCE_RUN=1 \ -Wl,--allow-undefined \ core_list_join.c core_main.c core_matrix.c core_state.c \ core_util.c posix/core_portme.c \ diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/tests/benchmarks/coremark/run.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/tests/benchmarks/coremark/run.sh similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/tests/benchmarks/coremark/run.sh rename to lib/wasm-micro-runtime-WAMR-1.2.2/tests/benchmarks/coremark/run.sh diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/tests/benchmarks/jetstream/README.md b/lib/wasm-micro-runtime-WAMR-1.2.2/tests/benchmarks/jetstream/README.md similarity index 95% rename from lib/wasm-micro-runtime-WAMR-1.1.1/tests/benchmarks/jetstream/README.md rename to lib/wasm-micro-runtime-WAMR-1.2.2/tests/benchmarks/jetstream/README.md index 9e9bcb021bd..f6c593d1168 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/tests/benchmarks/jetstream/README.md +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/tests/benchmarks/jetstream/README.md @@ -8,7 +8,7 @@ Please build iwasm and wamrc, refer to: - [Build iwasm on Linux](../../../doc/build_wamr.md#linux), or [Build iwasm on MacOS](../../../doc/build_wamr.md#macos) -- [build wamrc AOT compiler](../../../README.md#build-wamrc-aot-compiler) +- [Build wamrc AOT compiler](../../../README.md#build-wamrc-aot-compiler) And install emsdk, refer to [the guide](https://emscripten.org/docs/getting_started/downloads.html). Don't forget to activate emsdk and set up environment variables. For example, use instructions below to install it under /opt and activate it: diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/tests/benchmarks/jetstream/build.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/tests/benchmarks/jetstream/build.sh similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/tests/benchmarks/jetstream/build.sh rename to lib/wasm-micro-runtime-WAMR-1.2.2/tests/benchmarks/jetstream/build.sh diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/tests/benchmarks/jetstream/jetstream.patch b/lib/wasm-micro-runtime-WAMR-1.2.2/tests/benchmarks/jetstream/jetstream.patch similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/tests/benchmarks/jetstream/jetstream.patch rename to lib/wasm-micro-runtime-WAMR-1.2.2/tests/benchmarks/jetstream/jetstream.patch diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/tests/benchmarks/jetstream/run_aot.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/tests/benchmarks/jetstream/run_aot.sh similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/tests/benchmarks/jetstream/run_aot.sh rename to lib/wasm-micro-runtime-WAMR-1.2.2/tests/benchmarks/jetstream/run_aot.sh diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/tests/benchmarks/libsodium/README.md b/lib/wasm-micro-runtime-WAMR-1.2.2/tests/benchmarks/libsodium/README.md new file mode 100644 index 00000000000..19500afe615 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/tests/benchmarks/libsodium/README.md @@ -0,0 +1,23 @@ +# Introduction + +[libsodium](https://github.com/jedisct1/libsodium) is a new, easy-to-use software library for encryption, decryption, signatures, password hashing and more. + +**Source**: https://github.com/jedisct1/libsodium + +# Building + +Please build iwasm and wamrc, refer to: +- [Build iwasm on Linux](../../../doc/build_wamr.md#linux), or [Build iwasm on MacOS](../../../doc/build_wamr.md#macos) +- [Build wamrc AOT compiler](../../../README.md#build-wamrc-aot-compiler) + +And install [zig toolchain](https://ziglang.org/learn/getting-started), refer to [Install Zig from a Package Manager](https://github.com/ziglang/zig/wiki/Install-Zig-from-a-Package-Manager) for how to install it. + +And then run `./build.sh` to build the source code, the libsodium source code will be cloned, and test benchmarks of native version, wasm files and AOT files will be generated under `libsodium/zig-out/bin`. + +# Running + +Run `./run_aot.sh` to test the benchmark, the native mode and iwasm aot mode will be tested respectively. + +# Others + +Refer to [Performance of WebAssembly runtimes in 2023](https://00f.net/2023/01/04/webassembly-benchmark-2023) for more about the performance comparison of wasm runtimes on running the libsodium benchmarks. diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/tests/benchmarks/libsodium/build.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/tests/benchmarks/libsodium/build.sh new file mode 100755 index 00000000000..1e9cc21a702 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/tests/benchmarks/libsodium/build.sh @@ -0,0 +1,42 @@ +#!/bin/bash + +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +libsodium_CASES="aead_aes256gcm2 aead_aes256gcm aead_chacha20poly13052 aead_chacha20poly1305 \ + aead_xchacha20poly1305 auth2 auth3 auth5 auth6 auth7 auth box2 box7 box8 \ + box_easy2 box_easy box_seal box_seed box chacha20 codecs core1 core2 core3 \ + core4 core5 core6 core_ed25519 core_ristretto255 ed25519_convert generichash2 \ + generichash3 generichash hash3 hash kdf keygen kx metamorphic misuse \ + onetimeauth2 onetimeauth7 onetimeauth pwhash_argon2id pwhash_argon2i \ + pwhash_scrypt_ll pwhash_scrypt randombytes scalarmult2 scalarmult5 \ + scalarmult6 scalarmult7 scalarmult8 scalarmult_ed25519 scalarmult_ristretto255 \ + scalarmult secretbox2 secretbox7 secretbox8 secretbox_easy2 secretbox_easy \ + secretbox secretstream shorthash sign siphashx24 sodium_core sodium_utils2 \ + sodium_utils3 sodium_utils sodium_version stream2 stream3 stream4 stream verify1 \ + xchacha20" + +readonly WAMRC_CMD=$PWD/../../../wamr-compiler/build/wamrc +readonly OUT_DIR=$PWD/libsodium/zig-out/bin + +if [ ! -d libsodium ]; then + git clone -b stable https://github.com/jedisct1/libsodium.git +fi + +cd libsodium + +echo "Build libsodium native" +zig build -Drelease-fast -Denable_benchmarks=true + +echo "Build libsodium wasm32-wasi" +zig build -Drelease-fast -Denable_benchmarks=true -Dtarget=wasm32-wasi + +for case in ${libsodium_CASES} +do + ${WAMRC_CMD} -o ${OUT_DIR}/${case}.aot ${OUT_DIR}/${case}.wasm + + if [ "$?" != 0 ]; then + echo -e "Error while compiling ${case}.wasm to ${case}.aot" + exit + fi +done diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/tests/benchmarks/libsodium/test_aot.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/tests/benchmarks/libsodium/test_aot.sh new file mode 100755 index 00000000000..2e4e3e357c4 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/tests/benchmarks/libsodium/test_aot.sh @@ -0,0 +1,59 @@ +#!/bin/bash + +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +libsodium_CASES="aead_aes256gcm2 aead_aes256gcm aead_chacha20poly13052 aead_chacha20poly1305 \ + aead_xchacha20poly1305 auth2 auth3 auth5 auth6 auth7 auth box2 box7 box8 \ + box_easy2 box_easy box_seal box_seed box chacha20 codecs core1 core2 core3 \ + core4 core5 core6 core_ed25519 core_ristretto255 ed25519_convert generichash2 \ + generichash3 generichash hash3 hash kdf keygen kx metamorphic misuse \ + onetimeauth2 onetimeauth7 onetimeauth pwhash_argon2id pwhash_argon2i \ + pwhash_scrypt_ll pwhash_scrypt randombytes scalarmult2 scalarmult5 \ + scalarmult6 scalarmult7 scalarmult8 scalarmult_ed25519 scalarmult_ristretto255 \ + scalarmult secretbox2 secretbox7 secretbox8 secretbox_easy2 secretbox_easy \ + secretbox secretstream shorthash sign siphashx24 sodium_core sodium_utils2 \ + sodium_utils3 sodium_utils sodium_version stream2 stream3 stream4 stream verify1 \ + xchacha20" + +readonly OUT_DIR=$PWD/libsodium/zig-out/bin +readonly REPORT=$PWD/report.txt +readonly IWASM_CMD=$PWD/../../../product-mini/platforms/linux/build/iwasm + +BENCH_NAME_MAX_LEN=20 + +rm -f $REPORT +touch $REPORT + +function print_bench_name() +{ + name=$1 + echo -en "$name" >> $REPORT + name_len=${#name} + if [ $name_len -lt $BENCH_NAME_MAX_LEN ] + then + spaces=$(( $BENCH_NAME_MAX_LEN - $name_len )) + for i in $(eval echo "{1..$spaces}"); do echo -n " " >> $REPORT; done + fi +} + +# run benchmarks +cd $OUT_DIR + +echo -en "\t\t\t\t\t\tnative\tiwasm-aot\n" >> $REPORT + +for t in $libsodium_CASES +do + print_bench_name $t + + echo "run $t with native..." + echo -en "\t" >> $REPORT + ./${t} | awk -F '-' 'BEGIN{FIELDWIDTHS="10"}{ORS=""; print $1 / 1000000.0}' >> $REPORT + + echo "run $t with iwasm aot..." + echo -en "\t \t" >> $REPORT + $IWASM_CMD ${t}.aot | awk -F '-' 'BEGIN{FIELDWIDTHS="10"}{ORS=""; print $1 / 1000000.0}' >> $REPORT + + echo -en "\n" >> $REPORT +done + diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/tests/benchmarks/polybench/README.md b/lib/wasm-micro-runtime-WAMR-1.2.2/tests/benchmarks/polybench/README.md similarity index 94% rename from lib/wasm-micro-runtime-WAMR-1.1.1/tests/benchmarks/polybench/README.md rename to lib/wasm-micro-runtime-WAMR-1.2.2/tests/benchmarks/polybench/README.md index 191c6f9dcd6..7808e17d912 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/tests/benchmarks/polybench/README.md +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/tests/benchmarks/polybench/README.md @@ -8,7 +8,7 @@ Please build iwasm and wamrc, refer to: - [Build iwasm on Linux](../../../doc/build_wamr.md#linux), or [Build iwasm on MacOS](../../../doc/build_wamr.md#macos) -- [build wamrc AOT compiler](../../../README.md#build-wamrc-aot-compiler) +- [Build wamrc AOT compiler](../../../README.md#build-wamrc-aot-compiler) And install WASI SDK, please download the [wasi-sdk release](https://github.com/CraneStation/wasi-sdk/releases) and extract the archive to default path `/opt/wasi-sdk`. diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/tests/benchmarks/polybench/build.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/tests/benchmarks/polybench/build.sh similarity index 96% rename from lib/wasm-micro-runtime-WAMR-1.1.1/tests/benchmarks/polybench/build.sh rename to lib/wasm-micro-runtime-WAMR-1.2.2/tests/benchmarks/polybench/build.sh index 43cd3321a17..bc7bf4c10e5 100755 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/tests/benchmarks/polybench/build.sh +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/tests/benchmarks/polybench/build.sh @@ -34,7 +34,8 @@ do utilities/polybench.c ${file} \ -Wl,--export=__heap_base -Wl,--export=__data_end \ -Wl,--export=malloc -Wl,--export=free \ - -DPOLYBENCH_TIME -o ${OUT_DIR}/${file_name%.*}.wasm + -DPOLYBENCH_TIME -o ${OUT_DIR}/${file_name%.*}.wasm \ + -D_WASI_EMULATED_PROCESS_CLOCKS echo "Compile ${file_name%.*}.wasm into ${file_name%.*}.aot" ${WAMRC_CMD} -o ${OUT_DIR}/${file_name%.*}.aot \ diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/tests/benchmarks/polybench/run_aot.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/tests/benchmarks/polybench/run_aot.sh similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/tests/benchmarks/polybench/run_aot.sh rename to lib/wasm-micro-runtime-WAMR-1.2.2/tests/benchmarks/polybench/run_aot.sh diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/tests/benchmarks/polybench/run_interp.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/tests/benchmarks/polybench/run_interp.sh similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/tests/benchmarks/polybench/run_interp.sh rename to lib/wasm-micro-runtime-WAMR-1.2.2/tests/benchmarks/polybench/run_interp.sh diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/tests/benchmarks/sightglass/README.md b/lib/wasm-micro-runtime-WAMR-1.2.2/tests/benchmarks/sightglass/README.md similarity index 94% rename from lib/wasm-micro-runtime-WAMR-1.1.1/tests/benchmarks/sightglass/README.md rename to lib/wasm-micro-runtime-WAMR-1.2.2/tests/benchmarks/sightglass/README.md index 8ffef0994d7..a446d80ea8f 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/tests/benchmarks/sightglass/README.md +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/tests/benchmarks/sightglass/README.md @@ -8,7 +8,7 @@ Please build iwasm and wamrc, refer to: - [Build iwasm on Linux](../../../doc/build_wamr.md#linux), or [Build iwasm on MacOS](../../../doc/build_wamr.md#macos) -- [build wamrc AOT compiler](../../../README.md#build-wamrc-aot-compiler) +- [Build wamrc AOT compiler](../../../README.md#build-wamrc-aot-compiler) And install WASI SDK, please download the [wasi-sdk release](https://github.com/CraneStation/wasi-sdk/releases) and extract the archive to default path `/opt/wasi-sdk`. diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/tests/benchmarks/sightglass/build.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/tests/benchmarks/sightglass/build.sh similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/tests/benchmarks/sightglass/build.sh rename to lib/wasm-micro-runtime-WAMR-1.2.2/tests/benchmarks/sightglass/build.sh diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/tests/benchmarks/sightglass/run_aot.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/tests/benchmarks/sightglass/run_aot.sh similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/tests/benchmarks/sightglass/run_aot.sh rename to lib/wasm-micro-runtime-WAMR-1.2.2/tests/benchmarks/sightglass/run_aot.sh diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/tests/benchmarks/sightglass/run_interp.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/tests/benchmarks/sightglass/run_interp.sh similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/tests/benchmarks/sightglass/run_interp.sh rename to lib/wasm-micro-runtime-WAMR-1.2.2/tests/benchmarks/sightglass/run_interp.sh diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/tests/wamr-test-suites/README.md b/lib/wasm-micro-runtime-WAMR-1.2.2/tests/wamr-test-suites/README.md similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/tests/wamr-test-suites/README.md rename to lib/wasm-micro-runtime-WAMR-1.2.2/tests/wamr-test-suites/README.md diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/tests/wamr-test-suites/spec-test-script/CHANGES b/lib/wasm-micro-runtime-WAMR-1.2.2/tests/wamr-test-suites/spec-test-script/CHANGES similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/tests/wamr-test-suites/spec-test-script/CHANGES rename to lib/wasm-micro-runtime-WAMR-1.2.2/tests/wamr-test-suites/spec-test-script/CHANGES diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/tests/wamr-test-suites/spec-test-script/all.py b/lib/wasm-micro-runtime-WAMR-1.2.2/tests/wamr-test-suites/spec-test-script/all.py similarity index 75% rename from lib/wasm-micro-runtime-WAMR-1.1.1/tests/wamr-test-suites/spec-test-script/all.py rename to lib/wasm-micro-runtime-WAMR-1.2.2/tests/wamr-test-suites/spec-test-script/all.py index e19ad6fde91..8b26d689225 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/tests/wamr-test-suites/spec-test-script/all.py +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/tests/wamr-test-suites/spec-test-script/all.py @@ -5,35 +5,46 @@ # import argparse -import hashlib import multiprocessing as mp import os import pathlib -import random -import shlex -import shutil -import string import subprocess import sys import time """ The script itself has to be put under the same directory with the "spec". +To run a single non-GC case with interpreter mode: + cd workspace + python3 runtest.py --wast2wasm wabt/bin/wat2wasm --interpreter iwasm \ + spec/test/core/xxx.wast +To run a single non-GC case with aot mode: + cd workspace + python3 runtest.py --aot --wast2wasm wabt/bin/wat2wasm --interpreter iwasm \ + --aot-compiler wamrc spec/test/core/xxx.wast +To run a single GC case: + cd workspace + python3 runtest.py --wast2wasm spec/interpreter/wasm --interpreter iwasm \ + --aot-compiler wamrc --gc spec/test/core/xxx.wast """ PLATFORM_NAME = os.uname().sysname.lower() IWASM_CMD = "../../../product-mini/platforms/" + PLATFORM_NAME + "/build/iwasm" IWASM_SGX_CMD = "../../../product-mini/platforms/linux-sgx/enclave-sample/iwasm" +IWASM_QEMU_CMD = "iwasm" SPEC_TEST_DIR = "spec/test/core" WAST2WASM_CMD = "./wabt/out/gcc/Release/wat2wasm" +SPEC_INTERPRETER_CMD = "spec/interpreter/wasm" WAMRC_CMD = "../../../wamr-compiler/build/wamrc" - class TargetAction(argparse.Action): TARGET_MAP = { "ARMV7_VFP": "armv7", - "RISCV64": "riscv64_lp64d", - "RISCV64_LP64": "riscv64_lp64d", + "RISCV32": "riscv32_ilp32", + "RISCV32_ILP32": "riscv32_ilp32", + "RISCV32_ILP32D": "riscv32_ilp32d", + "RISCV64": "riscv64_lp64", + "RISCV64_LP64": "riscv64_lp64", "RISCV64_LP64D": "riscv64_lp64", "THUMBV7_VFP": "thumbv7", "X86_32": "i386", @@ -52,7 +63,9 @@ def ignore_the_case( multi_module_flag=False, multi_thread_flag=False, simd_flag=False, + gc_flag=False, xip_flag=False, + qemu_flag=False ): if case_name in ["comments", "inline-module", "names"]: return True @@ -63,6 +76,10 @@ def ignore_the_case( if "i386" == target and case_name in ["float_exprs"]: return True + if gc_flag: + if case_name in ["type-canon", "type-equivalence", "type-rec"]: + return True; + if sgx_flag: if case_name in ["conversions", "f32_bitwise", "f64_bitwise"]: return True @@ -75,6 +92,12 @@ def ignore_the_case( ]: return True + if qemu_flag: + if case_name in ["f32_bitwise", "f64_bitwise", "loop", "f64", "f64_cmp", + "conversions", "f32", "f32_cmp", "float_exprs", + "float_misc", "select", "memory_grow"]: + return True + return False @@ -105,6 +128,10 @@ def test_case( xip_flag=False, clean_up_flag=True, verbose_flag=True, + gc_flag=False, + qemu_flag=False, + qemu_firmware='', + log='', ): case_path = pathlib.Path(case_path).resolve() case_name = case_path.stem @@ -117,22 +144,33 @@ def test_case( multi_module_flag, multi_thread_flag, simd_flag, + gc_flag, xip_flag, + qemu_flag ): return True - CMD = ["python2.7", "runtest.py"] + CMD = ["python3", "runtest.py"] CMD.append("--wast2wasm") - CMD.append(WAST2WASM_CMD) + CMD.append(WAST2WASM_CMD if not gc_flag else SPEC_INTERPRETER_CMD) CMD.append("--interpreter") - CMD.append(IWASM_CMD if not sgx_flag else IWASM_SGX_CMD) + if sgx_flag: + CMD.append(IWASM_SGX_CMD) + elif qemu_flag: + CMD.append(IWASM_QEMU_CMD) + else: + CMD.append(IWASM_CMD) CMD.append("--aot-compiler") CMD.append(WAMRC_CMD) if aot_flag: CMD.append("--aot") - CMD.append("--aot-target") - CMD.append(target) + + CMD.append("--target") + CMD.append(target) + + if multi_module_flag: + CMD.append("--multi-module") if multi_thread_flag: CMD.append("--multi-thread") @@ -146,9 +184,21 @@ def test_case( if xip_flag: CMD.append("--xip") + if qemu_flag: + CMD.append("--qemu") + CMD.append("--qemu-firmware") + CMD.append(qemu_firmware) + if not clean_up_flag: CMD.append("--no_cleanup") + if gc_flag: + CMD.append("--gc") + + if log != '': + CMD.append("--log-dir") + CMD.append(log) + CMD.append(case_path) print(f"============> run {case_name} ", end="") with subprocess.Popen( @@ -205,7 +255,11 @@ def test_suite( xip_flag=False, clean_up_flag=True, verbose_flag=True, + gc_flag=False, parl_flag=False, + qemu_flag=False, + qemu_firmware='', + log='', ): suite_path = pathlib.Path(SPEC_TEST_DIR).resolve() if not suite_path.exists(): @@ -217,6 +271,10 @@ def test_suite( simd_case_list = sorted(suite_path.glob("simd/*.wast")) case_list.extend(simd_case_list) + if gc_flag: + gc_case_list = sorted(suite_path.glob("gc/*.wast")) + case_list.extend(gc_case_list) + case_count = len(case_list) failed_case = 0 successful_case = 0 @@ -239,13 +297,21 @@ def test_suite( xip_flag, clean_up_flag, verbose_flag, + gc_flag, + qemu_flag, + qemu_firmware, + log, ], ) for case_name, result in results.items(): try: - # 5 min / case - result.wait(300) + if qemu_flag: + # 60 min / case, testing on QEMU may be very slow + result.wait(7200) + else: + # 5 min / case + result.wait(300) if not result.successful(): failed_case += 1 else: @@ -268,11 +334,15 @@ def test_suite( xip_flag, clean_up_flag, verbose_flag, + gc_flag, + qemu_flag, + qemu_firmware, + log, ) successful_case += 1 - except Exception: + except Exception as e: failed_case += 1 - break + raise e print( f"IN ALL {case_count} cases: {successful_case} PASS, {failed_case} FAIL, {case_count - successful_case - failed_case} SKIP" @@ -349,6 +419,25 @@ def main(): dest="parl_flag", help="To run whole test suite parallelly", ) + parser.add_argument( + "--qemu", + action="store_true", + default=False, + dest="qemu_flag", + help="To run whole test suite in qemu", + ) + parser.add_argument( + "--qemu-firmware", + default="", + dest="qemu_firmware", + help="Firmware required by qemu", + ) + parser.add_argument( + "--log", + default='', + dest="log", + help="Log directory", + ) parser.add_argument( "--quiet", action="store_false", @@ -356,6 +445,13 @@ def main(): dest="verbose_flag", help="Close real time output while running cases, only show last words of failed ones", ) + parser.add_argument( + "--gc", + action="store_true", + default=False, + dest="gc_flag", + help="Running with GC feature", + ) parser.add_argument( "cases", metavar="path_to__case", @@ -388,7 +484,11 @@ def main(): options.xip_flag, options.clean_up_flag, options.verbose_flag, + options.gc_flag, options.parl_flag, + options.qemu_flag, + options.qemu_firmware, + options.log, ) end = time.time_ns() print( @@ -408,6 +508,10 @@ def main(): options.xip_flag, options.clean_up_flag, options.verbose_flag, + options.gc_flag, + options.qemu_flag, + options.qemu_firmware, + options.log ) else: ret = True diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/tests/wamr-test-suites/spec-test-script/all.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/tests/wamr-test-suites/spec-test-script/all.sh similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/tests/wamr-test-suites/spec-test-script/all.sh rename to lib/wasm-micro-runtime-WAMR-1.2.2/tests/wamr-test-suites/spec-test-script/all.sh diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/tests/wamr-test-suites/spec-test-script/collect_coverage.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/tests/wamr-test-suites/spec-test-script/collect_coverage.sh new file mode 100755 index 00000000000..09b1f465ee3 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/tests/wamr-test-suites/spec-test-script/collect_coverage.sh @@ -0,0 +1,82 @@ +#!/usr/bin/env bash + +# +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# + +readonly WORK_DIR=$PWD +readonly WAMR_DIR=${WORK_DIR}/../../.. +readonly DST_COV_FILE=$1 +readonly SRC_COV_DIR=$2 +readonly SRC_TEMP_COV_FILE=wamr_temp.lcov +readonly SRC_COV_FILE=wamr.lcov + +# get dest folder +dir=$(dirname ${DST_COV_FILE}) +pushd ${dir} > /dev/null 2>&1 +readonly DST_COV_DIR=${PWD} +popd > /dev/null 2>&1 + +if [[ ! -d ${SRC_COV_DIR} ]]; then + echo "${SRC_COV_DIR} doesn't exist, ignore code coverage collection" + exit +fi + +echo "Start to collect code coverage of ${SRC_COV_DIR} .." + +pushd ${SRC_COV_DIR} > /dev/null 2>&1 + +# collect all code coverage data +lcov -q -o ${SRC_TEMP_COV_FILE} -c -d . --rc lcov_branch_coverage=1 +# extract code coverage data of WAMR source files +lcov -q -r ${SRC_TEMP_COV_FILE} -o ${SRC_TEMP_COV_FILE} \ + -rc lcov_branch_coverage=1 \ + "*/usr/*" "*/_deps/*" "*/deps/*" "*/tests/unit/*" \ + "*/llvm/include/*" "*/include/llvm/*" "*/samples/*" \ + "*/app-framework/*" "*/app-mgr/*" "*/test-tools/*" \ + "*/tests/standalone/*" "*/tests/*" + +if [[ -s ${SRC_TEMP_COV_FILE} ]]; then + if [[ -s ${DST_COV_FILE} ]]; then + # merge code coverage data + lcov --rc lcov_branch_coverage=1 \ + --add-tracefile ${SRC_TEMP_COV_FILE} \ + -a ${DST_COV_FILE} -o ${SRC_COV_FILE} + # backup the original lcov file + cp -a ${DST_COV_FILE} "${DST_COV_FILE}.orig" + # replace the lcov file + cp -a ${SRC_COV_FILE} ${DST_COV_FILE} + echo "Code coverage file ${DST_COV_FILE} was appended" + else + cp -a ${SRC_TEMP_COV_FILE} ${SRC_COV_FILE} + cp -a ${SRC_COV_FILE} ${DST_COV_FILE} + echo "Code coverage file ${DST_COV_FILE} was generated" + fi + + # get ignored prefix path + dir=$(dirname ${WAMR_DIR}/../..) + pushd ${dir} > /dev/null 2>&1 + prefix_full_path=${PWD} + popd > /dev/null 2>&1 + + # generate html output for merged code coverage data + rm -fr ${DST_COV_DIR}/wamr-lcov + genhtml -q -t "WAMR Code Coverage" \ + --rc lcov_branch_coverage=1 --prefix=${prefix_full_path} \ + -o ${DST_COV_DIR}/wamr-lcov \ + ${DST_COV_FILE} + + cd ${DST_COV_DIR} + rm -f wamr-lcov.zip + zip -r -q -o wamr-lcov.zip wamr-lcov + rm -fr wamr-lcov + + echo "Code coverage html ${DST_COV_DIR}/wamr-lcov.zip was generated" +else + echo "generate code coverage html failed" +fi + +echo "" + +popd > /dev/null 2>&1 diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/tests/wamr-test-suites/spec-test-script/ignore_cases.patch b/lib/wasm-micro-runtime-WAMR-1.2.2/tests/wamr-test-suites/spec-test-script/ignore_cases.patch similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/tests/wamr-test-suites/spec-test-script/ignore_cases.patch rename to lib/wasm-micro-runtime-WAMR-1.2.2/tests/wamr-test-suites/spec-test-script/ignore_cases.patch diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/tests/wamr-test-suites/spec-test-script/runtest.py b/lib/wasm-micro-runtime-WAMR-1.2.2/tests/wamr-test-suites/spec-test-script/runtest.py similarity index 81% rename from lib/wasm-micro-runtime-WAMR-1.1.1/tests/wamr-test-suites/spec-test-script/runtest.py rename to lib/wasm-micro-runtime-WAMR-1.2.2/tests/wamr-test-suites/spec-test-script/runtest.py index ef4eb162ca4..a1e505bd047 100755 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/tests/wamr-test-suites/spec-test-script/runtest.py +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/tests/wamr-test-suites/spec-test-script/runtest.py @@ -1,32 +1,34 @@ #!/usr/bin/env python from __future__ import print_function -import os, sys, re -from pickletools import long1 -import argparse, time -import signal, atexit, tempfile, subprocess - -from subprocess import Popen, STDOUT, PIPE -from select import select +import argparse +import array +import atexit +import fcntl +import math +import os # Pseudo-TTY and terminal manipulation -import pty, array, fcntl, termios - +import pty +import re import shutil - import struct -import math +import subprocess +import sys +import tempfile +import termios +import time import traceback +from select import select +from subprocess import PIPE, STDOUT, Popen -try: - long +if sys.version_info[0] == 2: IS_PY_3 = False -except NameError: - long = int +else: IS_PY_3 = True test_aot = False -# "x86_64", "i386", "aarch64", "armv7" or "thumbv7" +# "x86_64", "i386", "aarch64", "armv7", "thumbv7", "riscv32_ilp32", "riscv32_ilp32d", "riscv32_lp64", "riscv64_lp64d" test_target = "x86_64" debug_file = None @@ -35,10 +37,8 @@ # to save the register module with self-define name temp_file_repo = [] -# get current work directory -current_work_directory = os.getcwd() -# set temporal file directory -temp_file_directory = os.path.join(current_work_directory,"tempfile") +# to save the mapping of module files in /tmp by name +temp_module_table = {} def debug(data): if debug_file: @@ -54,6 +54,7 @@ def log(data, end='\n'): # TODO: do we need to support '\n' too import platform + if platform.system().find("CYGWIN_NT") >= 0: # TODO: this is weird, is this really right on Cygwin? sep = "\n\r\n" @@ -154,7 +155,8 @@ def cleanup(self): self.stdout.close() self.stdin = None self.stdout = None - sys.exc_clear() + if not IS_PY_3: + sys.exc_clear() def assert_prompt(runner, prompts, timeout, is_need_execute_result): # Wait for the initial prompt @@ -198,6 +200,8 @@ def assert_prompt(runner, prompts, timeout, is_need_execute_result): help="Use direct pipes instead of pseudo-tty") parser.add_argument('--log-file', type=str, help="Write messages to the named file in addition the screen") +parser.add_argument('--log-dir', type=str, + help="The log directory to save the case file if test failed") parser.add_argument('--debug-file', type=str, help="Write all test interaction the named file") @@ -207,9 +211,9 @@ def assert_prompt(runner, prompts, timeout, is_need_execute_result): parser.add_argument('--aot', action='store_true', help="Test with AOT") -parser.add_argument('--aot-target', type=str, +parser.add_argument('--target', type=str, default="x86_64", - help="Set aot target") + help="Set running target") parser.add_argument('--sgx', action='store_true', help="Test SGX") @@ -220,9 +224,20 @@ def assert_prompt(runner, prompts, timeout, is_need_execute_result): parser.add_argument('--xip', default=False, action='store_true', help="Enable XIP") +parser.add_argument('--multi-module', default=False, action='store_true', + help="Enable Multi-thread") + parser.add_argument('--multi-thread', default=False, action='store_true', help="Enable Multi-thread") +parser.add_argument('--gc', default=False, action='store_true', + help='Test with GC') + +parser.add_argument('--qemu', default=False, action='store_true', + help="Enable QEMU") + +parser.add_argument('--qemu-firmware', default='', help="Firmware required by qemu") + parser.add_argument('--verbose', default=False, action='store_true', help='show more logs') @@ -408,11 +423,20 @@ def parse_simple_const_w_type(number, type): number = float.fromhex(number) if '0x' in number else float(number) return number, "{:.7g}:{}".format(number, type) elif type == "ref.null": - # hard coding - return "extern", "extern:ref.null" + if number == "func": + return "func", "func:ref.null" + elif number == "extern": + return "extern", "extern:ref.null" + elif number == "any": + return "any", "any:ref.null" + else: + raise Exception("invalid value {} and type {}".format(number, type)) elif type == "ref.extern": number = int(number, 16) if '0x' in number else int(number) return number, "0x{:x}:ref.extern".format(number) + elif type == "ref.host": + number = int(number, 16) if '0x' in number else int(number) + return number, "0x{:x}:ref.host".format(number) else: raise Exception("invalid value {} and type {}".format(number, type)) @@ -428,6 +452,10 @@ def parse_assertion_value(val): type.const val ref.extern val ref.null ref_type + ref.array + ref.struct + ref.func + ref.i31 """ if not val: return None, "" @@ -441,6 +469,8 @@ def parse_assertion_value(val): if type in ["i32", "i64", "f32", "f64"]: return parse_simple_const_w_type(numbers[0], type) elif type == "ref": + if splitted[0] in ["ref.array", "ref.struct", "ref.func", "ref.i31"]: + return splitted[0] # need to distinguish between "ref.null" and "ref.extern" return parse_simple_const_w_type(numbers[0], splitted[0]) else: @@ -603,6 +633,9 @@ def simple_value_comparison(out, expected): elif "ref.extern" == expected_type: out_val_binary = out_val expected_val_binary = expected_val + elif "ref.host" == expected_type: + out_val_binary = out_val + expected_val_binary = expected_val else: assert(0), "unknown 'expected_type' {}".format(expected_type) @@ -625,8 +658,10 @@ def value_comparison(out, expected): if not expected: return False - assert(':' in out), "out should be in a form likes numbers:type, but {}".format(out) - assert(':' in expected), "expected should be in a form likes numbers:type, but {}".format(expected) + if not out in ["ref.array", "ref.struct", "ref.func", "ref.any", "ref.i31"]: + assert(':' in out), "out should be in a form likes numbers:type, but {}".format(out) + if not expected in ["ref.array", "ref.struct", "ref.func", "ref.any", "ref.i31"]: + assert(':' in expected), "expected should be in a form likes numbers:type, but {}".format(expected) if 'v128' in out: return vector_value_comparison(out, expected) @@ -639,10 +674,10 @@ def is_result_match_expected(out, expected): def test_assert(r, opts, mode, cmd, expected): log("Testing(%s) %s = %s" % (mode, cmd, expected)) - out = invoke(r, opts, cmd) - outs = [''] + out.split('\n')[1:] - out = outs[-1] + if '\n' in out or ' ' in out: + outs = [''] + out.split('\n')[1:] + out = outs[-1] if mode=='trap': o = re.sub('^Exception: ', '', out) @@ -749,6 +784,9 @@ def test_assert_return(r, opts, form): elif "ref.extern" == splitted[0]: number, _ = parse_simple_const_w_type(splitted[1], splitted[0]) args.append(str(number)) + elif "ref.host" == splitted[0]: + number, _ = parse_simple_const_w_type(splitted[1], splitted[0]) + args.append(str(number)) else: assert(0), "an unkonwn parameter type" @@ -757,10 +795,20 @@ def test_assert_return(r, opts, form): else: returns = re.split("\)\s*\(", m.group(3)[1:-1]) # processed numbers in strings - expected = [parse_assertion_value(v)[1] for v in returns] - test_assert(r, opts, "return", "%s %s" % (func, " ".join(args)), ",".join(expected)) + if len(returns) == 1 and returns[0] in ["ref.array", "ref.struct", "ref.i31", + "ref.eq", "ref.any", "ref.extern", + "ref.func", "ref.null"]: + expected = [returns[0]] + elif len(returns) == 1 and returns[0] in ["func:ref.null", "any:ref.null", + "extern:ref.null"]: + expected = [returns[0]] + else: + expected = [parse_assertion_value(v)[1] for v in returns] + expected = ",".join(expected) + + test_assert(r, opts, "return", "%s %s" % (func, " ".join(args)), expected) elif not m and n: - module = os.path.join(temp_file_directory,n.group(1)) + module = temp_module_table[n.group(1)].split(".wasm")[0] # assume the cmd is (assert_return(invoke $ABC "func")). # run the ABC.wasm firstly if test_aot: @@ -771,9 +819,7 @@ def test_assert_return(r, opts, form): _, exc, _ = sys.exc_info() log("Run wamrc failed:\n got: '%s'" % r.buf) sys.exit(1) - r = run_wasm_with_repl(module+".wasm", module+".aot", opts, r) - else: - r = run_wasm_with_repl(module+".wasm", None, opts, r) + r = run_wasm_with_repl(module+".wasm", module+".aot" if test_aot else module, opts, r) # Wait for the initial prompt try: assert_prompt(r, ['webassembly> '], opts.start_timeout, False) @@ -788,10 +834,10 @@ def test_assert_return(r, opts, form): if n.group(3) == '': args=[] else: - args = [re.split(' +', v)[1] for v in re.split("\)\s*\(", n.group(3)[1:-1])] - - # a workaround for "ref.null extern" and "ref.null func" - args = [ arg.replace('extern', 'null').replace('func', 'null') for arg in args] + # convert (ref.null extern/func) into (ref.null null) + n1 = n.group(3).replace("(ref.null extern)", "(ref.null null)") + n1 = n1.replace("ref.null func)", "(ref.null null)") + args = [re.split(' +', v)[1] for v in re.split("\)\s*\(", n1[1:-1])] _, expected = parse_assertion_value(n.group(4)[1:-1]) test_assert(r, opts, "return", "%s %s" % (func, " ".join(args)), expected) @@ -816,16 +862,18 @@ def test_assert_trap(r, opts, form): if m.group(2) == '': args = [] else: - args = [re.split(' +', v)[1] for v in re.split("\)\s*\(", m.group(2)[1:-1])] - - # workaround for "ref.null extern" - args = [ arg.replace('extern', 'null').replace('func', 'null') for arg in args] + # convert (ref.null extern/func) into (ref.null null) + m1 = m.group(2).replace("(ref.null extern)", "(ref.null null)") + m1 = m1.replace("ref.null func)", "(ref.null null)") + args = [re.split(' +', v)[1] for v in re.split("\)\s*\(", m1[1:-1])] expected = "Exception: %s" % m.group(3) test_assert(r, opts, "trap", "%s %s" % (func, " ".join(args)), expected) elif not m and n: module = n.group(1) + module = tempfile.gettempdir() + "/" + module + # will trigger the module named in assert_return(invoke $ABC). # run the ABC.wasm firstly if test_aot: @@ -836,9 +884,7 @@ def test_assert_trap(r, opts, form): _, exc, _ = sys.exc_info() log("Run wamrc failed:\n got: '%s'" % r.buf) sys.exit(1) - r = run_wasm_with_repl(module+".wasm", module+".aot", opts, r) - else: - r = run_wasm_with_repl(module+".wasm", None, opts, r) + r = run_wasm_with_repl(module+".wasm", module+".aot" if test_aot else module, opts, r) # Wait for the initial prompt try: assert_prompt(r, ['webassembly> '], opts.start_timeout, False) @@ -906,10 +952,11 @@ def compile_wast_to_wasm(form, wast_tempfile, wasm_tempfile, opts): log("Compiling WASM to '%s'" % wasm_tempfile) # default arguments - cmd = [opts.wast2wasm, - "--enable-thread", - "--no-check", - wast_tempfile, "-o", wasm_tempfile ] + if opts.gc: + cmd = [opts.wast2wasm, "-u", "-d", wast_tempfile, "-o", wasm_tempfile] + else: + cmd = [opts.wast2wasm, "--enable-thread", "--no-check", + wast_tempfile, "-o", wasm_tempfile ] # remove reference-type and bulk-memory enabling options since a WABT # commit 30c1e983d30b33a8004b39fd60cbd64477a7956c @@ -924,7 +971,7 @@ def compile_wast_to_wasm(form, wast_tempfile, wasm_tempfile, opts): return True -def compile_wasm_to_aot(wasm_tempfile, aot_tempfile, runner, opts, r): +def compile_wasm_to_aot(wasm_tempfile, aot_tempfile, runner, opts, r, output = 'default'): log("Compiling AOT to '%s'" % aot_tempfile) cmd = [opts.aot_compiler] @@ -938,11 +985,15 @@ def compile_wasm_to_aot(wasm_tempfile, aot_tempfile, runner, opts, r): elif test_target == "armv7": cmd += ["--target=armv7", "--target-abi=gnueabihf"] elif test_target == "thumbv7": - cmd += ["--target=thumbv7", "--target-abi=gnueabihf", "--cpu=cortex-a15"] - elif test_target == "riscv64_lp64d": - cmd += ["--target=riscv64", "--target-abi=lp64d"] + cmd += ["--target=thumbv7", "--target-abi=gnueabihf", "--cpu=cortex-a9", "--cpu-features=-neon"] + elif test_target == "riscv32_ilp32": + cmd += ["--target=riscv32", "--target-abi=ilp32", "--cpu=generic-rv32", "--cpu-features=+m,+a,+c"] + elif test_target == "riscv32_ilp32d": + cmd += ["--target=riscv32", "--target-abi=ilp32d", "--cpu=generic-rv32", "--cpu-features=+m,+a,+c"] elif test_target == "riscv64_lp64": - cmd += ["--target=riscv64", "--target-abi=lp64"] + cmd += ["--target=riscv64", "--target-abi=lp64", "--cpu=generic-rv64", "--cpu-features=+m,+a,+c"] + elif test_target == "riscv64_lp64d": + cmd += ["--target=riscv64", "--target-abi=lp64d", "--cpu=generic-rv32", "--cpu-features=+m,+a,+c"] else: pass @@ -959,6 +1010,11 @@ def compile_wasm_to_aot(wasm_tempfile, aot_tempfile, runner, opts, r): if opts.multi_thread: cmd.append("--enable-multi-thread") + if output == 'object': + cmd.append("--format=object") + elif output == 'ir': + cmd.append("--format=llvmir-opt") + # disable llvm link time optimization as it might convert # code of tail call into code of dead loop, and stack overflow # exception isn't thrown in several cases @@ -976,59 +1032,57 @@ def compile_wasm_to_aot(wasm_tempfile, aot_tempfile, runner, opts, r): return r def run_wasm_with_repl(wasm_tempfile, aot_tempfile, opts, r): - if not test_aot: - log("Starting interpreter for module '%s'" % wasm_tempfile) - if opts.verbose: - cmd = [opts.interpreter, "--heap-size=0", "-v=5", "--repl", wasm_tempfile] - else: - cmd = [opts.interpreter, "--heap-size=0", "--repl", wasm_tempfile] + tmpfile = aot_tempfile if test_aot else wasm_tempfile + log("Starting interpreter for module '%s'" % tmpfile) + + cmd_iwasm = [opts.interpreter, "--heap-size=0", "-v=5" if opts.verbose else "-v=0", "--repl", tmpfile] + + if opts.multi_module: + cmd_iwasm.insert(1, "--module-path=" + (tempfile.gettempdir() if not opts.qemu else "/tmp" )) + + if opts.qemu: + if opts.qemu_firmware == '': + raise Exception("QEMU firmware missing") + + if opts.target == "thumbv7": + cmd = ["qemu-system-arm", "-semihosting", "-M", "sabrelite", "-m", "1024", "-smp", "4", "-nographic", "-kernel", opts.qemu_firmware] + elif opts.target == "riscv32_ilp32": + cmd = ["qemu-system-riscv32", "-semihosting", "-M", "virt,aclint=on", "-cpu", "rv32", "-smp", "8", "-nographic", "-bios", "none", "-kernel", opts.qemu_firmware] + elif opts.target == "riscv64_lp64": + cmd = ["qemu-system-riscv64", "-semihosting", "-M", "virt,aclint=on", "-cpu", "rv64", "-smp", "8", "-nographic", "-bios", "none", "-kernel", opts.qemu_firmware] + else: - log("Starting aot for module '%s'" % aot_tempfile) - if opts.verbose: - cmd = [opts.interpreter, "--heap-size=0", "-v=5", "--repl", aot_tempfile] - else: - cmd = [opts.interpreter, "--heap-size=0", "--repl", aot_tempfile] + cmd = cmd_iwasm log("Running: %s" % " ".join(cmd)) if (r != None): r.cleanup() r = Runner(cmd, no_pty=opts.no_pty) + + if opts.qemu: + r.read_to_prompt(['nsh> '], 10) + r.writeline("mount -t hostfs -o fs={} /tmp".format(tempfile.gettempdir())) + r.read_to_prompt(['nsh> '], 10) + r.writeline(" ".join(cmd_iwasm)) + return r def create_tmpfiles(wast_name): tempfiles = [] - # make tempfile directory - if not os.path.exists(temp_file_directory): - os.mkdir(temp_file_directory) - - def makefile(name): - open(name, "w").close() - - # create temporal file with particular name - temp_wast_file = os.path.join(temp_file_directory, ""+ wast_name + ".wast") - if not os.path.exists(temp_wast_file): - makefile(temp_wast_file) - tempfiles.append(temp_wast_file) - - # now we define the same file name as wast for wasm & aot - wasm_file = wast_name +".wasm" - temp_wasm_file = os.path.join(temp_file_directory, wasm_file) - if not os.path.exists(temp_wasm_file): - makefile(temp_wasm_file) - tempfiles.append(temp_wasm_file) + (t1fd, wast_tempfile) = tempfile.mkstemp(suffix=".wast") + (t2fd, wasm_tempfile) = tempfile.mkstemp(suffix=".wasm") + tempfiles.append(wast_tempfile) + tempfiles.append(wasm_tempfile) if test_aot: - aot_file = wast_name +".aot" - temp_aot_file =os.path.join(temp_file_directory, aot_file) - if not os.path.exists(temp_aot_file): - makefile(temp_aot_file) - tempfiles.append(temp_aot_file) + (t3fd, aot_tempfile) = tempfile.mkstemp(suffix=".aot") + tempfiles.append(aot_tempfile) # add these temp file to temporal repo, will be deleted when finishing the test temp_file_repo.extend(tempfiles) return tempfiles -def test_assert_with_exception(form, wast_tempfile, wasm_tempfile, aot_tempfile, opts, r): +def test_assert_with_exception(form, wast_tempfile, wasm_tempfile, aot_tempfile, opts, r, loadable = True): details_inside_ast = get_module_exp_from_assert(form) log("module is ....'%s'"%details_inside_ast[0]) log("exception is ....'%s'"%details_inside_ast[1]) @@ -1054,29 +1108,32 @@ def test_assert_with_exception(form, wast_tempfile, wasm_tempfile, aot_tempfile, log("Run wamrc failed:\n expected: '%s'\n got: '%s'" % \ (expected, r.buf)) sys.exit(1) - r = run_wasm_with_repl(wasm_tempfile, aot_tempfile, opts, r) - else: - r = run_wasm_with_repl(wasm_tempfile, None, opts, r) - # Wait for the initial prompt - try: - assert_prompt(r, ['webassembly> '], opts.start_timeout, True) - except: - _, exc, _ = sys.exc_info() - if (r.buf.find(expected) >= 0): - log("Out exception includes expected one, pass:") - log(" Expected: %s" %expected) - log(" Got: %s" % r.buf) - else: - raise Exception("Failed:\n expected: '%s'\n got: '%s'" % \ - (expected, r.buf)) + r = run_wasm_with_repl(wasm_tempfile, aot_tempfile if test_aot else None, opts, r) + + # Some module couldn't load so will raise an error directly, so shell prompt won't show here + + if loadable: + # Wait for the initial prompt + try: + assert_prompt(r, ['webassembly> '], opts.start_timeout, True) + except: + _, exc, _ = sys.exc_info() + if (r.buf.find(expected) >= 0): + log("Out exception includes expected one, pass:") + log(" Expected: %s" %expected) + log(" Got: %s" % r.buf) + else: + raise Exception("Failed:\n expected: '%s'\n got: '%s'" % \ + (expected, r.buf)) if __name__ == "__main__": opts = parser.parse_args(sys.argv[1:]) + print('Input param :',opts) if opts.aot: test_aot = True # default x86_64 - test_target = opts.aot_target + test_target = opts.target if opts.rundir: os.chdir(opts.rundir) @@ -1108,17 +1165,11 @@ def test_assert_with_exception(form, wast_tempfile, wasm_tempfile, aot_tempfile, elif skip_test(form, SKIP_TESTS): log("Skipping test: %s" % form[0:60]) elif re.match("^\(assert_trap\s+\(module", form): - if test_aot: - test_assert_with_exception(form, wast_tempfile, wasm_tempfile, aot_tempfile, opts, r) - else: - test_assert_with_exception(form, wast_tempfile, wasm_tempfile, None, opts, r) + test_assert_with_exception(form, wast_tempfile, wasm_tempfile, aot_tempfile if test_aot else None, opts, r) elif re.match("^\(assert_exhaustion\\b.*", form): test_assert_exhaustion(r, opts, form) elif re.match("^\(assert_unlinkable\\b.*", form): - if test_aot: - test_assert_with_exception(form, wast_tempfile, wasm_tempfile, aot_tempfile, opts, r) - else: - test_assert_with_exception(form, wast_tempfile, wasm_tempfile, None, opts, r) + test_assert_with_exception(form, wast_tempfile, wasm_tempfile, aot_tempfile if test_aot else None, opts, r, False) elif re.match("^\(assert_malformed\\b.*", form): # remove comments in wast form,n = re.subn(";;.*\n", "", form) @@ -1128,11 +1179,15 @@ def test_assert_with_exception(form, wast_tempfile, wasm_tempfile, aot_tempfile, # workaround: spec test changes error message to "malformed" while iwasm still use "invalid" error_msg = m.group(2).replace("malformed", "invalid") log("Testing(malformed)") - f = open(wasm_tempfile, 'w') + f = open(wasm_tempfile, 'wb') s = m.group(1) while s: res = re.match("[^\"]*\"([^\"]*)\"(.*)", s, re.DOTALL) - f.write(res.group(1).replace("\\", "\\x").decode("string_escape")) + if IS_PY_3: + context = res.group(1).replace("\\", "\\x").encode("latin1").decode("unicode-escape").encode("latin1") + f.write(context) + else: + f.write(res.group(1).replace("\\", "\\x").decode("string-escape")) s = res.group(2) f.close() @@ -1151,32 +1206,22 @@ def test_assert_with_exception(form, wast_tempfile, wasm_tempfile, aot_tempfile, log("Run wamrc failed:\n expected: '%s'\n got: '%s'" % \ (error_msg, r.buf)) continue - cmd = [opts.interpreter, "--heap-size=0", "--repl", aot_tempfile] - else: - cmd = [opts.interpreter, "--heap-size=0", "--repl", wasm_tempfile] - log("Running: %s" % " ".join(cmd)) - output = subprocess.check_output(cmd) - - if (error_msg == "unexpected end of section or function") \ - and output.endswith("unexpected end\n"): + + r = run_wasm_with_repl(wasm_tempfile, aot_tempfile if test_aot else None, opts, r) + + if (error_msg == "unexpected end of section or function"): # one case in binary.wast - pass - elif (error_msg == "invalid value type") \ - and output.endswith("unexpected end\n"): + assert_prompt(r, ["unexpected end", error_msg], opts.start_timeout, True) + elif (error_msg == "invalid value type"): # one case in binary.wast - pass - elif (error_msg == "length out of bounds") \ - and output.endswith("unexpected end\n"): + assert_prompt(r, ["unexpected end", error_msg], opts.start_timeout, True) + elif (error_msg == "length out of bounds"): # one case in custom.wast - pass - elif (error_msg == "integer representation too long") \ - and output.endswith("invalid section id\n"): + assert_prompt(r, ["unexpected end", error_msg], opts.start_timeout, True) + elif (error_msg == "integer representation too long"): # several cases in binary-leb128.wast - pass - elif not error_msg in output: - raise Exception("Failed:\n expected: '%s'\n got: '%s'" % (error_msg, output[0:-1])) - else: - pass + assert_prompt(r, ["invalid section id", error_msg], opts.start_timeout, True) + elif re.match("^\(assert_malformed\s*\(module quote", form): log("ignoring assert_malformed module quote") else: @@ -1210,9 +1255,8 @@ def test_assert_with_exception(form, wast_tempfile, wasm_tempfile, aot_tempfile, _, exc, _ = sys.exc_info() log("Run wamrc failed:\n got: '%s'" % r.buf) sys.exit(1) - r = run_wasm_with_repl(temp_files[1], temp_files[2], opts, r) - else: - r = run_wasm_with_repl(temp_files[1], None, opts, r) + temp_module_table[module_name] = temp_files[1] + r = run_wasm_with_repl(temp_files[1], temp_files[2] if test_aot else None, opts, r) else: if not compile_wast_to_wasm(form, wast_tempfile, wasm_tempfile, opts): raise Exception("compile wast to wasm failed") @@ -1225,9 +1269,8 @@ def test_assert_with_exception(form, wast_tempfile, wasm_tempfile, aot_tempfile, _, exc, _ = sys.exc_info() log("Run wamrc failed:\n got: '%s'" % r.buf) sys.exit(1) - r = run_wasm_with_repl(wasm_tempfile, aot_tempfile, opts, r) - else: - r = run_wasm_with_repl(wasm_tempfile, None, opts, r) + + r = run_wasm_with_repl(wasm_tempfile, aot_tempfile if test_aot else None, opts, r) # Wait for the initial prompt try: @@ -1246,32 +1289,14 @@ def test_assert_with_exception(form, wast_tempfile, wasm_tempfile, aot_tempfile, assert(r), "iwasm repl runtime should be not null" do_invoke(r, opts, form) elif re.match("^\(assert_invalid\\b.*", form): - if test_aot: - test_assert_with_exception(form, wast_tempfile, wasm_tempfile, aot_tempfile, opts, r) - else: - test_assert_with_exception(form, wast_tempfile, wasm_tempfile, None, opts, r) - - + test_assert_with_exception(form, wast_tempfile, wasm_tempfile, aot_tempfile if test_aot else None, opts, r) elif re.match("^\(register\\b.*", form): # get module's new name from the register cmd name_new =re.split('\"',re.search('\".*\"',form).group(0))[1] if name_new: - # if the register cmd include the new and old module name. - # like: (register "new" $old) - # we will replace the old with new name. - name_old = re.search('\$.*\)',form) - if name_old: - old_ = re.split('\W', re.search('\$.*\)',form).group(0))[1] - old_module = os.path.join(temp_file_directory,old_+".wasm") - else: - # like: (register "new") - # this kind of register cmd will be behind of a noramal module - # these modules' name are default temporal file name - # we replace them with new name. - old_module = wasm_tempfile - - new_module = os.path.join(current_work_directory,name_new+".wasm") - shutil.copyfile(old_module,new_module) + new_module = os.path.join(tempfile.gettempdir(), name_new + ".wasm") + shutil.copyfile(temp_module_table.get(name_new, wasm_tempfile), new_module) + # add new_module copied from the old into temp_file_repo[] temp_file_repo.append(new_module) else: @@ -1283,6 +1308,18 @@ def test_assert_with_exception(form, wast_tempfile, wasm_tempfile, aot_tempfile, traceback.print_exc() print("THE FINAL EXCEPTION IS {}".format(e)) ret_code = 101 + + shutil.copyfile(wasm_tempfile, os.path.join(opts.log_dir, os.path.basename(wasm_tempfile))) + + if opts.aot or opts.xip: + shutil.copyfile(aot_tempfile, os.path.join(opts.log_dir,os.path.basename(aot_tempfile))) + if "indirect-mode" in str(e): + compile_wasm_to_aot(wasm_tempfile, aot_tempfile, None, opts, None, "object") + shutil.copyfile(aot_tempfile, os.path.join(opts.log_dir,os.path.basename(aot_tempfile)+'.o')) + subprocess.check_call(["llvm-objdump", "-r", aot_tempfile]) + compile_wasm_to_aot(wasm_tempfile, aot_tempfile, None, opts, None, "ir") + shutil.copyfile(aot_tempfile, os.path.join(opts.log_dir,os.path.basename(aot_tempfile)+".ir")) + else: ret_code = 0 finally: @@ -1298,9 +1335,6 @@ def test_assert_with_exception(form, wast_tempfile, wasm_tempfile, aot_tempfile, for t in temp_file_repo: if(len(str(t))!=0 and os.path.exists(t)): os.remove(t) - # remove /tempfiles/ directory - if os.path.exists(temp_file_directory): - shutil.rmtree(temp_file_directory) log("### End testing %s" % opts.test_file.name) else: diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/tests/wamr-test-suites/spec-test-script/simd_ignore_cases.patch b/lib/wasm-micro-runtime-WAMR-1.2.2/tests/wamr-test-suites/spec-test-script/simd_ignore_cases.patch similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/tests/wamr-test-suites/spec-test-script/simd_ignore_cases.patch rename to lib/wasm-micro-runtime-WAMR-1.2.2/tests/wamr-test-suites/spec-test-script/simd_ignore_cases.patch diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/tests/wamr-test-suites/spec-test-script/tail-call/return_call.wast b/lib/wasm-micro-runtime-WAMR-1.2.2/tests/wamr-test-suites/spec-test-script/tail-call/return_call.wast similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/tests/wamr-test-suites/spec-test-script/tail-call/return_call.wast rename to lib/wasm-micro-runtime-WAMR-1.2.2/tests/wamr-test-suites/spec-test-script/tail-call/return_call.wast diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/tests/wamr-test-suites/spec-test-script/tail-call/return_call_indirect.wast b/lib/wasm-micro-runtime-WAMR-1.2.2/tests/wamr-test-suites/spec-test-script/tail-call/return_call_indirect.wast similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/tests/wamr-test-suites/spec-test-script/tail-call/return_call_indirect.wast rename to lib/wasm-micro-runtime-WAMR-1.2.2/tests/wamr-test-suites/spec-test-script/tail-call/return_call_indirect.wast diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/tests/wamr-test-suites/spec-test-script/thread_proposal_fix_atomic_case.patch b/lib/wasm-micro-runtime-WAMR-1.2.2/tests/wamr-test-suites/spec-test-script/thread_proposal_fix_atomic_case.patch similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/tests/wamr-test-suites/spec-test-script/thread_proposal_fix_atomic_case.patch rename to lib/wasm-micro-runtime-WAMR-1.2.2/tests/wamr-test-suites/spec-test-script/thread_proposal_fix_atomic_case.patch diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/tests/wamr-test-suites/spec-test-script/thread_proposal_ignore_cases.patch b/lib/wasm-micro-runtime-WAMR-1.2.2/tests/wamr-test-suites/spec-test-script/thread_proposal_ignore_cases.patch similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/tests/wamr-test-suites/spec-test-script/thread_proposal_ignore_cases.patch rename to lib/wasm-micro-runtime-WAMR-1.2.2/tests/wamr-test-suites/spec-test-script/thread_proposal_ignore_cases.patch diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/tests/wamr-test-suites/test_wamr.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/tests/wamr-test-suites/test_wamr.sh similarity index 59% rename from lib/wasm-micro-runtime-WAMR-1.1.1/tests/wamr-test-suites/test_wamr.sh rename to lib/wasm-micro-runtime-WAMR-1.2.2/tests/wamr-test-suites/test_wamr.sh index dfcde06d8ce..67868b9c9ed 100755 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/tests/wamr-test-suites/test_wamr.sh +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/tests/wamr-test-suites/test_wamr.sh @@ -14,36 +14,50 @@ function help() { echo "test_wamr.sh [options]" echo "-c clean previous test results, not start test" - echo "-s {suite_name} test only one suite (spec)" - echo "-m set compile target of iwasm(x86_64\x86_32\armv7_vfp\thumbv7_vfp\riscv64_lp64d\riscv64_lp64)" - echo "-t set compile type of iwasm(classic-interp\fast-interp\jit\aot\fast-jit)" + echo "-s {suite_name} test only one suite (spec|wasi_certification)" + echo "-m set compile target of iwasm(x86_64|x86_32|armv7_vfp|thumbv7_vfp|riscv64_lp64d|riscv64_lp64)" + echo "-t set compile type of iwasm(classic-interp|fast-interp|jit|aot|fast-jit|multi-tier-jit)" echo "-M enable multi module feature" echo "-p enable multi thread feature" echo "-S enable SIMD feature" + echo "-G enable GC feature" echo "-X enable XIP feature" echo "-x test SGX" + echo "-w enable WASI threads" echo "-b use the wabt binary release package instead of compiling from the source code" + echo "-g build iwasm with debug version" + echo "-v enable GC heap verification" echo "-P run the spec test parallelly" + echo "-Q enable qemu" + echo "-F set the firmware path used by qemu" + echo "-C enable code coverage collect" } OPT_PARSED="" WABT_BINARY_RELEASE="NO" #default type -TYPE=("classic-interp" "fast-interp" "jit" "aot" "fast-jit") +TYPE=("classic-interp" "fast-interp" "jit" "aot" "fast-jit" "multi-tier-jit") #default target TARGET="X86_64" +ENABLE_WASI_THREADS=0 ENABLE_MULTI_MODULE=0 ENABLE_MULTI_THREAD=0 COLLECT_CODE_COVERAGE=0 ENABLE_SIMD=0 +ENABLE_GC=0 ENABLE_XIP=0 +ENABLE_DEBUG_VERSION=0 +ENABLE_GC_HEAP_VERIFY=0 #unit test case arrary TEST_CASE_ARR=() SGX_OPT="" PLATFORM=$(uname -s | tr A-Z a-z) PARALLELISM=0 +ENABLE_QEMU=0 +QEMU_FIRMWARE="" +WASI_TESTSUITE_COMMIT="aca78d919355ae00af141e6741a439039615b257" -while getopts ":s:cabt:m:MCpSXxP" opt +while getopts ":s:cabgvt:m:MCpSXxwPGQF:" opt do OPT_PARSED="TRUE" case $opt in @@ -65,8 +79,9 @@ do c) read -t 5 -p "Are you sure to delete all reports. y/n " cmd if [[ $cmd == "y" && $(ls -A workspace/report) ]];then - rm -r workspace/report/* - echo "cleaned all reports" + rm -fr workspace/report/* + rm -fr /tmp/*.wasm /tmp/*.wast /tmp/*.aot + echo "cleaned all reports and temp files" fi exit 0;; a) @@ -80,7 +95,8 @@ do t) echo "set compile type of wamr " ${OPTARG} if [[ ${OPTARG} != "classic-interp" && ${OPTARG} != "fast-interp" \ - && ${OPTARG} != "jit" && ${OPTARG} != "aot" && ${OPTARG} != "fast-jit" ]]; then + && ${OPTARG} != "jit" && ${OPTARG} != "aot" + && ${OPTARG} != "fast-jit" && ${OPTARG} != "multi-tier-jit" ]]; then echo "*----- please varify a type of compile when using -t! -----*" help exit 1 @@ -92,6 +108,10 @@ do echo "set compile target of wamr" ${OPTARG} TARGET=${OPTARG^^} # set target to uppercase if input x86_32 or x86_64 --> X86_32 and X86_64 ;; + w) + echo "enable WASI threads" + ENABLE_WASI_THREADS=1 + ;; M) echo "enable multi module feature" ENABLE_MULTI_MODULE=1 @@ -116,9 +136,29 @@ do echo "test SGX" SGX_OPT="--sgx" ;; + g) + echo "enable build iwasm with debug version" + ENABLE_DEBUG_VERSION=1 + ;; + v) + echo "enable GC heap verification" + ENABLE_GC_HEAP_VERIFY=1 + ;; + G) + echo "enable GC feature" + ENABLE_GC=1 + ;; P) PARALLELISM=1 ;; + Q) + echo "enable QEMU" + ENABLE_QEMU=1 + ;; + F) + echo "QEMU firmware" ${OPTARG} + QEMU_FIRMWARE=${OPTARG} + ;; ?) help exit 1;; @@ -144,7 +184,6 @@ readonly DATE=$(date +%Y-%m-%d_%H:%M:%S) readonly REPORT_DIR=${WORK_DIR}/report/${DATE} mkdir -p ${REPORT_DIR} -# TODO: a strong assumation about a link to the WAMR project readonly WAMR_DIR=${WORK_DIR}/../../.. if [[ ${SGX_OPT} == "--sgx" ]];then @@ -173,11 +212,21 @@ readonly FAST_INTERP_COMPILE_FLAGS="\ # jit: report linking error if set COLLECT_CODE_COVERAGE, # now we don't collect code coverage of jit type -readonly JIT_COMPILE_FLAGS="\ +readonly ORC_EAGER_JIT_COMPILE_FLAGS="\ + -DWAMR_BUILD_TARGET=${TARGET} \ + -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_FAST_INTERP=0 \ + -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_AOT=1 \ + -DWAMR_BUILD_LAZY_JIT=0 \ + -DWAMR_BUILD_SPEC_TEST=1 \ + -DCOLLECT_CODE_COVERAGE=${COLLECT_CODE_COVERAGE}" + +readonly ORC_LAZY_JIT_COMPILE_FLAGS="\ -DWAMR_BUILD_TARGET=${TARGET} \ -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_FAST_INTERP=0 \ -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_AOT=1 \ - -DWAMR_BUILD_SPEC_TEST=1" + -DWAMR_BUILD_LAZY_JIT=1 \ + -DWAMR_BUILD_SPEC_TEST=1 \ + -DCOLLECT_CODE_COVERAGE=${COLLECT_CODE_COVERAGE}" readonly AOT_COMPILE_FLAGS="\ -DWAMR_BUILD_TARGET=${TARGET} \ @@ -191,49 +240,39 @@ readonly FAST_JIT_COMPILE_FLAGS="\ -DWAMR_BUILD_INTERP=1 -DWAMR_BUILD_FAST_INTERP=0 \ -DWAMR_BUILD_JIT=0 -DWAMR_BUILD_AOT=0 \ -DWAMR_BUILD_FAST_JIT=1 \ - -DWAMR_BUILD_SPEC_TEST=1" + -DWAMR_BUILD_SPEC_TEST=1 \ + -DCOLLECT_CODE_COVERAGE=${COLLECT_CODE_COVERAGE}" + +readonly MULTI_TIER_JIT_COMPILE_FLAGS="\ + -DWAMR_BUILD_TARGET=${TARGET} \ + -DWAMR_BUILD_INTERP=1 -DWAMR_BUILD_FAST_INTERP=0 \ + -DWAMR_BUILD_FAST_JIT=1 -DWAMR_BUILD_JIT=1 \ + -DWAMR_BUILD_SPEC_TEST=1 \ + -DCOLLECT_CODE_COVERAGE=${COLLECT_CODE_COVERAGE}" readonly COMPILE_FLAGS=( "${CLASSIC_INTERP_COMPILE_FLAGS}" "${FAST_INTERP_COMPILE_FLAGS}" - "${JIT_COMPILE_FLAGS}" + "${ORC_EAGER_JIT_COMPILE_FLAGS}" + "${ORC_LAZY_JIT_COMPILE_FLAGS}" "${AOT_COMPILE_FLAGS}" "${FAST_JIT_COMPILE_FLAGS}" + "${MULTI_TIER_JIT_COMPILE_FLAGS}" ) -# TODO: with libiwasm.so only function unit_test() { echo "Now start unit tests" cd ${WORK_DIR} - readonly UNIT_CASES="wasm-vm host-tool utils" + rm -fr unittest-build && mkdir unittest-build + cd unittest-build echo "Build unit test" touch ${REPORT_DIR}/unit_test_report.txt - - for compile_flag in "${COMPILE_FLAGS[@]}"; do - echo "Build unit test with compile flags with " ${compile_flag} - - # keep going and do not care if it is success or not - make -ki clean | true - cmake ${compile_flag} ${WORK_DIR}/../../unit && make -j 4 - if [ "$?" != 0 ];then - echo -e "build unit test failed, you may need to change wamr into dev/aot branch and ensure llvm is built" - exit 1 - fi - - echo ${compile_flag} >> ${REPORT_DIR}/unit_test_report.txt - - for case in ${UNIT_CASES} - do - echo "run ${case} ..." - cd ./${case}/ - ./${case/-/_}"_test" | tee -a ${REPORT_DIR}/unit_test_report.txt - cd - - echo "finish ${case}" - done - done + cmake ${WORK_DIR}/../../unit -DCOLLECT_CODE_COVERAGE=${COLLECT_CODE_COVERAGE} + make -j + make test | tee -a ${REPORT_DIR}/unit_test_report.txt echo "Finish unit tests" } @@ -311,6 +350,27 @@ function spec_test() git apply ../../spec-test-script/thread_proposal_fix_atomic_case.patch fi + # update GC cases + if [[ ${ENABLE_GC} == 1 ]]; then + echo "checkout spec for GC proposal" + + popd + rm -fr spec + # check spec test cases for GC + git clone -b main --single-branch https://github.com/WebAssembly/gc.git spec + pushd spec + + git restore . && git clean -ffd . + # Sync constant expression descriptions + git reset --hard 62beb94ddd41987517781732f17f213d8b866dcc + git apply ../../spec-test-script/gc_ignore_cases.patch + + echo "compile the reference intepreter" + pushd interpreter + make opt + popd + fi + popd echo $(pwd) @@ -330,16 +390,16 @@ function spec_test() exit 1 ;; esac - if [ ! -f /tmp/wabt-1.0.29-${WABT_PLATFORM}.tar.gz ]; then + if [ ! -f /tmp/wabt-1.0.31-${WABT_PLATFORM}.tar.gz ]; then wget \ - https://github.com/WebAssembly/wabt/releases/download/1.0.29/wabt-1.0.29-${WABT_PLATFORM}.tar.gz \ + https://github.com/WebAssembly/wabt/releases/download/1.0.31/wabt-1.0.31-${WABT_PLATFORM}.tar.gz \ -P /tmp fi cd /tmp \ - && tar zxf wabt-1.0.29-${WABT_PLATFORM}.tar.gz \ + && tar zxf wabt-1.0.31-${WABT_PLATFORM}.tar.gz \ && mkdir -p ${WORK_DIR}/wabt/out/gcc/Release/ \ - && install wabt-1.0.29/bin/wa* ${WORK_DIR}/wabt/out/gcc/Release/ \ + && install wabt-1.0.31/bin/wa* ${WORK_DIR}/wabt/out/gcc/Release/ \ && cd - fi else @@ -384,28 +444,43 @@ function spec_test() if [[ ${ENABLE_MULTI_THREAD} == 1 ]]; then ARGS_FOR_SPEC_TEST+="-p " - if [[ $1 == 'fast-jit' ]]; then - echo "fast-jit doesn't support multi-thread feature yet, skip it" - return - fi fi if [[ ${ENABLE_XIP} == 1 ]]; then ARGS_FOR_SPEC_TEST+="-X " fi + # set the current running target + ARGS_FOR_SPEC_TEST+="-m ${TARGET} " + # require warmc only in aot mode if [[ $1 == 'aot' ]]; then - ARGS_FOR_SPEC_TEST+="-t -m ${TARGET} " + ARGS_FOR_SPEC_TEST+="-t " fi if [[ ${PARALLELISM} == 1 ]]; then ARGS_FOR_SPEC_TEST+="--parl " fi + if [[ ${ENABLE_GC} == 1 ]]; then + ARGS_FOR_SPEC_TEST+="--gc " + fi + + if [[ ${ENABLE_QEMU} == 1 ]]; then + ARGS_FOR_SPEC_TEST+="--qemu " + ARGS_FOR_SPEC_TEST+="--qemu-firmware ${QEMU_FIRMWARE} " + fi + + # set log directory + ARGS_FOR_SPEC_TEST+="--log ${REPORT_DIR}" + cd ${WORK_DIR} + echo "python3 ./all.py ${ARGS_FOR_SPEC_TEST} | tee -a ${REPORT_DIR}/spec_test_report.txt" python3 ./all.py ${ARGS_FOR_SPEC_TEST} | tee -a ${REPORT_DIR}/spec_test_report.txt - [[ ${PIPESTATUS[0]} -ne 0 ]] && exit 1 + if [[ ${PIPESTATUS[0]} -ne 0 ]];then + echo -e "\nspec tests FAILED" | tee -a ${REPORT_DIR}/spec_test_report.txt + exit 1 + fi cd - echo -e "\nFinish spec tests" | tee -a ${REPORT_DIR}/spec_test_report.txt @@ -427,6 +502,30 @@ function wasi_test() echo "Finish wasi tests" } +function wasi_certification_test() +{ + echo "Now start wasi certification tests" + + cd ${WORK_DIR} + if [ ! -d "wasi-testsuite" ]; then + echo "wasi not exist, clone it from github" + git clone -b prod/testsuite-all \ + --single-branch https://github.com/WebAssembly/wasi-testsuite.git + fi + cd wasi-testsuite + git reset --hard ${WASI_TESTSUITE_COMMIT} + + bash ../../wasi-test-script/run_wasi_tests.sh $1 $TARGET \ + | tee -a ${REPORT_DIR}/wasi_test_report.txt + ret=${PIPESTATUS[0]} + + if [[ ${ret} -ne 0 ]];then + echo -e "\nwasi tests FAILED" | tee -a ${REPORT_DIR}/wasi_test_report.txt + exit 1 + fi + echo -e "\nFinish wasi tests" | tee -a ${REPORT_DIR}/wasi_test_report.txt +} + function polybench_test() { echo "Now start polybench tests" @@ -435,7 +534,6 @@ function polybench_test() if [[ $1 == "aot" || $1 == "jit" ]];then ./build.sh AOT ${SGX_OPT} ./test_aot.sh $1 ${SGX_OPT} - else ./build.sh ./test_interp.sh ${SGX_OPT} @@ -445,6 +543,22 @@ function polybench_test() echo "Finish polybench tests" } +function libsodium_test() +{ + echo "Now start libsodium tests" + + cd ${WORK_DIR}/../libsodium + if [[ $1 == "aot" || $1 == "jit" ]];then + ./build.sh ${SGX_OPT} + ./test_aot.sh $1 ${SGX_OPT} + else + ./test_interp.sh ${SGX_OPT} + fi + cp report.txt ${REPORT_DIR}/libsodium_$1_test_report.txt + + echo "Finish libsodium tests" +} + function malformed_test() { # build iwasm firstly @@ -452,20 +566,64 @@ function malformed_test() ./malformed_test.py --run ${IWASM_CMD} | tee ${REPORT_DIR}/malfomed_$1_test_report.txt } +function collect_standalone() +{ + if [[ ${COLLECT_CODE_COVERAGE} == 1 ]]; then + pushd ${WORK_DIR} > /dev/null 2>&1 + + CODE_COV_FILE="" + if [[ -z "${CODE_COV_FILE}" ]]; then + CODE_COV_FILE="${WORK_DIR}/wamr.lcov" + else + CODE_COV_FILE="${CODE_COV_FILE}" + fi + + STANDALONE_DIR=${WORK_DIR}/../../standalone + + echo "Collect code coverage of standalone dump-call-stack" + ./collect_coverage.sh "${CODE_COV_FILE}" "${STANDALONE_DIR}/dump-call-stack/build" + echo "Collect code coverage of standalone dump-mem-profiling" + ./collect_coverage.sh "${CODE_COV_FILE}" "${STANDALONE_DIR}/dump-mem-profiling/build" + echo "Collect code coverage of standalone dump-perf-profiling" + ./collect_coverage.sh "${CODE_COV_FILE}" "${STANDALONE_DIR}/dump-perf-profiling/build" + if [[ $1 == "aot" ]]; then + echo "Collect code coverage of standalone pad-test" + ./collect_coverage.sh "${CODE_COV_FILE}" "${STANDALONE_DIR}/pad-test/build" + fi + echo "Collect code coverage of standalone test-invoke-native" + ./collect_coverage.sh "${CODE_COV_FILE}" "${STANDALONE_DIR}/test-invoke-native/build" + echo "Collect code coverage of standalone test-running-modes" + ./collect_coverage.sh "${CODE_COV_FILE}" "${STANDALONE_DIR}/test-running-modes/build" + echo "Collect code coverage of standalone test-running-modes/c-embed" + ./collect_coverage.sh "${CODE_COV_FILE}" "${STANDALONE_DIR}/test-running-modes/c-embed/build" + echo "Collect code coverage of standalone test-ts2" + ./collect_coverage.sh "${CODE_COV_FILE}" "${STANDALONE_DIR}/test-ts2/build" + + popd > /dev/null 2>&1 + fi +} + function standalone_test() { + if [[ ${COLLECT_CODE_COVERAGE} == 1 ]]; then + export COLLECT_CODE_COVERAGE=1 + fi + cd ${WORK_DIR}/../../standalone - args="" + args="--$1" - [[ $1 == "aot" ]] && args="$args --aot" || args="$args --no-aot" [[ ${SGX_OPT} == "--sgx" ]] && args="$args --sgx" || args="$args --no-sgx" - if [[ ${ENABLE_MULTI_THREAD} == 1 ]];then - args="$args --thread" - fi + [[ ${ENABLE_MULTI_THREAD} == 1 ]] && args="$args --thread" || args="$args --no-thread" + + [[ ${ENABLE_SIMD} == 1 ]] && args="$args --simd" || args="$args --no-simd" + + args="$args ${TARGET}" ./standalone.sh $args | tee ${REPORT_DIR}/standalone_$1_test_report.txt + + collect_standalone "$1" } function build_iwasm_with_cfg() @@ -499,8 +657,8 @@ function build_iwasm_with_cfg() function build_wamrc() { if [[ $TARGET == "ARMV7_VFP" || $TARGET == "THUMBV7_VFP" - || $TARGET == "RISCV64" || $TARGET == "RISCV64_LP64D" - || $TARGET == "RISCV64_LP64" ]];then + || $TARGET == "RISCV32" || $TARGET == "RISCV32_ILP32" || $TARGET == "RISCV32_ILP32D" + || $TARGET == "RISCV64" || $TARGET == "RISCV64_LP64D" || $TARGET == "RISCV64_LP64" ]];then echo "suppose wamrc is already built" return fi @@ -510,7 +668,7 @@ function build_wamrc() && ./build_llvm.sh \ && if [ -d build ]; then rm -r build/*; else mkdir build; fi \ && cd build \ - && cmake .. \ + && cmake .. -DCOLLECT_CODE_COVERAGE=${COLLECT_CODE_COVERAGE} \ && make -j 4 } @@ -523,15 +681,33 @@ function build_wamrc() function collect_coverage() { - if [[ ${COLLECT_CODE_COVERAGE} == 1 ]];then - cd ${IWASM_LINUX_ROOT_DIR}/build - lcov -t "iwasm code coverage" -o iwasm.info -c -d . - genhtml -o iwasm-gcov iwasm.info - [[ -d iwasm-gcov ]] && \ - cp -r iwasm-gcov ${REPORT_DIR}/$1_iwasm_gcov || \ - echo "generate code coverage html failed" + if [[ ${COLLECT_CODE_COVERAGE} == 1 ]]; then + ln -sf ${WORK_DIR}/../spec-test-script/collect_coverage.sh ${WORK_DIR} + + CODE_COV_FILE="" + if [[ -z "${CODE_COV_FILE}" ]]; then + CODE_COV_FILE="${WORK_DIR}/wamr.lcov" + else + CODE_COV_FILE="${CODE_COV_FILE}" + fi + + pushd ${WORK_DIR} > /dev/null 2>&1 + echo "Collect code coverage of iwasm" + ./collect_coverage.sh ${CODE_COV_FILE} ${IWASM_LINUX_ROOT_DIR}/build + if [[ $1 == "llvm-aot" ]]; then + echo "Collect code coverage of wamrc" + ./collect_coverage.sh ${CODE_COV_FILE} ${WAMR_DIR}/wamr-compiler/build + fi + for suite in "${TEST_CASE_ARR[@]}"; do + if [[ ${suite} = "unit" ]]; then + echo "Collect code coverage of unit test" + ./collect_coverage.sh ${CODE_COV_FILE} ${WORK_DIR}/unittest-build + break + fi + done + popd > /dev/null 2>&1 else - echo "will not collect code coverage" + echo "code coverage isn't collected" fi } @@ -560,6 +736,24 @@ function trigger() EXTRA_COMPILE_FLAGS+=" -DWAMR_BUILD_SIMD=0" fi + if [[ ${ENABLE_GC} == 1 ]]; then + EXTRA_COMPILE_FLAGS+=" -DWAMR_BUILD_GC=1" + EXTRA_COMPILE_FLAGS+=" -DWAMR_BUILD_REF_TYPES=1" + EXTRA_COMPILE_FLAGS+=" -DWAMR_BUILD_BULK_MEMORY=1" + fi + + if [[ ${ENABLE_DEBUG_VERSION} == 1 ]]; then + EXTRA_COMPILE_FLAGS+=" -DCMAKE_BUILD_TYPE=Debug" + fi + + if [[ ${ENABLE_GC_HEAP_VERIFY} == 1 ]]; then + EXTRA_COMPILE_FLAGS+=" -DWAMR_BUILD_GC_HEAP_VERIFY=1" + fi + + if [[ ${ENABLE_WASI_THREADS} == 1 ]]; then + EXTRA_COMPILE_FLAGS+=" -DWAMR_BUILD_LIB_WASI_THREADS=1" + fi + for t in "${TYPE[@]}"; do case $t in "classic-interp") @@ -571,7 +765,9 @@ function trigger() echo "work in classic-interp mode" # classic-interp BUILD_FLAGS="$CLASSIC_INTERP_COMPILE_FLAGS $EXTRA_COMPILE_FLAGS" - build_iwasm_with_cfg $BUILD_FLAGS + if [[ ${ENABLE_QEMU} == 0 ]]; then + build_iwasm_with_cfg $BUILD_FLAGS + fi for suite in "${TEST_CASE_ARR[@]}"; do $suite"_test" classic-interp done @@ -587,7 +783,9 @@ function trigger() echo "work in fast-interp mode" # fast-interp BUILD_FLAGS="$FAST_INTERP_COMPILE_FLAGS $EXTRA_COMPILE_FLAGS" - build_iwasm_with_cfg $BUILD_FLAGS + if [[ ${ENABLE_QEMU} == 0 ]]; then + build_iwasm_with_cfg $BUILD_FLAGS + fi for suite in "${TEST_CASE_ARR[@]}"; do $suite"_test" fast-interp done @@ -600,36 +798,57 @@ function trigger() continue fi - echo "work in jit mode" - # jit - BUILD_FLAGS="$JIT_COMPILE_FLAGS $EXTRA_COMPILE_FLAGS" + echo "work in orc jit eager compilation mode" + BUILD_FLAGS="$ORC_EAGER_JIT_COMPILE_FLAGS $EXTRA_COMPILE_FLAGS" build_iwasm_with_cfg $BUILD_FLAGS - build_wamrc for suite in "${TEST_CASE_ARR[@]}"; do $suite"_test" jit done + collect_coverage llvm-jit + + echo "work in orc jit lazy compilation mode" + BUILD_FLAGS="$ORC_EAGER_JIT_COMPILE_FLAGS $EXTRA_COMPILE_FLAGS" + build_iwasm_with_cfg $BUILD_FLAGS + for suite in "${TEST_CASE_ARR[@]}"; do + $suite"_test" jit + done + collect_coverage llvm-jit ;; "aot") echo "work in aot mode" # aot BUILD_FLAGS="$AOT_COMPILE_FLAGS $EXTRA_COMPILE_FLAGS" - build_iwasm_with_cfg $BUILD_FLAGS + if [[ ${ENABLE_QEMU} == 0 ]]; then + build_iwasm_with_cfg $BUILD_FLAGS + fi build_wamrc for suite in "${TEST_CASE_ARR[@]}"; do $suite"_test" aot done - collect_coverage aot + collect_coverage llvm-aot ;; "fast-jit") echo "work in fast-jit mode" - # jit + # fast-jit BUILD_FLAGS="$FAST_JIT_COMPILE_FLAGS $EXTRA_COMPILE_FLAGS" build_iwasm_with_cfg $BUILD_FLAGS for suite in "${TEST_CASE_ARR[@]}"; do $suite"_test" fast-jit done + collect_coverage fast-jit + ;; + + "multi-tier-jit") + echo "work in multi-tier-jit mode" + # multi-tier-jit + BUILD_FLAGS="$MULTI_TIER_JIT_COMPILE_FLAGS $EXTRA_COMPILE_FLAGS" + build_iwasm_with_cfg $BUILD_FLAGS + for suite in "${TEST_CASE_ARR[@]}"; do + $suite"_test" multi-tier-jit + done + collect_coverage multi-tier-jit ;; *) @@ -640,11 +859,19 @@ function trigger() } # if collect code coverage, ignore -s, test all test cases. -if [[ $TEST_CASE_ARR && $COLLECT_CODE_COVERAGE != 1 ]];then +if [[ $TEST_CASE_ARR ]];then trigger || (echo "TEST FAILED"; exit 1) else - # test all suite, ignore polybench because of long time cost - TEST_CASE_ARR=("sightglass" "spec" "wasi" "malformed" "standalone") + # test all suite, ignore polybench and libsodium because of long time cost + TEST_CASE_ARR=("spec") + : ' + if [[ $COLLECT_CODE_COVERAGE == 1 ]];then + # add polybench if collecting code coverage data + TEST_CASE_ARR+=("polybench") + # add libsodium if needed, which takes long time to run + TEST_CASE_ARR+=("libsodium") + fi + ' trigger || (echo "TEST FAILED"; exit 1) # Add more suites here fi diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/tests/wamr-test-suites/wasi-test-script/run_wasi_tests.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/tests/wamr-test-suites/wasi-test-script/run_wasi_tests.sh new file mode 100755 index 00000000000..eb6cf3f91e1 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/tests/wamr-test-suites/wasi-test-script/run_wasi_tests.sh @@ -0,0 +1,80 @@ +#!/bin/bash + +# +# Copyright (C) 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# + +readonly MODE=$1 +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 WAMRC_CMD="${WORK_DIR}/../../../../wamr-compiler/build/wamrc" +readonly C_TESTS="tests/c/testsuite/" +readonly ASSEMBLYSCRIPT_TESTS="tests/assemblyscript/testsuite/" +readonly THREAD_PROPOSAL_TESTS="tests/proposals/wasi-threads/" +readonly THREAD_INTERNAL_TESTS="${WAMR_DIR}/core/iwasm/libraries/lib-wasi-threads/test/" +readonly LIB_SOCKET_TESTS="${WAMR_DIR}/core/iwasm/libraries/lib-socket/test/" + +run_aot_tests () { + local tests=("$@") + for test_wasm in ${tests[@]}; do + test_aot="${test_wasm%.wasm}.aot" + test_json="${test_wasm%.wasm}.json" + + if [ -f ${test_wasm} ]; then + expected=$(jq .exit_code ${test_json}) + fi + + echo "Compiling $test_wasm to $test_aot" + ${WAMRC_CMD} --enable-multi-thread ${target_option} \ + -o ${test_aot} ${test_wasm} + + echo "Running $test_aot" + expected=0 + if [ -f ${test_json} ]; then + expected=$(jq .exit_code ${test_json}) + fi + + ${IWASM_CMD} $test_aot + + ret=${PIPESTATUS[0]} + + echo "expected=$expected, actual=$ret" + if [[ $expected != "" ]] && [[ $expected != $ret ]];then + 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 + 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]} + deactivate +else + target_option="" + if [[ $TARGET == "X86_32" ]];then + target_option="--target=i386" + fi + + exit_code=0 + for testsuite in ${THREAD_PROPOSAL_TESTS} ${THREAD_INTERNAL_TESTS}; do + tests=$(ls ${testsuite}*.wasm) + tests_array=($tests) + run_aot_tests "${tests_array[@]}" + done +fi + +exit ${exit_code} \ No newline at end of file diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/wamr-compiler/CMakeLists.txt b/lib/wasm-micro-runtime-WAMR-1.2.2/wamr-compiler/CMakeLists.txt similarity index 93% rename from lib/wasm-micro-runtime-WAMR-1.1.1/wamr-compiler/CMakeLists.txt rename to lib/wasm-micro-runtime-WAMR-1.2.2/wamr-compiler/CMakeLists.txt index 64bd33eab68..0ae821af651 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/wamr-compiler/CMakeLists.txt +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/wamr-compiler/CMakeLists.txt @@ -1,7 +1,9 @@ # Copyright (C) 2019 Intel Corporation. All rights reserved. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -cmake_minimum_required (VERSION 2.9) +cmake_minimum_required (VERSION 3.14) + +include(CheckPIESupported) if (NOT DEFINED WAMR_BUILD_PLATFORM) if (CMAKE_SYSTEM_NAME) @@ -42,6 +44,7 @@ add_definitions(-DWASM_ENABLE_CUSTOM_NAME_SECTION=1) add_definitions(-DWASM_ENABLE_DUMP_CALL_STACK=1) add_definitions(-DWASM_ENABLE_PERF_PROFILING=1) add_definitions(-DWASM_ENABLE_LOAD_CUSTOM_SECTION=1) +add_definitions(-DWASM_ENABLE_LIB_WASI_THREADS=1) if (WAMR_BUILD_LLVM_LEGACY_PM EQUAL 1) add_definitions(-DWASM_ENABLE_LLVM_LEGACY_PM=1) @@ -107,7 +110,9 @@ if (CMAKE_SIZEOF_VOID_P EQUAL 8) if (NOT WAMR_BUILD_PLATFORM STREQUAL "windows") # Add -fPIC flag if build as 64-bit set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC") + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") set (CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "${CMAKE_SHARED_LIBRARY_LINK_C_FLAGS} -fPIC") + set (CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "${CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS} -fPIC") endif () else () add_definitions (-m32) @@ -161,6 +166,12 @@ if (WAMR_BUILD_DEBUG_AOT EQUAL 1) message(STATUS "find lldb ${LLDB_ALL_PLUGINS} in: ${LLVM_LIBRARY_DIRS}") endif() +if ("$ENV{COLLECT_CODE_COVERAGE}" STREQUAL "1" OR COLLECT_CODE_COVERAGE EQUAL 1) + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage") + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage") + message ("-- Collect code coverage enabled") +endif () + if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang")) if(NOT MSVC) set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") @@ -200,6 +211,7 @@ if (NOT MINGW) endif() endif() include (${IWASM_DIR}/libraries/lib-pthread/lib_pthread.cmake) +include (${IWASM_DIR}/libraries/lib-wasi-threads/lib_wasi_threads.cmake) include (${IWASM_DIR}/common/iwasm_common.cmake) include (${IWASM_DIR}/interpreter/iwasm_interp.cmake) include (${IWASM_DIR}/aot/iwasm_aot.cmake) @@ -237,9 +249,6 @@ endif() if (NOT MSVC) add_definitions(-D_FORTIFY_SOURCE=2) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ftrapv") - if (NOT WIN32) - set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pie -fPIE") - endif() endif() if (WIN32) @@ -257,6 +266,7 @@ add_library (vmlib ${LIBC_BUILTIN_SOURCE} ${LIBC_WASI_SOURCE} ${LIB_PTHREAD_SOURCE} + ${LIB_WASI_THREADS_SOURCE} ${IWASM_COMMON_SOURCE} ${IWASM_INTERP_SOURCE} ${IWASM_AOT_SOURCE}) @@ -264,6 +274,8 @@ add_library (vmlib add_library (aotclib ${IWASM_COMPL_SOURCE}) add_executable (wamrc main.c) +check_pie_supported() +set_target_properties (wamrc PROPERTIES POSITION_INDEPENDENT_CODE ON) if (LLVM_LINK_LLVM_DYLIB) set(WAMRC_LINK_LLVM_LIBS LLVM) diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/wamr-compiler/README.md b/lib/wasm-micro-runtime-WAMR-1.2.2/wamr-compiler/README.md new file mode 100644 index 00000000000..b9e566af2ad --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/wamr-compiler/README.md @@ -0,0 +1,32 @@ + +### Build wamrc AOT compiler + +Both wasm binary file and AOT file are supported by iwasm. The wamrc AOT compiler is to compile wasm binary file to AOT file which can also be run by iwasm. You can execute following commands to build **wamrc** compiler: + +For **Linux**(Ubuntu 20.04 as an example): + +First, make sure necessary dependency are installed: + +```shell +sudo apt-get install git build-essential cmake g++-multilib libgcc-9-dev lib32gcc-9-dev ccache +``` + +```shell +cd wamr-compiler +./build_llvm.sh (or "./build_llvm_xtensa.sh" to support xtensa target) +mkdir build && cd build +cmake .. (or "cmake .. -DWAMR_BUILD_PLATFORM=darwin" for MacOS) +make +# wamrc is generated under current directory +``` + +For **Windows**: + +```shell +cd wamr-compiler +python build_llvm.py +mkdir build && cd build +cmake .. +cmake --build . --config Release +# wamrc.exe is generated under .\Release directory +``` diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/wamr-compiler/build_llvm.py b/lib/wasm-micro-runtime-WAMR-1.2.2/wamr-compiler/build_llvm.py similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/wamr-compiler/build_llvm.py rename to lib/wasm-micro-runtime-WAMR-1.2.2/wamr-compiler/build_llvm.py diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/wamr-compiler/build_llvm.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/wamr-compiler/build_llvm.sh similarity index 70% rename from lib/wasm-micro-runtime-WAMR-1.1.1/wamr-compiler/build_llvm.sh rename to lib/wasm-micro-runtime-WAMR-1.2.2/wamr-compiler/build_llvm.sh index 35dc35edd93..c3ec54b61b2 100755 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/wamr-compiler/build_llvm.sh +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/wamr-compiler/build_llvm.sh @@ -3,4 +3,5 @@ # Copyright (C) 2020 Intel Corporation. All rights reserved. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +/usr/bin/env python3 -m pip install --user -r ../build-scripts/requirements.txt /usr/bin/env python3 ../build-scripts/build_llvm.py "$@" diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/wamr-compiler/build_llvm_arc.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/wamr-compiler/build_llvm_arc.sh similarity index 71% rename from lib/wasm-micro-runtime-WAMR-1.1.1/wamr-compiler/build_llvm_arc.sh rename to lib/wasm-micro-runtime-WAMR-1.2.2/wamr-compiler/build_llvm_arc.sh index f8f40edd9a2..d148e11ecc1 100755 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/wamr-compiler/build_llvm_arc.sh +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/wamr-compiler/build_llvm_arc.sh @@ -3,4 +3,5 @@ # Copyright (C) 2020 Intel Corporation. All rights reserved. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +/usr/bin/env python3 -m pip install --user -r ../build-scripts/requirements.txt /usr/bin/env python3 ../build-scripts/build_llvm.py --platform arc "$@" diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/wamr-compiler/build_llvm_xtensa.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/wamr-compiler/build_llvm_xtensa.sh similarity index 72% rename from lib/wasm-micro-runtime-WAMR-1.1.1/wamr-compiler/build_llvm_xtensa.sh rename to lib/wasm-micro-runtime-WAMR-1.2.2/wamr-compiler/build_llvm_xtensa.sh index d75b62fe9fd..183ea379fd2 100755 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/wamr-compiler/build_llvm_xtensa.sh +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/wamr-compiler/build_llvm_xtensa.sh @@ -3,4 +3,5 @@ # Copyright (C) 2020 Intel Corporation. All rights reserved. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +/usr/bin/env python3 -m pip install --user -r ../build-scripts/requirements.txt /usr/bin/env python3 ../build-scripts/build_llvm.py --platform xtensa "$@" diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/wamr-compiler/main.c b/lib/wasm-micro-runtime-WAMR-1.2.2/wamr-compiler/main.c similarity index 93% rename from lib/wasm-micro-runtime-WAMR-1.1.1/wamr-compiler/main.c rename to lib/wasm-micro-runtime-WAMR-1.2.2/wamr-compiler/main.c index b77533ed3c1..bd8691c4b87 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/wamr-compiler/main.c +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/wamr-compiler/main.c @@ -37,6 +37,13 @@ print_help() printf(" by default it is disabled in all 64-bit platforms except SGX and\n"); printf(" in these platforms runtime does bounds checks with hardware trap,\n"); printf(" and by default it is enabled in all 32-bit platforms\n"); + printf(" --stack-bounds-checks=1/0 Enable or disable the bounds checks for native stack:\n"); + printf(" if the option isn't set, the status is same as `--bounds-check`,\n"); + printf(" if the option is set:\n"); + printf(" (1) it is always enabled when `--bounds-checks` is enabled,\n"); + printf(" (2) else it is enabled/disabled according to the option value\n"); + printf(" --stack-usage= Generate a stack-usage file.\n"); + printf(" Similarly to `clang -fstack-usage`.\n"); printf(" --format= Specifies the format of the output file\n"); printf(" The format supported:\n"); printf(" aot (default) AoT file\n"); @@ -54,6 +61,7 @@ print_help() printf(" --disable-aux-stack-check Disable auxiliary stack overflow/underflow check\n"); printf(" --enable-dump-call-stack Enable stack trace feature\n"); printf(" --enable-perf-profiling Enable function performance profiling\n"); + printf(" --enable-memory-profiling Enable memory usage profiling\n"); printf(" --enable-indirect-mode Enalbe call function through symbol table but not direct call\n"); printf(" --disable-llvm-intrinsics Disable the LLVM built-in intrinsics\n"); printf(" --disable-llvm-lto Disable the LLVM link time optimization\n"); @@ -139,6 +147,8 @@ main(int argc, char *argv[]) option.output_format = AOT_FORMAT_FILE; /* default value, enable or disable depends on the platform */ option.bounds_checks = 2; + /* default value, enable or disable depends on the platform */ + option.stack_bounds_checks = 2; option.enable_simd = true; option.enable_aux_stack_check = true; option.enable_bulk_memory = true; @@ -193,6 +203,12 @@ main(int argc, char *argv[]) else if (!strncmp(argv[0], "--bounds-checks=", 16)) { option.bounds_checks = (atoi(argv[0] + 16) == 1) ? 1 : 0; } + else if (!strncmp(argv[0], "--stack-bounds-checks=", 22)) { + option.stack_bounds_checks = (atoi(argv[0] + 22) == 1) ? 1 : 0; + } + else if (!strncmp(argv[0], "--stack-usage=", 14)) { + option.stack_usage_file = argv[0] + 14; + } else if (!strncmp(argv[0], "--format=", 9)) { if (argv[0][9] == '\0') PRINT_HELP_AND_EXIT(); @@ -244,6 +260,9 @@ main(int argc, char *argv[]) else if (!strcmp(argv[0], "--enable-perf-profiling")) { option.enable_aux_stack_frame = true; } + else if (!strcmp(argv[0], "--enable-memory-profiling")) { + option.enable_stack_estimation = true; + } else if (!strcmp(argv[0], "--enable-indirect-mode")) { option.is_indirect_mode = true; } diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/wamr-sdk/Kconfig b/lib/wasm-micro-runtime-WAMR-1.2.2/wamr-sdk/Kconfig similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/wamr-sdk/Kconfig rename to lib/wasm-micro-runtime-WAMR-1.2.2/wamr-sdk/Kconfig diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/wamr-sdk/Makefile b/lib/wasm-micro-runtime-WAMR-1.2.2/wamr-sdk/Makefile similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/wamr-sdk/Makefile rename to lib/wasm-micro-runtime-WAMR-1.2.2/wamr-sdk/Makefile diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/wamr-sdk/README.md b/lib/wasm-micro-runtime-WAMR-1.2.2/wamr-sdk/README.md similarity index 86% rename from lib/wasm-micro-runtime-WAMR-1.1.1/wamr-sdk/README.md rename to lib/wasm-micro-runtime-WAMR-1.2.2/wamr-sdk/README.md index c161a69a4af..14b172e0289 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/wamr-sdk/README.md +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/wamr-sdk/README.md @@ -1,5 +1,12 @@ # WebAssembly Micro Runtime SDK +Usually there are two tasks for integrating the WAMR into a particular project: + +- Select what WAMR components (vmcore, libc, app-mgr, app-framework components) to be integrated, and get the associated source files added into the project building configuration +- Generate the APP SDK for developing the WASM apps on the selected libc and framework components + +The **[WAMR SDK](./wamr-sdk)** tools is helpful to finish the two tasks quickly. It supports menu configuration for selecting WAMR components and builds the WAMR to a SDK package that includes **runtime SDK** and **APP SDK**. The runtime SDK is used for building the native application and the APP SDK should be shipped to WASM application developers. + **Note**: [WASI-SDK](https://github.com/CraneStation/wasi-sdk/releases) version 7 and above should be installed before building the WAMR SDK. diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/wamr-sdk/app/CMakeLists.txt b/lib/wasm-micro-runtime-WAMR-1.2.2/wamr-sdk/app/CMakeLists.txt similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/wamr-sdk/app/CMakeLists.txt rename to lib/wasm-micro-runtime-WAMR-1.2.2/wamr-sdk/app/CMakeLists.txt diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/wamr-sdk/app/libc-builtin-sysroot/include/assert.h b/lib/wasm-micro-runtime-WAMR-1.2.2/wamr-sdk/app/libc-builtin-sysroot/include/assert.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/wamr-sdk/app/libc-builtin-sysroot/include/assert.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/wamr-sdk/app/libc-builtin-sysroot/include/assert.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/wamr-sdk/app/libc-builtin-sysroot/include/ctype.h b/lib/wasm-micro-runtime-WAMR-1.2.2/wamr-sdk/app/libc-builtin-sysroot/include/ctype.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/wamr-sdk/app/libc-builtin-sysroot/include/ctype.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/wamr-sdk/app/libc-builtin-sysroot/include/ctype.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/wamr-sdk/app/libc-builtin-sysroot/include/errno.h b/lib/wasm-micro-runtime-WAMR-1.2.2/wamr-sdk/app/libc-builtin-sysroot/include/errno.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/wamr-sdk/app/libc-builtin-sysroot/include/errno.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/wamr-sdk/app/libc-builtin-sysroot/include/errno.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/wamr-sdk/app/libc-builtin-sysroot/include/fcntl.h b/lib/wasm-micro-runtime-WAMR-1.2.2/wamr-sdk/app/libc-builtin-sysroot/include/fcntl.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/wamr-sdk/app/libc-builtin-sysroot/include/fcntl.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/wamr-sdk/app/libc-builtin-sysroot/include/fcntl.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/wamr-sdk/app/libc-builtin-sysroot/include/inttypes.h b/lib/wasm-micro-runtime-WAMR-1.2.2/wamr-sdk/app/libc-builtin-sysroot/include/inttypes.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/wamr-sdk/app/libc-builtin-sysroot/include/inttypes.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/wamr-sdk/app/libc-builtin-sysroot/include/inttypes.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/wamr-sdk/app/libc-builtin-sysroot/include/limits.h b/lib/wasm-micro-runtime-WAMR-1.2.2/wamr-sdk/app/libc-builtin-sysroot/include/limits.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/wamr-sdk/app/libc-builtin-sysroot/include/limits.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/wamr-sdk/app/libc-builtin-sysroot/include/limits.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/wamr-sdk/app/libc-builtin-sysroot/include/pthread.h b/lib/wasm-micro-runtime-WAMR-1.2.2/wamr-sdk/app/libc-builtin-sysroot/include/pthread.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/wamr-sdk/app/libc-builtin-sysroot/include/pthread.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/wamr-sdk/app/libc-builtin-sysroot/include/pthread.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/wamr-sdk/app/libc-builtin-sysroot/include/semaphore.h b/lib/wasm-micro-runtime-WAMR-1.2.2/wamr-sdk/app/libc-builtin-sysroot/include/semaphore.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/wamr-sdk/app/libc-builtin-sysroot/include/semaphore.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/wamr-sdk/app/libc-builtin-sysroot/include/semaphore.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/wamr-sdk/app/libc-builtin-sysroot/include/stdarg.h b/lib/wasm-micro-runtime-WAMR-1.2.2/wamr-sdk/app/libc-builtin-sysroot/include/stdarg.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/wamr-sdk/app/libc-builtin-sysroot/include/stdarg.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/wamr-sdk/app/libc-builtin-sysroot/include/stdarg.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/wamr-sdk/app/libc-builtin-sysroot/include/stdbool.h b/lib/wasm-micro-runtime-WAMR-1.2.2/wamr-sdk/app/libc-builtin-sysroot/include/stdbool.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/wamr-sdk/app/libc-builtin-sysroot/include/stdbool.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/wamr-sdk/app/libc-builtin-sysroot/include/stdbool.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/wamr-sdk/app/libc-builtin-sysroot/include/stdint.h b/lib/wasm-micro-runtime-WAMR-1.2.2/wamr-sdk/app/libc-builtin-sysroot/include/stdint.h similarity index 52% rename from lib/wasm-micro-runtime-WAMR-1.1.1/wamr-sdk/app/libc-builtin-sysroot/include/stdint.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/wamr-sdk/app/libc-builtin-sysroot/include/stdint.h index 8c55bff5043..802e9ac5bfb 100644 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/wamr-sdk/app/libc-builtin-sysroot/include/stdint.h +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/wamr-sdk/app/libc-builtin-sysroot/include/stdint.h @@ -11,6 +11,13 @@ extern "C" { #endif /* clang-format off */ +/* The word size of platform */ +#ifdef __wasm64__ +#define __WORDSIZE 64 +#else +#define __WORDSIZE 32 +#endif + typedef char int8_t; typedef short int int16_t; typedef int int32_t; @@ -25,22 +32,56 @@ typedef unsigned long long int uint64_t; typedef __INTPTR_TYPE__ intptr_t; typedef __UINTPTR_TYPE__ uintptr_t; +/* Signed and unsigned */ +#if __WORDSIZE == 64 +#define INT64_C(c) c ## L +#define UINT64_C(c) c ## UL +#define INTMAX_C(c) c ## L +#define UINTMAX_C(c) c ## UL +#else +#define INT64_C(c) c ## LL +#define UINT64_C(c) c ## ULL +#define INTMAX_C(c) c ## LL +#define UINTMAX_C(c) c ## ULL +#endif + + /* Minimum of signed integral types. */ # define INT8_MIN (-128) # define INT16_MIN (-32767-1) # define INT32_MIN (-2147483647-1) -# define INT64_MIN (-__INT64_C(9223372036854775807)-1) +# define INT64_MIN (-INT64_C(9223372036854775807)-1) + /* Maximum of signed integral types. */ # define INT8_MAX (127) # define INT16_MAX (32767) # define INT32_MAX (2147483647) -# define INT64_MAX (__INT64_C(9223372036854775807)) +# define INT64_MAX (INT64_C(9223372036854775807)) /* Maximum of unsigned integral types. */ # define UINT8_MAX (255) # define UINT16_MAX (65535) # define UINT32_MAX (4294967295U) -# define UINT64_MAX (__UINT64_C(18446744073709551615)) +# define UINT64_MAX (UINT64_C(18446744073709551615)) + +/* Values to test for integral types holding `void *' pointer. */ +#if __WORDSIZE == 64 +#define INTPTR_MIN INT64_MIN +#define INTPTR_MAX INT64_MAX +#define UINTPTR_MAX UINT64_MAX +#else +#define INTPTR_MIN INT32_MIN +#define INTPTR_MAX INT32_MAX +#define UINTPTR_MAX UINT32_MAX +#endif + +/* Limit of `size_t' type. */ +#if __WORDSIZE == 64 +#define SIZE_MAX UINT64_MAX +#else +#define SIZE_MAX UINT32_MAX +#endif + /* clang-format on */ #ifdef __cplusplus diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/wamr-sdk/app/libc-builtin-sysroot/include/stdio.h b/lib/wasm-micro-runtime-WAMR-1.2.2/wamr-sdk/app/libc-builtin-sysroot/include/stdio.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/wamr-sdk/app/libc-builtin-sysroot/include/stdio.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/wamr-sdk/app/libc-builtin-sysroot/include/stdio.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/wamr-sdk/app/libc-builtin-sysroot/include/stdlib.h b/lib/wasm-micro-runtime-WAMR-1.2.2/wamr-sdk/app/libc-builtin-sysroot/include/stdlib.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/wamr-sdk/app/libc-builtin-sysroot/include/stdlib.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/wamr-sdk/app/libc-builtin-sysroot/include/stdlib.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/wamr-sdk/app/libc-builtin-sysroot/include/string.h b/lib/wasm-micro-runtime-WAMR-1.2.2/wamr-sdk/app/libc-builtin-sysroot/include/string.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/wamr-sdk/app/libc-builtin-sysroot/include/string.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/wamr-sdk/app/libc-builtin-sysroot/include/string.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/wamr-sdk/app/libc-builtin-sysroot/include/strings.h b/lib/wasm-micro-runtime-WAMR-1.2.2/wamr-sdk/app/libc-builtin-sysroot/include/strings.h similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/wamr-sdk/app/libc-builtin-sysroot/include/strings.h rename to lib/wasm-micro-runtime-WAMR-1.2.2/wamr-sdk/app/libc-builtin-sysroot/include/strings.h diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/wamr-sdk/app/libc-builtin-sysroot/share/defined-symbols.txt b/lib/wasm-micro-runtime-WAMR-1.2.2/wamr-sdk/app/libc-builtin-sysroot/share/defined-symbols.txt similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/wamr-sdk/app/libc-builtin-sysroot/share/defined-symbols.txt rename to lib/wasm-micro-runtime-WAMR-1.2.2/wamr-sdk/app/libc-builtin-sysroot/share/defined-symbols.txt diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/wamr-sdk/app/wamr_toolchain.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/wamr-sdk/app/wamr_toolchain.cmake similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/wamr-sdk/app/wamr_toolchain.cmake rename to lib/wasm-micro-runtime-WAMR-1.2.2/wamr-sdk/app/wamr_toolchain.cmake diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/wamr-sdk/app/wasi_toolchain.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/wamr-sdk/app/wasi_toolchain.cmake similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/wamr-sdk/app/wasi_toolchain.cmake rename to lib/wasm-micro-runtime-WAMR-1.2.2/wamr-sdk/app/wasi_toolchain.cmake diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/wamr-sdk/build_sdk.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/wamr-sdk/build_sdk.sh similarity index 98% rename from lib/wasm-micro-runtime-WAMR-1.1.1/wamr-sdk/build_sdk.sh rename to lib/wasm-micro-runtime-WAMR-1.2.2/wamr-sdk/build_sdk.sh index 53856e9c332..954584f690b 100755 --- a/lib/wasm-micro-runtime-WAMR-1.1.1/wamr-sdk/build_sdk.sh +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/wamr-sdk/build_sdk.sh @@ -224,8 +224,8 @@ echo -e "\n\n" echo "############## Start to build runtime sdk ###############" cd ${sdk_root}/runtime -rm -fr build_runtime_sdk && mkdir build_runtime_sdk -cd build_runtime_sdk +rm -fr build-runtime-sdk && mkdir build-runtime-sdk +cd build-runtime-sdk cmake .. $CM_DEXTRA_SDK_INCLUDE_PATH \ -DWAMR_BUILD_SDK_PROFILE=${PROFILE} \ -DCONFIG_PATH=${wamr_config_cmake_file} \ @@ -249,6 +249,6 @@ fi cd .. -rm -fr build_runtime_sdk +rm -fr build-runtime-sdk exit 0 diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/wamr-sdk/menuconfig.sh b/lib/wasm-micro-runtime-WAMR-1.2.2/wamr-sdk/menuconfig.sh similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/wamr-sdk/menuconfig.sh rename to lib/wasm-micro-runtime-WAMR-1.2.2/wamr-sdk/menuconfig.sh diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/wamr-sdk/runtime/CMakeLists.txt b/lib/wasm-micro-runtime-WAMR-1.2.2/wamr-sdk/runtime/CMakeLists.txt similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/wamr-sdk/runtime/CMakeLists.txt rename to lib/wasm-micro-runtime-WAMR-1.2.2/wamr-sdk/runtime/CMakeLists.txt diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/wamr-sdk/wamr_config_default.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/wamr-sdk/wamr_config_default.cmake similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/wamr-sdk/wamr_config_default.cmake rename to lib/wasm-micro-runtime-WAMR-1.2.2/wamr-sdk/wamr_config_default.cmake diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/wamr-sdk/wamr_config_macos_release.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/wamr-sdk/wamr_config_macos_release.cmake new file mode 100644 index 00000000000..cbcec2d6f33 --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/wamr-sdk/wamr_config_macos_release.cmake @@ -0,0 +1,40 @@ +set (WAMR_BUILD_PLATFORM "darwin") +set (WAMR_BUILD_TARGET X86_64) + +# Running mode +set (WAMR_BUILD_AOT 1) +set (WAMR_BUILD_INTERP 1) +set (WAMR_BUILD_JIT 0) + +# Runtime SDK Features +set (WAMR_BUILD_CUSTOM_NAME_SECTION 0) +set (WAMR_BUILD_DEBUG_INTERP 0) +set (WAMR_BUILD_DEBUG_AOT 0) +set (WAMR_BUILD_DUMP_CALL_STACK 0) +set (WAMR_BUILD_LIBC_UVWASI 0) +set (WAMR_BUILD_LIBC_EMCC 0) +set (WAMR_BUILD_LIB_RATS 0) +set (WAMR_BUILD_LOAD_CUSTOM_SECTION 0) +set (WAMR_BUILD_MEMORY_PROFILING 0) +set (WAMR_BUILD_MINI_LOADER 0) +set (WAMR_BUILD_MULTI_MODULE 0) +set (WAMR_BUILD_PERF_PROFILING 0) +set (WAMR_BUILD_SPEC_TEST 0) +set (WAMR_BUILD_BULK_MEMORY 1) +set (WAMR_BUILD_LIB_PTHREAD 1) +set (WAMR_BUILD_LIB_PTHREAD_SEMAPHORE 1) +set (WAMR_BUILD_LIBC_BUILTIN 1) +set (WAMR_BUILD_LIBC_WASI 1) +set (WAMR_BUILD_REF_TYPES 1) +set (WAMR_BUILD_SIMD 1) +set (WAMR_BUILD_SHARED_MEMORY 1) +set (WAMR_BUILD_TAIL_CALL 1) +set (WAMR_BUILD_THREAD_MGR 1) + +# APP SDK Features +set (WAMR_BUILD_APP_FRAMEWORK 1) +set (WAMR_BUILD_APP_LIST WAMR_APP_BUILD_BASE) + +# +# set (EXTRA_SDK_INCLUDE_PATH "") + diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/wamr-sdk/wamr_config_ubuntu_release.cmake b/lib/wasm-micro-runtime-WAMR-1.2.2/wamr-sdk/wamr_config_ubuntu_release.cmake new file mode 100644 index 00000000000..8919c4e414a --- /dev/null +++ b/lib/wasm-micro-runtime-WAMR-1.2.2/wamr-sdk/wamr_config_ubuntu_release.cmake @@ -0,0 +1,40 @@ +set (WAMR_BUILD_PLATFORM "linux") +set (WAMR_BUILD_TARGET X86_64) + +# Running mode +set (WAMR_BUILD_AOT 1) +set (WAMR_BUILD_INTERP 1) +set (WAMR_BUILD_JIT 0) + +# Runtime SDK Features +set (WAMR_BUILD_CUSTOM_NAME_SECTION 0) +set (WAMR_BUILD_DEBUG_INTERP 0) +set (WAMR_BUILD_DEBUG_AOT 0) +set (WAMR_BUILD_DUMP_CALL_STACK 0) +set (WAMR_BUILD_LIBC_UVWASI 0) +set (WAMR_BUILD_LIBC_EMCC 0) +set (WAMR_BUILD_LIB_RATS 0) +set (WAMR_BUILD_LOAD_CUSTOM_SECTION 0) +set (WAMR_BUILD_MEMORY_PROFILING 0) +set (WAMR_BUILD_MINI_LOADER 0) +set (WAMR_BUILD_MULTI_MODULE 0) +set (WAMR_BUILD_PERF_PROFILING 0) +set (WAMR_BUILD_SPEC_TEST 0) +set (WAMR_BUILD_BULK_MEMORY 1) +set (WAMR_BUILD_LIB_PTHREAD 1) +set (WAMR_BUILD_LIB_PTHREAD_SEMAPHORE 1) +set (WAMR_BUILD_LIBC_BUILTIN 1) +set (WAMR_BUILD_LIBC_WASI 1) +set (WAMR_BUILD_REF_TYPES 1) +set (WAMR_BUILD_SIMD 1) +set (WAMR_BUILD_SHARED_MEMORY 1) +set (WAMR_BUILD_TAIL_CALL 1) +set (WAMR_BUILD_THREAD_MGR 1) + +# APP SDK Features +set (WAMR_BUILD_APP_FRAMEWORK 1) +set (WAMR_BUILD_APP_LIST WAMR_APP_BUILD_BASE) + +# +# set (EXTRA_SDK_INCLUDE_PATH "") + diff --git a/lib/wasm-micro-runtime-WAMR-1.1.1/zephyr/module.yml b/lib/wasm-micro-runtime-WAMR-1.2.2/zephyr/module.yml similarity index 100% rename from lib/wasm-micro-runtime-WAMR-1.1.1/zephyr/module.yml rename to lib/wasm-micro-runtime-WAMR-1.2.2/zephyr/module.yml From b2ac44453afab64951c02ec65c178d7758cc0f40 Mon Sep 17 00:00:00 2001 From: Hiroshi Hatake Date: Fri, 16 Jun 2023 19:30:46 +0900 Subject: [PATCH 055/315] lib: wamr: Remove hadolint warned dockerfiles Signed-off-by: Hiroshi Hatake --- .../.devcontainer/Dockerfile | 133 ------------------ .../libraries/wasi-nn/test/Dockerfile.compile | 23 --- .../libraries/wasi-nn/test/Dockerfile.cpu | 27 ---- .../wasi-nn/test/Dockerfile.nvidia-gpu | 40 ------ .../wasi-nn/test/Dockerfile.vx-delegate | 99 ------------- 5 files changed, 322 deletions(-) delete mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/.devcontainer/Dockerfile delete mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/Dockerfile.compile delete mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/Dockerfile.cpu delete mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/Dockerfile.nvidia-gpu delete mode 100644 lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/Dockerfile.vx-delegate diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/.devcontainer/Dockerfile b/lib/wasm-micro-runtime-WAMR-1.2.2/.devcontainer/Dockerfile deleted file mode 100644 index 7ccfa2467f6..00000000000 --- a/lib/wasm-micro-runtime-WAMR-1.2.2/.devcontainer/Dockerfile +++ /dev/null @@ -1,133 +0,0 @@ -# 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} - -ARG DEBIAN_FRONTEND=noninteractive -ENV TZ=Asian/Shanghai - -# hadolint ignore=DL3008 -RUN apt-get update \ - && 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 \ - software-properties-common tree tzdata \ - unzip valgrind vim wget zip --no-install-recommends \ - && apt-get clean -y \ - && rm -rf /var/lib/apt/lists/* - -# -# binaryen -ARG BINARYEN_VER=111 -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 \ - && 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/* - -# -# install emsdk -WORKDIR /opt -RUN git clone https://github.com/emscripten-core/emsdk.git - -ARG EMSDK_VER=3.0.0 -WORKDIR /opt/emsdk -RUN git pull \ - && ./emsdk install ${EMSDK_VER} \ - && ./emsdk activate ${EMSDK_VER} \ - && echo "source /opt/emsdk/emsdk_env.sh" >> /root/.bashrc - -# -# install wasi-sdk -ARG WASI_SDK_VER=19 -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 \ - && rm /opt/wasi-sdk-${WASI_SDK_VER}.0-linux.tar.gz - -# -#install wabt -ARG WABT_VER=1.0.29 -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 \ - && rm /opt/wabt-${WABT_VER}-ubuntu.tar.gz - -# -# install bazelisk -ARG BAZELISK_VER=1.12.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 \ - && ln -fs /opt/bazelisk/bazelisk-linux-amd64 /opt/bazelisk/bazel - -# -# install clang+llvm -ARG LLVM_VER=14 -RUN apt-get purge -y clang-10 llvm-10 && apt 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 - -# -# [Optional] - -# -# Install pip -# hadolint ignore=DL3008 -RUN apt-get update \ - && apt-get install -y --reinstall python3-venv python3-pip --no-install-recommends \ - && apt-get clean -y \ - && rm -rf /var/lib/apt/lists/* - -# -# 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 - -# -# Install github-cli. It doens't work as a feature of devcontainer.json -RUN cd /tmp \ - && wget 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 - -# -# Install NodeJS -RUN curl -fsSL https://deb.nodesource.com/setup_19.x | bash - -RUN apt-get install -y nodejs - -# set path -ENV PATH="/opt/bazelisk:/usr/lib/llvm-${LLVM_VER}/bin:${PATH}" -ENV CC=/usr/lib/llvm-${LLVM_VER}/bin/clang CXX=/usr/lib/llvm-${LLVM_VER}/bin/clang++ -RUN printf "%s\n" "PS1='\n[ \u@wamr-dev-docker \W ]\n$ '" >> /root/.bashrc \ - && apt-get autoremove -y \ - && apt-get clean -y \ - && rm -rf /var/lib/apt/lists/* \ - && rm -rf /tmp/* - -# set workdir when container run -VOLUME /workspaces -WORKDIR /workspaces diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/Dockerfile.compile b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/Dockerfile.compile deleted file mode 100644 index 51a59707b8d..00000000000 --- a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/Dockerfile.compile +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright (C) 2019 Intel Corporation. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -FROM ubuntu:20.04 - -ENV DEBIAN_FRONTEND=noninteractive - -RUN apt-get update && apt-get install -y \ - cmake build-essential git wget python3.10 python3-pip - -ARG WASI_SDK_VER=19 -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 -fs /opt/wasi-sdk-${WASI_SDK_VER}.0 /opt/wasi-sdk \ - && rm /opt/wasi-sdk-${WASI_SDK_VER}.0-linux.tar.gz - -WORKDIR /wasi-nn/test - -COPY core/iwasm/libraries/wasi-nn/test/requirements.txt . - -RUN pip3 install -r requirements.txt && rm requirements.txt - -ENTRYPOINT [ "bash", "./build.sh" ] diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/Dockerfile.cpu b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/Dockerfile.cpu deleted file mode 100644 index 532a53365b7..00000000000 --- a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/Dockerfile.cpu +++ /dev/null @@ -1,27 +0,0 @@ -# Copyright (C) 2019 Intel Corporation. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -FROM ubuntu:20.04 AS base - -ENV DEBIAN_FRONTEND=noninteractive - -RUN apt-get update && apt-get install -y \ - cmake build-essential git - -WORKDIR /home/wamr - -COPY . . - -WORKDIR /home/wamr/core/iwasm/libraries/wasi-nn/test/build - -RUN cmake \ - -DWAMR_BUILD_WASI_NN=1 \ - .. - -RUN make -j $(grep -c ^processor /proc/cpuinfo) - -FROM ubuntu:22.04 - -COPY --from=base /home/wamr/core/iwasm/libraries/wasi-nn/test/build/iwasm /run/iwasm - -ENTRYPOINT [ "/run/iwasm" ] diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/Dockerfile.nvidia-gpu b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/Dockerfile.nvidia-gpu deleted file mode 100644 index 44963bd6388..00000000000 --- a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/Dockerfile.nvidia-gpu +++ /dev/null @@ -1,40 +0,0 @@ -# Copyright (C) 2019 Intel Corporation. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -FROM ubuntu:20.04 AS base - -ENV DEBIAN_FRONTEND=noninteractive - -RUN apt-get update && apt-get install -y \ - cmake build-essential git - -WORKDIR /home/wamr - -COPY . . - -WORKDIR /home/wamr/core/iwasm/libraries/wasi-nn/test/build - -RUN cmake \ - -DWAMR_BUILD_WASI_NN=1 \ - -DWASI_NN_ENABLE_GPU=1 \ - .. - -RUN make -j $(grep -c ^processor /proc/cpuinfo) - -FROM nvidia/cuda:11.3.0-runtime-ubuntu20.04 - -RUN apt-get update && apt-get install -y --no-install-recommends \ - ocl-icd-libopencl1 \ - ocl-icd-opencl-dev \ - clinfo && \ - rm -rf /var/lib/apt/lists/* - -RUN mkdir -p /etc/OpenCL/vendors && \ - echo "libnvidia-opencl.so.1" > /etc/OpenCL/vendors/nvidia.icd - -ENV NVIDIA_VISIBLE_DEVICES=all -ENV NVIDIA_DRIVER_CAPABILITIES=compute,utility - -COPY --from=base /home/wamr/core/iwasm/libraries/wasi-nn/test/build/iwasm /run/iwasm - -ENTRYPOINT [ "/run/iwasm" ] diff --git a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/Dockerfile.vx-delegate b/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/Dockerfile.vx-delegate deleted file mode 100644 index 89cc1a9dea0..00000000000 --- a/lib/wasm-micro-runtime-WAMR-1.2.2/core/iwasm/libraries/wasi-nn/test/Dockerfile.vx-delegate +++ /dev/null @@ -1,99 +0,0 @@ -# Copyright (C) 2019 Intel Corporation. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -FROM ubuntu:20.04 AS base - -ENV DEBIAN_FRONTEND=noninteractive - - -RUN apt-get update && apt-get install -y \ - cmake build-essential git curl libssl-dev python3 - - -# Build TensorFlow Lite VX delegate default built for x86-64 simulator -WORKDIR /tmp -RUN git clone https://github.com/VeriSilicon/TIM-VX.git tim-vx -RUN git clone https://github.com/VeriSilicon/tflite-vx-delegate.git -RUN git clone https://github.com/tensorflow/tensorflow.git - - -# Build TIM-VX -WORKDIR /tmp/tim-vx/host_build -RUN cmake -DCMAKE_INSTALL_PREFIX=/usr/local ../ -RUN make -j$(grep -c ^processor /proc/cpuinfo) -RUN make install - -WORKDIR /tmp/tim-vx -#RUN mkdir -p prebuilt-sdk/x86_64_linux/lib/include -#RUN cp prebuilt-sdk/x86_64_linux/include/CL prebuilt-sdk/x86_64_linux/lib/include -fr - - -# Build TensorFlow Lite -WORKDIR /tmp/tensorflow/build -RUN cmake \ - -DBUILD_SHARED_LIBS=ON=on \ - -DTFLITE_ENABLE_RUY=on \ - -DTFLITE_ENABLE_NNAPI=off \ - -DTFLITE_ENABLE_XNNPACK=on \ - -DTFLITE_ENABLE_EXTERNAL_DELEGATE=on \ - ../tensorflow/lite/ -RUN make -j$(grep -c ^processor /proc/cpuinfo) -RUN make install -RUN cp --no-preserve=ownership -d lib*.so* /usr/local/lib -RUN cp -r --no-preserve=ownership -d flatbuffers/include/flatbuffers /usr/local/include -# install header files -RUN install -d /usr/local/include/tensorflow/lite && \ - cd /tmp/tensorflow/tensorflow/lite && \ - cp --parents \ - $(find . -name "*.h*") \ - /usr/local/include/tensorflow/lite -# install version.h from core -RUN install -d /usr/local/include/tensorflow/core/public && \ - cp /tmp/tensorflow/tensorflow/core/public/version.h /usr/local/include/tensorflow/core/public - - -# Build Vx Delegate default built for x86-64 simulator -WORKDIR /tmp/tflite-vx-delegate/build -RUN cmake \ - -DBUILD_SHARED_LIBS=ON \ - -DFETCHCONTENT_SOURCE_DIR_TENSORFLOW=/tmp/tensorflow \ - -DTFLITE_LIB_LOC=/usr/local/lib/libtensorflow-lite.so \ - -DTIM_VX_INSTALL=/usr/local \ - -DCMAKE_INSTALL_PREFIX=/usr/ \ - ../ -RUN make vx_delegate -j$(grep -c ^processor /proc/cpuinfo) -RUN make install -RUN cp --no-preserve=ownership -d lib*.so* /usr/lib -# install header files -RUN install -d /usr/local/include/tensorflow-lite-vx-delegate && \ - cd /tmp/tflite-vx-delegate/ && \ - cp --parents \ - $(find . -name "*.h*") \ - /usr/local/include/tensorflow-lite-vx-delegate - -ENV VIVANTE_SDK_DIR=/tmp/tim-vx/prebuilt-sdk/x86_64_linux/ -ENV VSIMULATOR_CONFIG=czl - -ENV LD_LIBRARY_PATH=/tmp/tim-vx/prebuilt-sdk/x86_64_linux/lib:/usr/local/lib:/lib/x86_64-linux-gnu/:/lib64/:/usr/lib:$LD_LIBRARY_PATH - - -# Build WASI-NN -WORKDIR /home/wamr - -COPY . . - -WORKDIR /home/wamr/core/iwasm/libraries/wasi-nn/test/build - -RUN cmake \ - -DCMAKE_LIBRARY_PATH=${CMAKE_LIBRARY_PATH}:/usr/local/lib/ \ - -DCMAKE_INCLUDE_PATH=${CMAKE_INCLUDE_PATH}:/usr/local/include/ \ - -DWAMR_BUILD_WASI_NN=1 \ - -DWAMR_BUILD_WASI_NN_ENABLE_EXT=1 \ - -DWASI_NN_EXT_DELEGATE_PATH="/usr/lib/libvx_delegate.so" \ - .. - -RUN make -j $(grep -c ^processor /proc/cpuinfo) - -RUN cp /home/wamr/core/iwasm/libraries/wasi-nn/test/build/iwasm /run/iwasm - -ENTRYPOINT [ "/run/iwasm" ] From de15776e4b5c48d3379e27b87870475d895457c0 Mon Sep 17 00:00:00 2001 From: Hiroshi Hatake Date: Mon, 19 Jun 2023 14:37:43 +0900 Subject: [PATCH 056/315] build: Permit to build WAMR on FreeBSD Signed-off-by: Hiroshi Hatake --- CMakeLists.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ed4bac08bb8..67f42cef059 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -84,8 +84,9 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD") set(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} -lutil") endif() -# *BSD is not supported platform for wasm-micro-runtime. Now, we should be disabled for these platforms. -if(${CMAKE_SYSTEM_NAME} MATCHES "BSD") +# *BSD is not supported platform for wasm-micro-runtime except for FreeBSD. +# Now, we should be disabled for these platforms. +if(NOT FLB_SYSTEM_FREEBSD AND ${CMAKE_SYSTEM_NAME} MATCHES "BSD") message(STATUS "This platform is not supported for WASM feature so disabled.") set(FLB_WASM OFF) endif() From 82c8e74c731b4305a52124837ec28cd400cb12fc Mon Sep 17 00:00:00 2001 From: Hiroshi Hatake Date: Mon, 19 Jun 2023 15:09:07 +0900 Subject: [PATCH 057/315] build: flb-wamrc: Build flb-wamrc with LLVM 13.0 or later Signed-off-by: Hiroshi Hatake --- src/wamrc/CMakeLists.txt | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/wamrc/CMakeLists.txt b/src/wamrc/CMakeLists.txt index fd450a38fbb..f8de6449fc8 100644 --- a/src/wamrc/CMakeLists.txt +++ b/src/wamrc/CMakeLists.txt @@ -123,6 +123,14 @@ else() endif() find_package(LLVM CONFIG) +if (LLVM_FOUND) + if (LLVM_PACKAGE_VERSION VERSION_LESS 13.0) + message(STATUS "Outdated LLVM ${LLVM_PACKAGE_VERSION} is found. WAMRC won't be built.") + set(LLVM_FOUND 0) + endif() +else() + message(STATUS "LLVM is not found. WAMRC won't be built.") +endif() if (LLVM_FOUND) include_directories(${LLVM_INCLUDE_DIRS}) add_definitions(${LLVM_DEFINITIONS}) @@ -199,6 +207,4 @@ if (LLVM_FOUND) install(FILES $ DESTINATION "${FLB_INSTALL_BINDIR}") endif() -else() - message(STATUS "LLVM is not found. WAMRC won't be built.") endif () \ No newline at end of file From f8296f2a1dd0ca1d9425dbaef9b1b20802b65161 Mon Sep 17 00:00:00 2001 From: Hiroshi Hatake Date: Mon, 19 Jun 2023 15:44:14 +0900 Subject: [PATCH 058/315] build: freebsd: Add recommended default value for WAMR Signed-off-by: Hiroshi Hatake --- CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 67f42cef059..6672ad01206 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -89,6 +89,9 @@ endif() if(NOT FLB_SYSTEM_FREEBSD AND ${CMAKE_SYSTEM_NAME} MATCHES "BSD") message(STATUS "This platform is not supported for WASM feature so disabled.") set(FLB_WASM OFF) +elseif(FLB_SYSTEM_FREEBSD) + message(STATUS "Some of FreeBSD environment do not work with hardware boundary check so disabled.") + set(WAMR_DISABLE_STACK_HW_BOUND_CHECK 1) endif() include(GNUInstallDirs) From 81a04c136157c646674f97af0afbafcda38398bb Mon Sep 17 00:00:00 2001 From: Hiroshi Hatake Date: Tue, 20 Jun 2023 17:41:25 +0900 Subject: [PATCH 059/315] in_windows_exporter_metrics: Implement Windows Service metrics Signed-off-by: Hiroshi Hatake --- .../CMakeLists.txt | 1 + plugins/in_windows_exporter_metrics/we.c | 75 +++++- plugins/in_windows_exporter_metrics/we.h | 14 +- plugins/in_windows_exporter_metrics/we_wmi.c | 39 ++- plugins/in_windows_exporter_metrics/we_wmi.h | 3 + .../we_wmi_cpu_info.c | 1 + .../we_wmi_logon.c | 1 + .../we_wmi_service.c | 224 ++++++++++++++++++ .../we_wmi_service.h | 29 +++ .../we_wmi_system.c | 1 + .../we_wmi_thermalzone.c | 3 + 11 files changed, 388 insertions(+), 3 deletions(-) create mode 100644 plugins/in_windows_exporter_metrics/we_wmi_service.c create mode 100644 plugins/in_windows_exporter_metrics/we_wmi_service.h diff --git a/plugins/in_windows_exporter_metrics/CMakeLists.txt b/plugins/in_windows_exporter_metrics/CMakeLists.txt index 92472a9adc0..8b20fa9bd55 100644 --- a/plugins/in_windows_exporter_metrics/CMakeLists.txt +++ b/plugins/in_windows_exporter_metrics/CMakeLists.txt @@ -14,6 +14,7 @@ set(src we_wmi_cpu_info.c we_wmi_logon.c we_wmi_system.c + we_wmi_service.c ) set(libs diff --git a/plugins/in_windows_exporter_metrics/we.c b/plugins/in_windows_exporter_metrics/we.c index 604d2c1e2ef..5a010485b95 100644 --- a/plugins/in_windows_exporter_metrics/we.c +++ b/plugins/in_windows_exporter_metrics/we.c @@ -35,6 +35,13 @@ #include "we_logical_disk.h" #include "we_cs.h" +/* wmi collectors */ +#include "we_wmi_cpu_info.h" +#include "we_wmi_logon.h" +#include "we_wmi_system.h" +#include "we_wmi_thermalzone.h" +#include "we_wmi_service.h" + static int we_timer_cpu_metrics_cb(struct flb_input_instance *ins, struct flb_config *config, void *in_context) { @@ -125,6 +132,16 @@ static int we_timer_wmi_system_metrics_cb(struct flb_input_instance *ins, return 0; } +static int we_timer_wmi_service_metrics_cb(struct flb_input_instance *ins, + struct flb_config *config, void *in_context) +{ + struct flb_ne *ctx = in_context; + + we_wmi_service_update(ctx); + + return 0; +} + struct flb_we_callback { char *name; void (*func)(char *, void *, void *); @@ -240,6 +257,13 @@ static void we_wmi_system_update_cb(char *name, void *p1, void *p2) we_wmi_system_update(ctx); } +static void we_wmi_service_update_cb(char *name, void *p1, void *p2) +{ + struct flb_we *ctx = p1; + + we_wmi_service_update(ctx); +} + static int we_update_cb(struct flb_we *ctx, char *name) { int ret; @@ -262,6 +286,7 @@ struct flb_we_callback ne_callbacks[] = { { "thermalzone", we_wmi_thermalzone_update_cb }, { "logon", we_wmi_logon_update_cb }, { "system", we_wmi_system_update_cb }, + { "service", we_wmi_service_update_cb }, { 0 } }; @@ -295,6 +320,7 @@ static int in_we_init(struct flb_input_instance *in, ctx->coll_wmi_cpu_info_fd = -1; ctx->coll_wmi_logon_fd = -1; ctx->coll_wmi_system_fd = -1; + ctx->coll_wmi_service_fd = -1; ctx->callback = flb_callback_create(in->name); if (!ctx->callback) { @@ -574,6 +600,31 @@ static int in_we_init(struct flb_input_instance *in, return -1; } } + else if (strncmp(entry->str, "service", 7) == 0) { + if (ctx->wmi_service_scrape_interval == 0) { + flb_plg_debug(ctx->ins, "enabled metrics %s", entry->str); + metric_idx = 9; + } + else { + /* Create the service collector */ + ret = flb_input_set_collector_time(in, + we_timer_wmi_service_metrics_cb, + ctx->wmi_service_scrape_interval, 0, + config); + if (ret == -1) { + flb_plg_error(ctx->ins, + "could not set service collector for Windows Exporter Metrics plugin"); + return -1; + } + ctx->coll_wmi_service_fd = ret; + } + + /* Initialize service metric collectors */ + ret = we_wmi_service_init(ctx); + if (ret) { + return -1; + } + } else { flb_plg_warn(ctx->ins, "Unknown metrics: %s", entry->str); metric_idx = -1; @@ -644,6 +695,9 @@ static int in_we_exit(void *data, struct flb_config *config) else if (strncmp(entry->str, "system", 6) == 0) { we_wmi_system_exit(ctx); } + else if (strncmp(entry->str, "service", 7) == 0) { + we_wmi_service_exit(ctx); + } else { flb_plg_warn(ctx->ins, "Unknown metrics: %s", entry->str); } @@ -681,6 +735,9 @@ static int in_we_exit(void *data, struct flb_config *config) if (ctx->coll_wmi_system_fd != -1) { we_wmi_system_exit(ctx); } + if (ctx->coll_wmi_service_fd != -1) { + we_wmi_service_exit(ctx); + } flb_we_config_destroy(ctx); @@ -721,6 +778,9 @@ static void in_we_pause(void *data, struct flb_config *config) if (ctx->coll_wmi_system_fd != -1) { flb_input_collector_pause(ctx->coll_wmi_system_fd, ctx->ins); } + if (ctx->coll_wmi_service_fd != -1) { + flb_input_collector_pause(ctx->coll_wmi_service_fd, ctx->ins); + } } static void in_we_resume(void *data, struct flb_config *config) @@ -757,6 +817,9 @@ static void in_we_resume(void *data, struct flb_config *config) if (ctx->coll_wmi_system_fd != -1) { flb_input_collector_resume(ctx->coll_wmi_system_fd, ctx->ins); } + if (ctx->coll_wmi_service_fd != -1) { + flb_input_collector_resume(ctx->coll_wmi_service_fd, ctx->ins); + } } /* Configuration properties map */ @@ -822,9 +885,14 @@ static struct flb_config_map config_map[] = { 0, FLB_TRUE, offsetof(struct flb_we, wmi_system_scrape_interval), "scrape interval to collect system metrics from the node." }, + { + FLB_CONFIG_MAP_TIME, "collector.service.scrape_interval", "0", + 0, FLB_TRUE, offsetof(struct flb_we, wmi_service_scrape_interval), + "scrape interval to collect service metrics from the node." + }, { FLB_CONFIG_MAP_CLIST, "metrics", - "cpu,cpu_info,os,net,logical_disk,cs,thermalzone,logon,system", + "cpu,cpu_info,os,net,logical_disk,cs,thermalzone,logon,system,service", 0, FLB_TRUE, offsetof(struct flb_we, metrics), "Comma separated list of keys to enable metrics." }, @@ -843,6 +911,11 @@ static struct flb_config_map config_map[] = { 0, FLB_TRUE, offsetof(struct flb_we, raw_allowing_nic), "Specify to be scribable regex for net metrics by name of NIC." }, + { + FLB_CONFIG_MAP_STR, "we.service.where", NULL, + 0, FLB_TRUE, offsetof(struct flb_we, raw_where_clause), + "Specify the where clause for retrieving service metrics." + }, /* EOF */ {0} }; diff --git a/plugins/in_windows_exporter_metrics/we.h b/plugins/in_windows_exporter_metrics/we.h index 0432c0807ec..2bbf6cdebe7 100644 --- a/plugins/in_windows_exporter_metrics/we.h +++ b/plugins/in_windows_exporter_metrics/we.h @@ -145,6 +145,15 @@ struct we_wmi_system_counters { int operational; }; +struct we_wmi_service_counters { + struct wmi_query_spec *info; + struct cmt_gauge *information; + struct cmt_gauge *state; + struct cmt_gauge *start_mode; + struct cmt_gauge *status; + int operational; +}; + struct we_os_counters { struct cmt_gauge *info; struct cmt_gauge *users; @@ -178,6 +187,7 @@ struct flb_we { char *raw_allowing_disk; char *raw_denying_disk; char *raw_allowing_nic; + char *raw_where_clause; struct flb_regex *allowing_disk_regex; struct flb_regex *denying_disk_regex; @@ -203,6 +213,7 @@ struct flb_we { int wmi_cpu_info_scrape_interval; int wmi_logon_scrape_interval; int wmi_system_scrape_interval; + int wmi_service_scrape_interval; int coll_cpu_fd; /* collector fd (cpu) */ int coll_net_fd; /* collector fd (net) */ @@ -213,6 +224,7 @@ struct flb_we { int coll_wmi_cpu_info_fd; /* collector fd (wmi_cpu_info) */ int coll_wmi_logon_fd; /* collector fd (wmi_logon) */ int coll_wmi_system_fd; /* collector fd (wmi_system) */ + int coll_wmi_service_fd; /* collector fd (wmi_service) */ /* * Metrics Contexts @@ -228,7 +240,7 @@ struct flb_we { struct we_wmi_cpu_info_counters *wmi_cpu_info; struct we_wmi_logon_counters *wmi_logon; struct we_wmi_system_counters *wmi_system; - + struct we_wmi_service_counters *wmi_service; }; typedef int (*collector_cb)(struct flb_we *); diff --git a/plugins/in_windows_exporter_metrics/we_wmi.c b/plugins/in_windows_exporter_metrics/we_wmi.c index 0392c798d32..be93653ae9d 100644 --- a/plugins/in_windows_exporter_metrics/we_wmi.c +++ b/plugins/in_windows_exporter_metrics/we_wmi.c @@ -231,6 +231,28 @@ static double wmi_get_property_value(struct flb_we *ctx, char *raw_property_key, return val; } +static char *wmi_get_property_str_value(struct flb_we *ctx, char *raw_property_key, + IWbemClassObject *class_obj) +{ + VARIANT prop; + char *strprop; + char *str_val = NULL; + HRESULT hr; + wchar_t *wproperty; + + + VariantInit(&prop); + wproperty = we_convert_str(raw_property_key); + hr = class_obj->lpVtbl->Get(class_obj, wproperty, 0, &prop, 0, 0); + if (FAILED(hr)) { + flb_plg_warn(ctx->ins, "Retrive prop failed. Error code = %x", hr); + } + str_val = convert_prop_to_str(&prop, FLB_TRUE); + VariantClear(&prop); + flb_free(wproperty); + + return str_val; +} static inline int wmi_update_metrics(struct flb_we *ctx, struct wmi_query_spec *spec, double val, IWbemClassObject *class_obj, uint64_t timestamp) @@ -279,12 +301,21 @@ static inline int wmi_execute_query(struct flb_we *ctx, struct wmi_query_spec *s size_t size; size = 14 + strlen(spec->wmi_counter); + if (spec->where_clause != NULL) { + size += 7 + strlen(spec->where_clause); + } query = flb_calloc(size, sizeof(char *)); if (!query) { flb_errno(); return -1; } - snprintf(query, size, "SELECT * FROM %s", spec->wmi_counter); + if (spec->where_clause != NULL) { + snprintf(query, size, "SELECT * FROM %s WHERE %s", spec->wmi_counter, spec->where_clause); + } + else { + snprintf(query, size, "SELECT * FROM %s", spec->wmi_counter); + } + flb_trace("[wmi] query = %s", query); wquery = we_convert_str(query); flb_free(query); @@ -519,6 +550,12 @@ double we_wmi_get_property_value(struct flb_we *ctx, char *raw_property_key, IWb return wmi_get_property_value(ctx, raw_property_key, class_obj); } +char *we_wmi_get_property_str_value(struct flb_we *ctx, char *raw_property_key, + IWbemClassObject *class_obj) +{ + return wmi_get_property_str_value(ctx, raw_property_key, class_obj); +} + int we_wmi_update_counters(struct flb_we *ctx, struct wmi_query_spec *spec, uint64_t timestamp, double val, int metric_label_count, char **metric_label_set) { wmi_update_counters(spec, timestamp, val, metric_label_count, metric_label_set); diff --git a/plugins/in_windows_exporter_metrics/we_wmi.h b/plugins/in_windows_exporter_metrics/we_wmi.h index bdb2fcc53c2..2999f57648f 100644 --- a/plugins/in_windows_exporter_metrics/we_wmi.h +++ b/plugins/in_windows_exporter_metrics/we_wmi.h @@ -34,6 +34,7 @@ struct wmi_query_spec { char *wmi_property; int label_property_count; char **label_property_keys; + char *where_clause; }; int we_wmi_init(struct flb_we *ctx); @@ -50,6 +51,8 @@ int we_wmi_coinitialize(struct flb_we *ctx); int we_wmi_execute_query(struct flb_we *ctx, struct wmi_query_spec *spec, IEnumWbemClassObject **out_enumerator); double we_wmi_get_value(struct flb_we *ctx, struct wmi_query_spec *spec, IWbemClassObject *class_obj); double we_wmi_get_property_value(struct flb_we *ctx, char *raw_property_key, IWbemClassObject *class_obj); +char *we_wmi_get_property_str_value(struct flb_we *ctx, char *raw_property_key, + IWbemClassObject *class_obj); int we_wmi_update_counters(struct flb_we *ctx, struct wmi_query_spec *spec, uint64_t timestamp, double val, int metric_label_count, char **metric_label_set); diff --git a/plugins/in_windows_exporter_metrics/we_wmi_cpu_info.c b/plugins/in_windows_exporter_metrics/we_wmi_cpu_info.c index 6d41b6a5750..9e8e96e1a17 100644 --- a/plugins/in_windows_exporter_metrics/we_wmi_cpu_info.c +++ b/plugins/in_windows_exporter_metrics/we_wmi_cpu_info.c @@ -84,6 +84,7 @@ int we_wmi_cpu_info_init(struct flb_we *ctx) ctx->wmi_cpu_info->info->label_property_keys[4] = "l2cachesize" ; ctx->wmi_cpu_info->info->label_property_keys[5] = "l3cachesize" ; ctx->wmi_cpu_info->info->label_property_keys[6] = "name" ; + ctx->wmi_cpu_info->info->where_clause = NULL; ctx->wmi_cpu_info->operational = FLB_TRUE; diff --git a/plugins/in_windows_exporter_metrics/we_wmi_logon.c b/plugins/in_windows_exporter_metrics/we_wmi_logon.c index b2ea201e10d..761d4ac7acb 100644 --- a/plugins/in_windows_exporter_metrics/we_wmi_logon.c +++ b/plugins/in_windows_exporter_metrics/we_wmi_logon.c @@ -70,6 +70,7 @@ int we_wmi_logon_init(struct flb_we *ctx) ctx->wmi_logon->info->wmi_property = "LogonType"; ctx->wmi_logon->info->label_property_count = 1; ctx->wmi_logon->info->label_property_keys[0] = "status" ; + ctx->wmi_logon->info->where_clause = NULL; ctx->wmi_logon->operational = FLB_TRUE; diff --git a/plugins/in_windows_exporter_metrics/we_wmi_service.c b/plugins/in_windows_exporter_metrics/we_wmi_service.c new file mode 100644 index 00000000000..4fb180a6217 --- /dev/null +++ b/plugins/in_windows_exporter_metrics/we_wmi_service.c @@ -0,0 +1,224 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Fluent Bit + * ========== + * Copyright (C) 2023 The Fluent Bit Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include + +#include "we.h" +#include "we_wmi.h" +#include "we_wmi_service.h" +#include "we_util.h" +#include "we_metric.h" + +static double nop_adjust(double value) +{ + return value; +} + +int we_wmi_service_init(struct flb_we *ctx) +{ + struct cmt_gauge *g; + + ctx->wmi_service = flb_calloc(1, sizeof(struct we_wmi_service_counters)); + if (!ctx->wmi_service) { + flb_errno(); + return -1; + } + ctx->wmi_service->operational = FLB_FALSE; + + g = cmt_gauge_create(ctx->cmt, "windows", "service", "info", + "A metric for Windows Service information", + 4, (char *[]) {"name", "display_name", "process_id", "run_as"}); + + if (!g) { + return -1; + } + ctx->wmi_service->information = g; + + + g = cmt_gauge_create(ctx->cmt, "windows", "service", "state", + "A state of the service", + 2, (char *[]){"name", "state"}); + if (!g) { + return -1; + } + ctx->wmi_service->state = g; + + g = cmt_gauge_create(ctx->cmt, "windows", "service", "start_mode", + "A start mode of the service", + 2, (char *[]){"name", "start_mode"}); + if (!g) { + return -1; + } + ctx->wmi_service->start_mode = g; + + g = cmt_gauge_create(ctx->cmt, "windows", "service", "status", + "A status of the service", + 2, (char *[]){"name", "status"}); + if (!g) { + return -1; + } + ctx->wmi_service->status = g; + + ctx->wmi_service->info = flb_calloc(1, sizeof(struct wmi_query_spec)); + if (!ctx->wmi_service->info) { + flb_errno(); + return -1; + } + ctx->wmi_service->info->metric_instance = (void *)g; + ctx->wmi_service->info->type = CMT_GAUGE; + ctx->wmi_service->info->value_adjuster = nop_adjust; + ctx->wmi_service->info->wmi_counter = "Win32_Service"; + ctx->wmi_service->info->wmi_property = ""; + ctx->wmi_service->info->label_property_count = 0; + ctx->wmi_service->info->label_property_keys = NULL; + ctx->wmi_service->info->where_clause = ctx->raw_where_clause; + + ctx->wmi_service->operational = FLB_TRUE; + + return 0; +} + +int we_wmi_service_exit(struct flb_we *ctx) +{ + flb_free(ctx->wmi_service->info); + flb_free(ctx->wmi_service); + + return 0; +} + +int we_wmi_service_update(struct flb_we *ctx) +{ + IEnumWbemClassObject* enumerator = NULL; + HRESULT hr; + + IWbemClassObject *class_obj = NULL; + ULONG ret = 0; + int i = 0; + uint64_t timestamp = 0; + char *service_name = NULL; + char *display_name = NULL; + char *pid = NULL; + char *run_as = NULL; + char *str_prop = NULL; + char *state = NULL; + char *start_mode = NULL; + char *status = NULL; + char **states = (char *[]){ + "stopped", "start pending", "stop pending", "running", + "continue pending", "pause pending", "paused", "unknown", NULL + }; + char **statuses = (char *[]){ + "ok", "error", "degraded", "unknown", + "pred fail", "starting", "stopping", "service", + "stressed", "nonrecover", "no contact", "lost comm", NULL + }; + char **start_modes = (char *[]) { + "boot", "system", "auto", "manual", "disabled", NULL + }; + + if (!ctx->wmi_service->operational) { + flb_plg_error(ctx->ins, "windows_service collector not yet in operational state"); + + return -1; + } + + if (FAILED(we_wmi_coinitialize(ctx))) { + return -1; + } + + timestamp = cfl_time_now(); + + if (FAILED(we_wmi_execute_query(ctx, ctx->wmi_service->info, &enumerator))) { + return -1; + } + + while (enumerator) { + hr = enumerator->lpVtbl->Next(enumerator, WBEM_INFINITE, 1, + &class_obj, &ret); + + if (0 == ret) { + break; + } + + service_name = we_wmi_get_property_str_value(ctx, "Name", class_obj); + display_name = we_wmi_get_property_str_value(ctx, "DisplayName", class_obj); + pid = we_wmi_get_property_str_value(ctx, "ProcessID", class_obj); + run_as = we_wmi_get_property_str_value(ctx, "StartName", class_obj); + state = we_wmi_get_property_str_value(ctx, "State", class_obj); + start_mode = we_wmi_get_property_str_value(ctx, "StartMode", class_obj); + status = we_wmi_get_property_str_value(ctx, "Status", class_obj); + + /* Information */ + cmt_gauge_set(ctx->wmi_service->information, timestamp, 1.0, + 4, (char *[]){ service_name, display_name, pid, run_as}); + + /* State */ + for (i = 0; states[i] != NULL; i++) { + if (strcasecmp(state, states[i]) == 0) { + cmt_gauge_set(ctx->wmi_service->state, timestamp, 1.0, + 2, (char *[]){ service_name, states[i]}); + } + else { + cmt_gauge_set(ctx->wmi_service->state, timestamp, 0.0, + 2, (char *[]){ service_name, states[i]}); + } + } + /* Start Mode */ + for (i = 0; start_modes[i] != NULL; i++) { + if (strcasecmp(start_mode, start_modes[i]) == 0) { + cmt_gauge_set(ctx->wmi_service->start_mode, timestamp, 1.0, + 2, (char *[]){ service_name, start_modes[i]}); + } + else { + cmt_gauge_set(ctx->wmi_service->start_mode, timestamp, 0.0, + 2, (char *[]){ service_name, start_modes[i]}); + } + } + + /* Status */ + for (i = 0; statuses[i] != NULL; i++) { + if (strcasecmp(status, statuses[i]) == 0) { + cmt_gauge_set(ctx->wmi_service->status, timestamp, 1.0, + 2, (char *[]){ service_name, statuses[i]}); + } else { + cmt_gauge_set(ctx->wmi_service->status, timestamp, 0.0, + 2, (char *[]){ service_name, statuses[i]}); + } + } + + class_obj->lpVtbl->Release(class_obj); + + flb_free(service_name); + flb_free(display_name); + flb_free(pid); + flb_free(run_as); + flb_free(state); + flb_free(start_mode); + flb_free(status); + } + + enumerator->lpVtbl->Release(enumerator); + we_wmi_cleanup(ctx); + + return 0; +} diff --git a/plugins/in_windows_exporter_metrics/we_wmi_service.h b/plugins/in_windows_exporter_metrics/we_wmi_service.h new file mode 100644 index 00000000000..d9b3efea9ef --- /dev/null +++ b/plugins/in_windows_exporter_metrics/we_wmi_service.h @@ -0,0 +1,29 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Fluent Bit + * ========== + * Copyright (C) 2023 The Fluent Bit Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLB_WE_WMI_SERVICE_H +#define FLB_WE_WMI_SERVICE_H + +#include "we.h" + +int we_wmi_service_init(struct flb_we *ctx); +int we_wmi_service_exit(struct flb_we *ctx); +int we_wmi_service_update(struct flb_we *ctx); + +#endif diff --git a/plugins/in_windows_exporter_metrics/we_wmi_system.c b/plugins/in_windows_exporter_metrics/we_wmi_system.c index aa2f0547b39..0eb7fffafc0 100644 --- a/plugins/in_windows_exporter_metrics/we_wmi_system.c +++ b/plugins/in_windows_exporter_metrics/we_wmi_system.c @@ -111,6 +111,7 @@ int we_wmi_system_init(struct flb_we *ctx) ctx->wmi_system->info->wmi_property = ""; ctx->wmi_system->info->label_property_count = 0; ctx->wmi_system->info->label_property_keys = NULL; + ctx->wmi_system->info->where_clause = NULL; ctx->wmi_system->operational = FLB_TRUE; diff --git a/plugins/in_windows_exporter_metrics/we_wmi_thermalzone.c b/plugins/in_windows_exporter_metrics/we_wmi_thermalzone.c index 757d8d92cdb..1766c590787 100644 --- a/plugins/in_windows_exporter_metrics/we_wmi_thermalzone.c +++ b/plugins/in_windows_exporter_metrics/we_wmi_thermalzone.c @@ -73,6 +73,7 @@ int we_wmi_thermalzone_init(struct flb_we *ctx) ctx->wmi_thermals->temperature_celsius->wmi_property = "HighPrecisionTemperature"; ctx->wmi_thermals->temperature_celsius->label_property_count = 1; ctx->wmi_thermals->temperature_celsius->label_property_keys[0] = "name" ; + ctx->wmi_thermals->temperature_celsius->where_clause = NULL; g = cmt_gauge_create(ctx->cmt, "windows", "thermalzone", "percent_passive_limit", "The limit of passive limit (percent).", @@ -100,6 +101,7 @@ int we_wmi_thermalzone_init(struct flb_we *ctx) ctx->wmi_thermals->percent_passive_limit->wmi_property = "PercentPassiveLimit"; ctx->wmi_thermals->percent_passive_limit->label_property_count = 1; ctx->wmi_thermals->percent_passive_limit->label_property_keys[0] = "name"; + ctx->wmi_thermals->percent_passive_limit->where_clause = NULL; g = cmt_gauge_create(ctx->cmt, "windows", "thermalzone", "throttle_reasons", "The reason of throttle.", @@ -125,6 +127,7 @@ int we_wmi_thermalzone_init(struct flb_we *ctx) ctx->wmi_thermals->throttle_reasons->wmi_property = "ThrottleReasons"; ctx->wmi_thermals->throttle_reasons->label_property_count = 1; ctx->wmi_thermals->throttle_reasons->label_property_keys[0] = "name"; + ctx->wmi_thermals->throttle_reasons->where_clause = NULL; ctx->wmi_thermals->operational = FLB_TRUE; From 933b788bb269d42360988bb47986069ce44e506f Mon Sep 17 00:00:00 2001 From: Hiroshi Hatake Date: Tue, 20 Jun 2023 18:33:57 +0900 Subject: [PATCH 060/315] in_windows_exporter_metrics: Display errored property name Signed-off-by: Hiroshi Hatake --- plugins/in_windows_exporter_metrics/we_wmi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/in_windows_exporter_metrics/we_wmi.c b/plugins/in_windows_exporter_metrics/we_wmi.c index be93653ae9d..03505c4bc90 100644 --- a/plugins/in_windows_exporter_metrics/we_wmi.c +++ b/plugins/in_windows_exporter_metrics/we_wmi.c @@ -191,7 +191,7 @@ static double wmi_get_value(struct flb_we *ctx, struct wmi_query_spec *spec, IWb wproperty = we_convert_str(spec->wmi_property); hr = class_obj->lpVtbl->Get(class_obj, wproperty, 0, &prop, 0, 0); if (FAILED(hr)) { - flb_plg_warn(ctx->ins, "Retrive prop failed. Error code = %x", hr); + flb_plg_warn(ctx->ins, "Retrive prop '%s' failed. Error code = %x", spec->wmi_property, hr); } strprop = convert_prop_to_str(&prop, FLB_FALSE); if (strprop == NULL) { @@ -217,7 +217,7 @@ static double wmi_get_property_value(struct flb_we *ctx, char *raw_property_key, wproperty = we_convert_str(raw_property_key); hr = class_obj->lpVtbl->Get(class_obj, wproperty, 0, &prop, 0, 0); if (FAILED(hr)) { - flb_plg_warn(ctx->ins, "Retrive prop failed. Error code = %x", hr); + flb_plg_warn(ctx->ins, "Retrive prop '%s' failed. Error code = %x", raw_property_key, hr); } strprop = convert_prop_to_str(&prop, FLB_FALSE); if (strprop == NULL) { @@ -245,7 +245,7 @@ static char *wmi_get_property_str_value(struct flb_we *ctx, char *raw_property_k wproperty = we_convert_str(raw_property_key); hr = class_obj->lpVtbl->Get(class_obj, wproperty, 0, &prop, 0, 0); if (FAILED(hr)) { - flb_plg_warn(ctx->ins, "Retrive prop failed. Error code = %x", hr); + flb_plg_warn(ctx->ins, "Retrive prop '%s' failed. Error code = %x", raw_property_key, hr); } str_val = convert_prop_to_str(&prop, FLB_TRUE); VariantClear(&prop); From 9fdd6c1c674956013d4b45025d56c518682a896e Mon Sep 17 00:00:00 2001 From: Hiroshi Hatake Date: Wed, 21 Jun 2023 16:58:52 +0900 Subject: [PATCH 061/315] in_windows_exporter_metrics: Prevent to operate service metrics when terminating Signed-off-by: Hiroshi Hatake --- plugins/in_windows_exporter_metrics/we_wmi_service.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/in_windows_exporter_metrics/we_wmi_service.c b/plugins/in_windows_exporter_metrics/we_wmi_service.c index 4fb180a6217..beb8ff8a38d 100644 --- a/plugins/in_windows_exporter_metrics/we_wmi_service.c +++ b/plugins/in_windows_exporter_metrics/we_wmi_service.c @@ -100,6 +100,8 @@ int we_wmi_service_init(struct flb_we *ctx) int we_wmi_service_exit(struct flb_we *ctx) { + ctx->wmi_service->operational = FLB_FALSE; + flb_free(ctx->wmi_service->info); flb_free(ctx->wmi_service); From 50453775c2073079eef54bd9bfce1c77b0f7cdd7 Mon Sep 17 00:00:00 2001 From: Hiroshi Hatake Date: Thu, 22 Jun 2023 13:45:00 +0900 Subject: [PATCH 062/315] in_windows_exporter_metrics: Handle we.service.include and we.service.exclude options to construct where clause Signed-off-by: Hiroshi Hatake --- plugins/in_windows_exporter_metrics/we.c | 10 + plugins/in_windows_exporter_metrics/we.h | 6 + .../in_windows_exporter_metrics/we_config.c | 42 +++ .../we_wmi_service.c | 269 +++++++++++++++++- 4 files changed, 326 insertions(+), 1 deletion(-) diff --git a/plugins/in_windows_exporter_metrics/we.c b/plugins/in_windows_exporter_metrics/we.c index 5a010485b95..b0af3ecccff 100644 --- a/plugins/in_windows_exporter_metrics/we.c +++ b/plugins/in_windows_exporter_metrics/we.c @@ -916,6 +916,16 @@ static struct flb_config_map config_map[] = { 0, FLB_TRUE, offsetof(struct flb_we, raw_where_clause), "Specify the where clause for retrieving service metrics." }, + { + FLB_CONFIG_MAP_STR, "we.service.include", NULL, + 0, FLB_TRUE, offsetof(struct flb_we, raw_service_include), + "Specify the key value condition pairs for includeing condition to construct where clause of service metrics." + }, + { + FLB_CONFIG_MAP_STR, "we.service.exclude", NULL, + 0, FLB_TRUE, offsetof(struct flb_we, raw_service_exclude), + "Specify the key value condition pairs for excludeing condition to construct where clause of service metrics." + }, /* EOF */ {0} }; diff --git a/plugins/in_windows_exporter_metrics/we.h b/plugins/in_windows_exporter_metrics/we.h index 2bbf6cdebe7..e74305e0967 100644 --- a/plugins/in_windows_exporter_metrics/we.h +++ b/plugins/in_windows_exporter_metrics/we.h @@ -188,6 +188,12 @@ struct flb_we { char *raw_denying_disk; char *raw_allowing_nic; char *raw_where_clause; + char *raw_service_include; + char *raw_service_exclude; + char *service_include_buffer; + int service_include_buffer_size; + char *service_exclude_buffer; + int service_exclude_buffer_size; struct flb_regex *allowing_disk_regex; struct flb_regex *denying_disk_regex; diff --git a/plugins/in_windows_exporter_metrics/we_config.c b/plugins/in_windows_exporter_metrics/we_config.c index 77a567758e8..c8f897042d3 100644 --- a/plugins/in_windows_exporter_metrics/we_config.c +++ b/plugins/in_windows_exporter_metrics/we_config.c @@ -19,6 +19,7 @@ */ #include +#include #include "we.h" struct flb_we *flb_we_config_create(struct flb_input_instance *ins, @@ -26,6 +27,7 @@ struct flb_we *flb_we_config_create(struct flb_input_instance *ins, { int ret; struct flb_we *ctx; + int root_type; ctx = flb_calloc(1, sizeof(struct flb_we)); if (!ctx) { @@ -36,6 +38,10 @@ struct flb_we *flb_we_config_create(struct flb_input_instance *ins, ctx->allowing_disk_regex = NULL; ctx->denying_disk_regex = NULL; ctx->allowing_nic_regex = NULL; + ctx->service_include_buffer = NULL; + ctx->service_include_buffer_size = 0; + ctx->service_exclude_buffer = NULL; + ctx->service_exclude_buffer_size = 0; /* Load the config map */ ret = flb_input_config_map_set(ins, (void *) ctx); @@ -57,6 +63,34 @@ struct flb_we *flb_we_config_create(struct flb_input_instance *ins, ctx->allowing_nic_regex = flb_regex_create(ctx->raw_allowing_nic); } + if (ctx->raw_service_include != NULL) { + ret = flb_pack_json(ctx->raw_service_include, + strlen(ctx->raw_service_include), + &ctx->service_include_buffer, + &ctx->service_include_buffer_size, + &root_type, + NULL); + if (ret != 0) { + flb_plg_warn(ctx->ins, "we.service.include is incomplete. Ignored."); + ctx->service_include_buffer = NULL; + ctx->service_include_buffer_size = 0; + } + } + + if (ctx->raw_service_exclude != NULL) { + ret = flb_pack_json(ctx->raw_service_exclude, + strlen(ctx->raw_service_exclude), + &ctx->service_exclude_buffer, + &ctx->service_exclude_buffer_size, + &root_type, + NULL); + if (ret != 0) { + flb_plg_warn(ctx->ins, "we.service.exclude is incomplete. Ignored."); + ctx->service_exclude_buffer = NULL; + ctx->service_exclude_buffer_size = 0; + } + } + ctx->cmt = cmt_create(); if (!ctx->cmt) { flb_plg_error(ins, "could not initialize CMetrics"); @@ -85,6 +119,14 @@ void flb_we_config_destroy(struct flb_we *ctx) flb_regex_destroy(ctx->allowing_nic_regex); } + if (ctx->service_include_buffer != NULL) { + flb_free(ctx->service_include_buffer); + } + + if (ctx->service_exclude_buffer != NULL) { + flb_free(ctx->service_exclude_buffer); + } + if (ctx->cmt) { cmt_destroy(ctx->cmt); } diff --git a/plugins/in_windows_exporter_metrics/we_wmi_service.c b/plugins/in_windows_exporter_metrics/we_wmi_service.c index beb8ff8a38d..e31a4943b8f 100644 --- a/plugins/in_windows_exporter_metrics/we_wmi_service.c +++ b/plugins/in_windows_exporter_metrics/we_wmi_service.c @@ -34,8 +34,268 @@ static double nop_adjust(double value) return value; } +static int construct_include_clause(struct flb_we *ctx, flb_sds_t *clause) +{ + int ret = -1; + size_t off = 0; + msgpack_unpacked result; + msgpack_object key; + msgpack_object val; + msgpack_object map; + int map_size; + int i; + int idx = 0; + int use_like = FLB_FALSE; + char *key_str = NULL; + size_t key_str_size = 0; + char *val_str = NULL; + size_t val_str_size = 0; + flb_sds_t val_buf; + + msgpack_unpacked_init(&result); + while (msgpack_unpack_next(&result, + ctx->service_include_buffer, + ctx->service_include_buffer_size, + &off) == MSGPACK_UNPACK_SUCCESS) { + if (result.data.type != MSGPACK_OBJECT_MAP) { + flb_plg_error(ctx->ins, "Invalid include buffer"); + ret = -2; + + goto cleanup; + } + + map = result.data; + map_size = map.via.map.size; + + for (i = 0; i < map_size; i++) { + use_like = FLB_FALSE; + if (idx == 0) { + flb_sds_cat_safe(clause, "(", 1); + } + else { + flb_sds_cat_safe(clause, " OR ", 4); + } + + key = map.via.map.ptr[i].key; + val = map.via.map.ptr[i].val; + if (key.type == MSGPACK_OBJECT_BIN) { + key_str = (char *) key.via.bin.ptr; + key_str_size = key.via.bin.size; + } + else if (key.type == MSGPACK_OBJECT_STR) { + key_str = (char *) key.via.str.ptr; + key_str_size = key.via.str.size; + } + if (val.type == MSGPACK_OBJECT_BIN) { + val_str = (char *) val.via.bin.ptr; + val_str_size = val.via.bin.size; + val_buf = flb_sds_create_len(val_str, val_str_size); + if (val_buf == NULL) { + flb_plg_error(ctx->ins, "val_buf creation is failed"); + ret = -3; + + goto cleanup; + } + } + else if (val.type == MSGPACK_OBJECT_STR) { + val_str = (char *) val.via.str.ptr; + val_str_size = val.via.str.size; + val_buf = flb_sds_create_len(val_str, val_str_size); + if (val_buf == NULL) { + flb_plg_error(ctx->ins, "val_buf creation is failed"); + ret = -3; + + goto cleanup; + } + } + + if (val_str != NULL && strstr(val_buf, "%") != NULL) { + use_like = FLB_TRUE; + flb_sds_destroy(val_buf); + } + flb_sds_cat_safe(clause, key_str, key_str_size); + if (use_like == FLB_TRUE) { + flb_sds_cat_safe(clause, " LIKE ", 6); + } + else { + flb_sds_cat_safe(clause, "=", 1); + } + flb_sds_cat_safe(clause, "'", 1); + flb_sds_cat_safe(clause, val_str, val_str_size); + flb_sds_cat_safe(clause, "'", 1); + idx++; + } + flb_sds_cat_safe(clause, ")", 1); + } + msgpack_unpacked_destroy(&result); + + return 0; + +cleanup: + msgpack_unpacked_destroy(&result); + + return ret; +} + +static int construct_exclude_clause(struct flb_we *ctx, flb_sds_t *clause) +{ + int ret = -1; + size_t off = 0; + msgpack_unpacked result; + msgpack_object key; + msgpack_object val; + msgpack_object map; + int map_size; + int i; + int idx = 0; + int use_like = FLB_FALSE; + char *key_str = NULL; + size_t key_str_size = 0; + char *val_str = NULL; + size_t val_str_size = 0; + flb_sds_t val_buf; + + msgpack_unpacked_init(&result); + while (msgpack_unpack_next(&result, + ctx->service_exclude_buffer, + ctx->service_exclude_buffer_size, + &off) == MSGPACK_UNPACK_SUCCESS) { + if (result.data.type != MSGPACK_OBJECT_MAP) { + flb_plg_error(ctx->ins, "Invalid exclude buffer"); + ret = -2; + + goto cleanup; + } + + map = result.data; + map_size = map.via.map.size; + + for (i = 0; i < map_size; i++) { + use_like = FLB_FALSE; + if (idx == 0) { + flb_sds_cat_safe(clause, "(", 1); + } + else { + flb_sds_cat_safe(clause, " AND ", 5); + } + + key = map.via.map.ptr[i].key; + val = map.via.map.ptr[i].val; + if (key.type == MSGPACK_OBJECT_BIN) { + key_str = (char *) key.via.bin.ptr; + key_str_size = key.via.bin.size; + } + else if (key.type == MSGPACK_OBJECT_STR) { + key_str = (char *) key.via.str.ptr; + key_str_size = key.via.str.size; + } + if (val.type == MSGPACK_OBJECT_BIN) { + val_str = (char *) val.via.bin.ptr; + val_str_size = val.via.bin.size; + val_buf = flb_sds_create_len(val_str, val_str_size); + if (val_buf == NULL) { + flb_plg_error(ctx->ins, "val_buf creation is failed"); + ret = -3; + + goto cleanup; + } + } + else if (val.type == MSGPACK_OBJECT_STR) { + val_str = (char *) val.via.str.ptr; + val_str_size = val.via.str.size; + val_buf = flb_sds_create_len(val_str, val_str_size); + if (val_buf == NULL) { + flb_plg_error(ctx->ins, "val_buf creation is failed"); + ret = -3; + + goto cleanup; + } + } + + if (val_str != NULL && strstr(val_buf, "%") != NULL) { + use_like = FLB_TRUE; + flb_sds_destroy(val_buf); + } + if (use_like == FLB_TRUE) { + flb_sds_cat_safe(clause, "NOT ", 4); + } + flb_sds_cat_safe(clause, key_str, key_str_size); + if (use_like == FLB_TRUE) { + flb_sds_cat_safe(clause, " LIKE ", 6); + } + else { + flb_sds_cat_safe(clause, "!=", 2); + } + flb_sds_cat_safe(clause, "'", 1); + flb_sds_cat_safe(clause, val_str, val_str_size); + flb_sds_cat_safe(clause, "'", 1); + idx++; + } + flb_sds_cat_safe(clause, ")", 1); + } + msgpack_unpacked_destroy(&result); + + return 0; + +cleanup: + msgpack_unpacked_destroy(&result); + + return ret; +} + +static int construct_where_clause(struct flb_we *ctx) +{ + int ret; + flb_sds_t clause; + + clause = flb_sds_create_size(256); + if (!clause) { + return -1; + } + + if (ctx->service_include_buffer != NULL && ctx->service_include_buffer_size > 0) { + ret = construct_include_clause(ctx, &clause); + if (ret != 0) { + goto cleanup; + } + } + + if (ctx->service_exclude_buffer != NULL && ctx->service_exclude_buffer_size > 0) { + if (flb_sds_len(clause) > 0) { + flb_sds_cat_safe(&clause, " AND ", 5); + } + ret = construct_exclude_clause(ctx, &clause); + if (ret != 0) { + goto cleanup; + } + } + + if (ctx->raw_where_clause != NULL){ + if (flb_sds_len(clause) > 0) { + flb_sds_cat_safe(&clause, " AND (", 6); + flb_sds_cat_safe(&clause, ctx->raw_where_clause, strlen(ctx->raw_where_clause)); + flb_sds_cat_safe(&clause, ")", 1); + } + else { + flb_sds_cat_safe(&clause, ctx->raw_where_clause, strlen(ctx->raw_where_clause)); + } + } + + if (flb_sds_len(clause) > 0) { + ctx->wmi_service->info->where_clause = clause; + } + + return 0; + +cleanup: + flb_sds_destroy(clause); + + return ret; +} + int we_wmi_service_init(struct flb_we *ctx) { + int ret; struct cmt_gauge *g; ctx->wmi_service = flb_calloc(1, sizeof(struct we_wmi_service_counters)); @@ -91,7 +351,11 @@ int we_wmi_service_init(struct flb_we *ctx) ctx->wmi_service->info->wmi_property = ""; ctx->wmi_service->info->label_property_count = 0; ctx->wmi_service->info->label_property_keys = NULL; - ctx->wmi_service->info->where_clause = ctx->raw_where_clause; + ctx->wmi_service->info->where_clause = NULL; + ret = construct_where_clause(ctx); + if (ret != 0) { + return ret; + } ctx->wmi_service->operational = FLB_TRUE; @@ -102,6 +366,9 @@ int we_wmi_service_exit(struct flb_we *ctx) { ctx->wmi_service->operational = FLB_FALSE; + if (ctx->wmi_service->info->where_clause != NULL) { + flb_sds_destroy(ctx->wmi_service->info->where_clause); + } flb_free(ctx->wmi_service->info); flb_free(ctx->wmi_service); From 531a48d01f9d314655581357af8341f72baccda4 Mon Sep 17 00:00:00 2001 From: Hiroshi Hatake Date: Fri, 23 Jun 2023 13:11:54 +0900 Subject: [PATCH 063/315] in_node_exporter_metrics: Handle missing throttle metrics case such as VM Signed-off-by: Hiroshi Hatake --- plugins/in_node_exporter_metrics/ne_cpu_linux.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/plugins/in_node_exporter_metrics/ne_cpu_linux.c b/plugins/in_node_exporter_metrics/ne_cpu_linux.c index 70b75b18b84..753a59ce98f 100644 --- a/plugins/in_node_exporter_metrics/ne_cpu_linux.c +++ b/plugins/in_node_exporter_metrics/ne_cpu_linux.c @@ -148,10 +148,9 @@ static int cpu_thermal_update(struct flb_ne *ctx, uint64_t ts) "thermal_throttle", "core_throttle_count", &core_throttle_count); if (ret != 0) { - flb_plg_error(ctx->ins, + flb_plg_debug(ctx->ins, "CPU is missing core_throttle_count: %s", entry->str); - continue; } snprintf(tmp1, sizeof(tmp1) -1, "%" PRIu64, core_id); @@ -175,10 +174,9 @@ static int cpu_thermal_update(struct flb_ne *ctx, uint64_t ts) "thermal_throttle", "package_throttle_count", &package_throttle_count); if (ret != 0) { - flb_plg_error(ctx->ins, + flb_plg_debug(ctx->ins, "CPU is missing package_throttle_count: %s", entry->str); - continue; } /* Set new value */ From 767b5f7a3456a94eb77a00e04e0d2adf3e6bbc99 Mon Sep 17 00:00:00 2001 From: Hiroshi Hatake Date: Fri, 23 Jun 2023 17:51:49 +0900 Subject: [PATCH 064/315] in_node_exporter_metrics: Update metrics value only if succeeded Signed-off-by: Hiroshi Hatake --- .../in_node_exporter_metrics/ne_cpu_linux.c | 29 ++++++++++--------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/plugins/in_node_exporter_metrics/ne_cpu_linux.c b/plugins/in_node_exporter_metrics/ne_cpu_linux.c index 753a59ce98f..8963f0c5599 100644 --- a/plugins/in_node_exporter_metrics/ne_cpu_linux.c +++ b/plugins/in_node_exporter_metrics/ne_cpu_linux.c @@ -152,15 +152,15 @@ static int cpu_thermal_update(struct flb_ne *ctx, uint64_t ts) "CPU is missing core_throttle_count: %s", entry->str); } - - snprintf(tmp1, sizeof(tmp1) -1, "%" PRIu64, core_id); - snprintf(tmp2, sizeof(tmp2) -1, "%" PRIu64, physical_package_id); - - /* Set new value */ - cmt_counter_set(ctx->cpu_core_throttles, ts, - (double) core_throttle_count, - 2, (char *[]) {tmp1, tmp2}); - + else { + snprintf(tmp1, sizeof(tmp1) -1, "%" PRIu64, core_id); + snprintf(tmp2, sizeof(tmp2) -1, "%" PRIu64, physical_package_id); + + /* Set new value */ + cmt_counter_set(ctx->cpu_core_throttles, ts, + (double) core_throttle_count, + 2, (char *[]) {tmp1, tmp2}); + } /* Only update this entry once */ if (package_throttles_set[physical_package_id] != 0) { @@ -178,11 +178,12 @@ static int cpu_thermal_update(struct flb_ne *ctx, uint64_t ts) "CPU is missing package_throttle_count: %s", entry->str); } - - /* Set new value */ - cmt_counter_set(ctx->cpu_package_throttles, ts, - (double) package_throttle_count, - 1, (char *[]) {tmp2}); + else { + /* Set new value */ + cmt_counter_set(ctx->cpu_package_throttles, ts, + (double) package_throttle_count, + 1, (char *[]) {tmp2}); + } } flb_slist_destroy(&list); From 3ac059fca6d83ff1f75e91df5d33c9daad9511f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Cendrzak?= Date: Tue, 30 May 2023 15:47:02 +0200 Subject: [PATCH 065/315] in_podman_metrics: Fixed reading undefined PID MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In case of not found pid file, it took a form of UINT64_MAX, after that plugin tried to read from it from proc. Fixed it. Also added alternative path for cgroupsv2 pid file. Signed-off-by: Paweł Cendrzak --- plugins/in_podman_metrics/podman_metrics_config.h | 1 + plugins/in_podman_metrics/podman_metrics_data.c | 13 +++++++++++-- .../cgroupv2/{18446744073709551615 => 42}/net/dev | 0 .../containers/cgroup.procs} | 0 .../memory.current | 1 + .../garbage/{18446744073709551615 => 42}/net/dev | 0 .../no_sysfs/{18446744073709551615 => 42}/net/dev | 0 .../regular/{18446744073709551615 => 42}/net/dev | 0 .../cgroup.procs | 3 +++ .../reversed/{18446744073709551615 => 42}/net/dev | 0 .../cgroup.procs | 3 +++ tests/runtime/in_podman_metrics.c | 2 +- 12 files changed, 20 insertions(+), 3 deletions(-) rename tests/runtime/data/podman/cgroupv2/{18446744073709551615 => 42}/net/dev (100%) rename tests/runtime/data/podman/cgroupv2/{memory/libpod-8a19d6058bfbe88cd0548eba9047d94c70161f5d74b545c7504b2f27491686d9/memory.current => libpod-8a19d6058bfbe88cd0548eba9047d94c70161f5d74b545c7504b2f27491686d9/containers/cgroup.procs} (100%) create mode 100644 tests/runtime/data/podman/cgroupv2/libpod-8a19d6058bfbe88cd0548eba9047d94c70161f5d74b545c7504b2f27491686d9/memory.current rename tests/runtime/data/podman/garbage/{18446744073709551615 => 42}/net/dev (100%) rename tests/runtime/data/podman/no_sysfs/{18446744073709551615 => 42}/net/dev (100%) rename tests/runtime/data/podman/regular/{18446744073709551615 => 42}/net/dev (100%) create mode 100644 tests/runtime/data/podman/regular/systemd/libpod-8a19d6058bfbe88cd0548eba9047d94c70161f5d74b545c7504b2f27491686d9/cgroup.procs rename tests/runtime/data/podman/reversed/{18446744073709551615 => 42}/net/dev (100%) create mode 100644 tests/runtime/data/podman/reversed/systemd/libpod-8a19d6058bfbe88cd0548eba9047d94c70161f5d74b545c7504b2f27491686d9/cgroup.procs diff --git a/plugins/in_podman_metrics/podman_metrics_config.h b/plugins/in_podman_metrics/podman_metrics_config.h index b7b653ac6f9..fabdc0a8ddb 100644 --- a/plugins/in_podman_metrics/podman_metrics_config.h +++ b/plugins/in_podman_metrics/podman_metrics_config.h @@ -106,6 +106,7 @@ #define V2_SYSFS_FILE_MEMORY_LIMIT "memory.max" #define V2_SYSFS_FILE_CPU_STAT "cpu.stat" #define V2_SYSFS_FILE_PIDS "cgroup.procs" +#define V2_SYSFS_FILE_PIDS_ALT "containers/cgroup.procs" /* Values used to construct counters/gauges names and descriptions */ #define COUNTER_PREFIX "container" diff --git a/plugins/in_podman_metrics/podman_metrics_data.c b/plugins/in_podman_metrics/podman_metrics_data.c index fba2c8e1ad0..e747fe4b8e3 100644 --- a/plugins/in_podman_metrics/podman_metrics_data.c +++ b/plugins/in_podman_metrics/podman_metrics_data.c @@ -331,9 +331,12 @@ int fill_counters_with_sysfs_data_v1(struct flb_in_metrics *ctx) cnt->cpu_user = get_data_from_sysfs(ctx, cpu_path, V1_SYSFS_FILE_CPU_USER, NULL); cnt->cpu = get_data_from_sysfs(ctx, cpu_path, V1_SYSFS_FILE_CPU, NULL); pid = get_data_from_sysfs(ctx, systemd_path, V1_SYSFS_FILE_PIDS, NULL); - if (pid) { + if (pid && pid != UINT64_MAX) { get_net_data_from_proc(ctx, cnt, pid); } + else { + flb_plg_warn(ctx->ins, "Failed to collect PID for %s", cnt->name); + } } return 0; } @@ -364,9 +367,15 @@ int fill_counters_with_sysfs_data_v2(struct flb_in_metrics *ctx) cnt->cpu_user = get_data_from_sysfs(ctx, path, V2_SYSFS_FILE_CPU_STAT, STAT_KEY_CPU_USER); cnt->cpu = get_data_from_sysfs(ctx, path, V2_SYSFS_FILE_CPU_STAT, STAT_KEY_CPU); pid = get_data_from_sysfs(ctx, path, V2_SYSFS_FILE_PIDS, NULL); - if (pid) { + if (!pid || pid == UINT64_MAX) { + pid = get_data_from_sysfs(ctx, path, V2_SYSFS_FILE_PIDS_ALT, NULL); + } + if (pid && pid != UINT64_MAX) { get_net_data_from_proc(ctx, cnt, pid); } + else { + flb_plg_warn(ctx->ins, "Failed to collect PID for %s", cnt->name); + } } return 0; } diff --git a/tests/runtime/data/podman/cgroupv2/18446744073709551615/net/dev b/tests/runtime/data/podman/cgroupv2/42/net/dev similarity index 100% rename from tests/runtime/data/podman/cgroupv2/18446744073709551615/net/dev rename to tests/runtime/data/podman/cgroupv2/42/net/dev diff --git a/tests/runtime/data/podman/cgroupv2/memory/libpod-8a19d6058bfbe88cd0548eba9047d94c70161f5d74b545c7504b2f27491686d9/memory.current b/tests/runtime/data/podman/cgroupv2/libpod-8a19d6058bfbe88cd0548eba9047d94c70161f5d74b545c7504b2f27491686d9/containers/cgroup.procs similarity index 100% rename from tests/runtime/data/podman/cgroupv2/memory/libpod-8a19d6058bfbe88cd0548eba9047d94c70161f5d74b545c7504b2f27491686d9/memory.current rename to tests/runtime/data/podman/cgroupv2/libpod-8a19d6058bfbe88cd0548eba9047d94c70161f5d74b545c7504b2f27491686d9/containers/cgroup.procs diff --git a/tests/runtime/data/podman/cgroupv2/libpod-8a19d6058bfbe88cd0548eba9047d94c70161f5d74b545c7504b2f27491686d9/memory.current b/tests/runtime/data/podman/cgroupv2/libpod-8a19d6058bfbe88cd0548eba9047d94c70161f5d74b545c7504b2f27491686d9/memory.current new file mode 100644 index 00000000000..d81cc0710eb --- /dev/null +++ b/tests/runtime/data/podman/cgroupv2/libpod-8a19d6058bfbe88cd0548eba9047d94c70161f5d74b545c7504b2f27491686d9/memory.current @@ -0,0 +1 @@ +42 diff --git a/tests/runtime/data/podman/garbage/18446744073709551615/net/dev b/tests/runtime/data/podman/garbage/42/net/dev similarity index 100% rename from tests/runtime/data/podman/garbage/18446744073709551615/net/dev rename to tests/runtime/data/podman/garbage/42/net/dev diff --git a/tests/runtime/data/podman/no_sysfs/18446744073709551615/net/dev b/tests/runtime/data/podman/no_sysfs/42/net/dev similarity index 100% rename from tests/runtime/data/podman/no_sysfs/18446744073709551615/net/dev rename to tests/runtime/data/podman/no_sysfs/42/net/dev diff --git a/tests/runtime/data/podman/regular/18446744073709551615/net/dev b/tests/runtime/data/podman/regular/42/net/dev similarity index 100% rename from tests/runtime/data/podman/regular/18446744073709551615/net/dev rename to tests/runtime/data/podman/regular/42/net/dev diff --git a/tests/runtime/data/podman/regular/systemd/libpod-8a19d6058bfbe88cd0548eba9047d94c70161f5d74b545c7504b2f27491686d9/cgroup.procs b/tests/runtime/data/podman/regular/systemd/libpod-8a19d6058bfbe88cd0548eba9047d94c70161f5d74b545c7504b2f27491686d9/cgroup.procs new file mode 100644 index 00000000000..a2a31c0022c --- /dev/null +++ b/tests/runtime/data/podman/regular/systemd/libpod-8a19d6058bfbe88cd0548eba9047d94c70161f5d74b545c7504b2f27491686d9/cgroup.procs @@ -0,0 +1,3 @@ +42 +73 +12 diff --git a/tests/runtime/data/podman/reversed/18446744073709551615/net/dev b/tests/runtime/data/podman/reversed/42/net/dev similarity index 100% rename from tests/runtime/data/podman/reversed/18446744073709551615/net/dev rename to tests/runtime/data/podman/reversed/42/net/dev diff --git a/tests/runtime/data/podman/reversed/systemd/libpod-8a19d6058bfbe88cd0548eba9047d94c70161f5d74b545c7504b2f27491686d9/cgroup.procs b/tests/runtime/data/podman/reversed/systemd/libpod-8a19d6058bfbe88cd0548eba9047d94c70161f5d74b545c7504b2f27491686d9/cgroup.procs new file mode 100644 index 00000000000..a2a31c0022c --- /dev/null +++ b/tests/runtime/data/podman/reversed/systemd/libpod-8a19d6058bfbe88cd0548eba9047d94c70161f5d74b545c7504b2f27491686d9/cgroup.procs @@ -0,0 +1,3 @@ +42 +73 +12 diff --git a/tests/runtime/in_podman_metrics.c b/tests/runtime/in_podman_metrics.c index 2b5195fb69b..5ea0f852b7c 100644 --- a/tests/runtime/in_podman_metrics.c +++ b/tests/runtime/in_podman_metrics.c @@ -158,7 +158,7 @@ void flb_test_ipm_no_sysfs() { TEST_CHECK(flb_start(ctx) == 0); sleep(1); TEST_CHECK(check_metric(ctx, "usage_bytes") != 0); - TEST_CHECK(check_metric(ctx, "receive_bytes_total") == 0); + TEST_CHECK(check_metric(ctx, "receive_bytes_total") != 0); do_destroy(ctx); } From f9e8dd8341c0830795a0be3ce55f2a25e266cac4 Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Sun, 2 Jul 2023 18:24:32 -0600 Subject: [PATCH 066/315] lib: cmetrics: upgrade to v0.6.3 Signed-off-by: Eduardo Silva --- lib/cmetrics/CMakeLists.txt | 12 ++++++------ lib/cmetrics/src/cmt_decode_opentelemetry.c | 3 +++ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/lib/cmetrics/CMakeLists.txt b/lib/cmetrics/CMakeLists.txt index 411e68ddc40..38a86e5f44b 100644 --- a/lib/cmetrics/CMakeLists.txt +++ b/lib/cmetrics/CMakeLists.txt @@ -3,6 +3,12 @@ project(cmetrics C) set(CMAKE_POSITION_INDEPENDENT_CODE ON) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +# CMetrics Version +set(CMT_VERSION_MAJOR 0) +set(CMT_VERSION_MINOR 6) +set(CMT_VERSION_PATCH 3) +set(CMT_VERSION_STR "${CMT_VERSION_MAJOR}.${CMT_VERSION_MINOR}.${CMT_VERSION_PATCH}") + # Include helpers include(cmake/macros.cmake) include(CheckCSourceCompiles) @@ -54,12 +60,6 @@ if(NOT MSVC) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall") endif() -# CMetrics Version -set(CMT_VERSION_MAJOR 0) -set(CMT_VERSION_MINOR 6) -set(CMT_VERSION_PATCH 2) -set(CMT_VERSION_STR "${CMT_VERSION_MAJOR}.${CMT_VERSION_MINOR}.${CMT_VERSION_PATCH}") - # Define __CMT_FILENAME__ consistently across Operating Systems if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Windows") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D__CMT_FILENAME__='\"$(subst ${CMAKE_SOURCE_DIR}/,,$(abspath $<))\"'") diff --git a/lib/cmetrics/src/cmt_decode_opentelemetry.c b/lib/cmetrics/src/cmt_decode_opentelemetry.c index 90d2d2fe7ee..aad4250710e 100644 --- a/lib/cmetrics/src/cmt_decode_opentelemetry.c +++ b/lib/cmetrics/src/cmt_decode_opentelemetry.c @@ -50,6 +50,9 @@ static struct cfl_variant *clone_variant(Opentelemetry__Proto__Common__V1__AnyVa struct cfl_variant *result_instance = NULL; int result; + if (source == NULL) { + return NULL; + } if (source->value_case == OPENTELEMETRY__PROTO__COMMON__V1__ANY_VALUE__VALUE_STRING_VALUE) { result_instance = cfl_variant_create_from_string(source->string_value); } From 785b7e3c174a60229172ea50ae5ee815a314a5f6 Mon Sep 17 00:00:00 2001 From: Leonardo Alminana Date: Thu, 15 Jun 2023 12:58:46 +0200 Subject: [PATCH 067/315] downstream: fixed the event loop registration detection mechanism Signed-off-by: Leonardo Alminana --- src/flb_downstream.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/flb_downstream.c b/src/flb_downstream.c index ce32b6d15b7..689d2020718 100644 --- a/src/flb_downstream.c +++ b/src/flb_downstream.c @@ -188,7 +188,7 @@ static int prepare_destroy_conn(struct flb_connection *connection) flb_trace("[downstream] destroy connection #%i to %s", connection->fd, flb_connection_get_remote_address(connection)); - if (stream->flags & FLB_IO_ASYNC) { + if(MK_EVENT_IS_REGISTERED((&connection->event))) { mk_event_del(connection->evl, &connection->event); } From c1641b35cdffa4a3e6c96025151418807b811ad8 Mon Sep 17 00:00:00 2001 From: leonardo-albertovich Date: Thu, 29 Jun 2023 12:31:06 +0200 Subject: [PATCH 068/315] Update src/flb_downstream.c Co-authored-by: igorpeshansky Signed-off-by: leonardo-albertovich --- src/flb_downstream.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/flb_downstream.c b/src/flb_downstream.c index 689d2020718..21af230338e 100644 --- a/src/flb_downstream.c +++ b/src/flb_downstream.c @@ -188,7 +188,7 @@ static int prepare_destroy_conn(struct flb_connection *connection) flb_trace("[downstream] destroy connection #%i to %s", connection->fd, flb_connection_get_remote_address(connection)); - if(MK_EVENT_IS_REGISTERED((&connection->event))) { + if (MK_EVENT_IS_REGISTERED((&connection->event))) { mk_event_del(connection->evl, &connection->event); } From d14fd217f78fdabbddfbe5f24c62982562fb1aa7 Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Mon, 5 Jun 2023 15:10:09 -0500 Subject: [PATCH 069/315] in_kubernetes_filter: fix leak on exception Signed-off-by: Eduardo Silva --- plugins/filter_kubernetes/kube_meta.c | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/filter_kubernetes/kube_meta.c b/plugins/filter_kubernetes/kube_meta.c index bd6a51979db..fbad2bb0248 100644 --- a/plugins/filter_kubernetes/kube_meta.c +++ b/plugins/filter_kubernetes/kube_meta.c @@ -373,6 +373,7 @@ static int get_meta_info_from_request(struct flb_kube *ctx, ret = refresh_token_if_needed(ctx); if (ret == -1) { flb_plg_error(ctx->ins, "failed to refresh token"); + flb_upstream_conn_release(u_conn); return -1; } From 5aa4196b79f3dd813d17394041543b57c7b9b707 Mon Sep 17 00:00:00 2001 From: DavidKorczynski Date: Mon, 3 Jul 2023 11:57:33 +0100 Subject: [PATCH 070/315] workflows: enable sarif output for CIFuzz (#7630) * workflows: enable sarif output for CIFuzz This will make it easier to interpret the output of CIFuzz by making it possible to view the result in the Github security page. Signed-off-by: David Korczynski * workflows: cifuzz: add sarif category Signed-off-by: David Korczynski --------- Signed-off-by: David Korczynski --- .github/workflows/pr-fuzz.yaml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.github/workflows/pr-fuzz.yaml b/.github/workflows/pr-fuzz.yaml index ddd5971ebc3..79371ed5dab 100644 --- a/.github/workflows/pr-fuzz.yaml +++ b/.github/workflows/pr-fuzz.yaml @@ -24,9 +24,18 @@ jobs: fuzz-seconds: 600 dry-run: false language: c + output-sarif: true - name: Upload Crash uses: actions/upload-artifact@v3 if: failure() && steps.build.outcome == 'success' with: name: artifacts path: ./out/artifacts + - name: Upload Sarif + if: always() && steps.build.outcome == 'success' + uses: github/codeql-action/upload-sarif@v2 + with: + # Path to SARIF file relative to the root of the repository + sarif_file: cifuzz-sarif/results.sarif + checkout_path: cifuzz-sarif + category: CIFuzz From 8861650db2e832670b9e32c1dadc2cad3a72bc39 Mon Sep 17 00:00:00 2001 From: David Korczynski Date: Mon, 26 Jun 2023 06:39:38 -0700 Subject: [PATCH 071/315] tests: internal: fuzzers: add cmetrics decoder fuzzer Signed-off-by: David Korczynski --- tests/internal/fuzzers/CMakeLists.txt | 1 + tests/internal/fuzzers/cmetrics_decode_fuzz.c | 57 +++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 tests/internal/fuzzers/cmetrics_decode_fuzz.c diff --git a/tests/internal/fuzzers/CMakeLists.txt b/tests/internal/fuzzers/CMakeLists.txt index 721b957e35f..0ace2db9898 100644 --- a/tests/internal/fuzzers/CMakeLists.txt +++ b/tests/internal/fuzzers/CMakeLists.txt @@ -3,6 +3,7 @@ set(UNIT_TESTS_FILES aws_credentials_fuzzer.c base64_fuzzer.c engine_fuzzer.c + cmetrics_decode_fuzz.c config_fuzzer.c config_random_fuzzer.c ctrace_fuzzer.c diff --git a/tests/internal/fuzzers/cmetrics_decode_fuzz.c b/tests/internal/fuzzers/cmetrics_decode_fuzz.c new file mode 100644 index 00000000000..78f2bc03111 --- /dev/null +++ b/tests/internal/fuzzers/cmetrics_decode_fuzz.c @@ -0,0 +1,57 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Fluent Bit + * ========== + * Copyright (C) 2015-2023 The Fluent Bit Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + + +int +LLVMFuzzerTestOneInput(const uint8_t * data, size_t size) +{ + struct cfl_list decoded_contexts; + struct cmt *cmt = NULL; + size_t off = 0; + int result; + + /* At least one byte is needed for deciding which decoder to use */ + if (size < 1) { + return 0; + } + + uint8_t decider = data[0] % 2; + + /* Adjust data pointer since the first byte is used */ + data += 1; + size -= 1; + + /* Fuzz a given decoder */ + if (decider == 0) { + result = cmt_decode_opentelemetry_create(&decoded_contexts, data, size, + &off); + if (result == CMT_DECODE_OPENTELEMETRY_SUCCESS) { + cmt_decode_opentelemetry_destroy (&decoded_contexts); + } + } + else if (decider == 1) { + result = cmt_decode_msgpack_create(&cmt, (char *) data, size, &off); + if (result == 0) { + cmt_destroy(cmt); + } + } + return 0; +} From 26b5d74a50922cb0a92092ff9caf005b48b77dd7 Mon Sep 17 00:00:00 2001 From: David Korczynski Date: Fri, 30 Jun 2023 06:29:34 -0700 Subject: [PATCH 072/315] tests: internal: fuzzers: move variable declaration Signed-off-by: David Korczynski --- tests/internal/fuzzers/cmetrics_decode_fuzz.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/internal/fuzzers/cmetrics_decode_fuzz.c b/tests/internal/fuzzers/cmetrics_decode_fuzz.c index 78f2bc03111..7ddd1ab2197 100644 --- a/tests/internal/fuzzers/cmetrics_decode_fuzz.c +++ b/tests/internal/fuzzers/cmetrics_decode_fuzz.c @@ -26,6 +26,7 @@ LLVMFuzzerTestOneInput(const uint8_t * data, size_t size) struct cfl_list decoded_contexts; struct cmt *cmt = NULL; size_t off = 0; + uint8_t decider; int result; /* At least one byte is needed for deciding which decoder to use */ @@ -33,7 +34,7 @@ LLVMFuzzerTestOneInput(const uint8_t * data, size_t size) return 0; } - uint8_t decider = data[0] % 2; + decider = data[0] % 2; /* Adjust data pointer since the first byte is used */ data += 1; From f0c266b55cc8e19ab93ef87040463c09db3893b0 Mon Sep 17 00:00:00 2001 From: David Korczynski Date: Fri, 30 Jun 2023 03:34:24 -0700 Subject: [PATCH 073/315] in_exec_wasi: fix possible NULL deref `tmpfile()` can return NULL and this is not checked for at the moment. If indeed it returns NULL then the call on line 70 `fileno(stdoutp)` will cause a NULL dereference. Signed-off-by: David Korczynski --- plugins/in_exec_wasi/in_exec_wasi.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/plugins/in_exec_wasi/in_exec_wasi.c b/plugins/in_exec_wasi/in_exec_wasi.c index 2515dd8584f..071aadee9d9 100644 --- a/plugins/in_exec_wasi/in_exec_wasi.c +++ b/plugins/in_exec_wasi/in_exec_wasi.c @@ -59,6 +59,11 @@ static int in_exec_wasi_collect(struct flb_input_instance *ins, size_t out_size = 0; struct flb_time out_time; + /* Validate the temporary file was created */ + if (stdoutp == NULL) { + return -1; + } + if (ctx->oneshot == FLB_TRUE) { ret = flb_pipe_r(ctx->ch_manager[0], &val, sizeof(val)); if (ret == -1) { From ce856fdfa2f7872985cfe4a67c97757c481573b7 Mon Sep 17 00:00:00 2001 From: David Korczynski Date: Fri, 30 Jun 2023 06:26:49 -0700 Subject: [PATCH 074/315] in_exec_wasi: add error message Signed-off-by: David Korczynski --- plugins/in_exec_wasi/in_exec_wasi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/in_exec_wasi/in_exec_wasi.c b/plugins/in_exec_wasi/in_exec_wasi.c index 071aadee9d9..704af9037a6 100644 --- a/plugins/in_exec_wasi/in_exec_wasi.c +++ b/plugins/in_exec_wasi/in_exec_wasi.c @@ -61,6 +61,7 @@ static int in_exec_wasi_collect(struct flb_input_instance *ins, /* Validate the temporary file was created */ if (stdoutp == NULL) { + flb_plg_error(ctx->ins, "failed to created temporary file"); return -1; } From 4e2dafd57e96d1d40c9bad0519d68088473142c6 Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Mon, 10 Jul 2023 18:31:22 -0700 Subject: [PATCH 075/315] upstream: fix logic to restrict number of connections In the previous version a new option called net.max_worker_connections was introduced to provide control around the maximum number of allowed TCP connections per worker inside an output plugin, the logic was wrong. In the upstream logic, connections are linked to one of these lists: - av_queue : connections ready to be used (available) - busy_queue: connections that are busy (someone is using them) - drop_queue: connections in the cleanup phase (to be drop) Fluent Bit don't create connections ahead of time, just on demand. When a connection is created is placed into the busy_queue, when is not longer needed one of these things happen: - if keepalive is enabled (default), the connection is moved to the 'av_queue'. - if keepalive is disabled, the connection is moved to 'drop_queue' then is closed and destroyed. Based on the logic described above, to limit the number of total connections in the worker, we only need to count the number of connections linked into the 'busy_queue' list because if there are connections available 'av_queue' it won't create a one. This patch fixes the logic by only using the busy_queue to count the limit. Signed-off-by: Eduardo Silva --- src/flb_upstream.c | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/src/flb_upstream.c b/src/flb_upstream.c index 03f9e805b4b..b46388ebf30 100644 --- a/src/flb_upstream.c +++ b/src/flb_upstream.c @@ -636,11 +636,30 @@ struct flb_connection *flb_upstream_conn_get(struct flb_upstream *u) /* If the upstream is limited by max connections, check current state */ if (u->base.net.max_worker_connections > 0) { - flb_stream_acquire_lock(&u->base, FLB_TRUE); - - total_connections = mk_list_size(&uq->av_queue); - total_connections += mk_list_size(&uq->busy_queue); + /* + * Connections are linked to one of these lists: + * + * - av_queue : connections ready to be used (available) + * - busy_queue: connections that are busy (someone is using them) + * - drop_queue: connections in the cleanup phase (to be drop) + * + * Fluent Bit don't create connections ahead of time, just on demand. When + * a connection is created is placed into the busy_queue, when is not longer + * needed one of these things happen: + * + * - if keepalive is enabled (default), the connection is moved to the 'av_queue'. + * - if keepalive is disabled, the connection is moved to 'drop_queue' then is + * closed and destroyed. + * + * Based on the logic described above, to limit the number of total connections + * in the worker, we only need to count the number of connections linked into + * the 'busy_queue' list because if there are connections available 'av_queue' it + * won't create a one. + */ + /* Count the number of relevant connections */ + flb_stream_acquire_lock(&u->base, FLB_TRUE); + total_connections = mk_list_size(&uq->busy_queue); flb_stream_release_lock(&u->base); if (total_connections >= u->base.net.max_worker_connections) { @@ -701,8 +720,9 @@ struct flb_connection *flb_upstream_conn_get(struct flb_upstream *u) } } - /* There are keepalive connections available or - * keepalive is disable so we need to create a new one + /* + * There are no keepalive connections available or keepalive is disabled + * so we need to create a new one. */ if (conn == NULL) { conn = create_conn(u); From 736d7cd97ad6742824f6e22367d3f835c57b63c2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 12 Jul 2023 09:13:34 +0100 Subject: [PATCH 076/315] workflows: bump helm/kind-action from 1.7.0 to 1.8.0 (#7687) Bumps [helm/kind-action](https://github.com/helm/kind-action) from 1.7.0 to 1.8.0. - [Release notes](https://github.com/helm/kind-action/releases) - [Commits](https://github.com/helm/kind-action/compare/v1.7.0...v1.8.0) --- updated-dependencies: - dependency-name: helm/kind-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/call-run-integration-test.yaml | 2 +- .github/workflows/call-test-images.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/call-run-integration-test.yaml b/.github/workflows/call-run-integration-test.yaml index 9e109d6ef75..96a7317d61a 100644 --- a/.github/workflows/call-run-integration-test.yaml +++ b/.github/workflows/call-run-integration-test.yaml @@ -228,7 +228,7 @@ jobs: bats-version: 1.9.0 - name: Create k8s Kind Cluster - uses: helm/kind-action@v1.7.0 + uses: helm/kind-action@v1.8.0 with: node_image: kindest/node:${{ matrix.k8s-release }} cluster_name: kind diff --git a/.github/workflows/call-test-images.yaml b/.github/workflows/call-test-images.yaml index d536c00f57e..61a78cbc188 100644 --- a/.github/workflows/call-test-images.yaml +++ b/.github/workflows/call-test-images.yaml @@ -182,7 +182,7 @@ jobs: ref: ${{ inputs.ref }} - name: Create k8s Kind Cluster - uses: helm/kind-action@v1.7.0 + uses: helm/kind-action@v1.8.0 - name: Set up Helm uses: azure/setup-helm@v3.5 From d6562d57a05e78ef4b0ced15248f90b9e3cb3ab3 Mon Sep 17 00:00:00 2001 From: Hiroshi Hatake Date: Thu, 13 Jul 2023 03:53:34 +0900 Subject: [PATCH 077/315] out_chronicle: Implement Google Chronicle output plugin (#7232) For the first revision, we'll provide log_key and one-by-one line JSON version like as out_loki plugin. --------- Signed-off-by: Hiroshi Hatake --- CMakeLists.txt | 1 + cmake/windows-setup.cmake | 1 + plugins/CMakeLists.txt | 1 + plugins/out_chronicle/CMakeLists.txt | 6 + plugins/out_chronicle/chronicle.c | 962 +++++++++++++++++++++++++ plugins/out_chronicle/chronicle.h | 96 +++ plugins/out_chronicle/chronicle_conf.c | 421 +++++++++++ plugins/out_chronicle/chronicle_conf.h | 29 + 8 files changed, 1517 insertions(+) create mode 100644 plugins/out_chronicle/CMakeLists.txt create mode 100644 plugins/out_chronicle/chronicle.c create mode 100644 plugins/out_chronicle/chronicle.h create mode 100644 plugins/out_chronicle/chronicle_conf.c create mode 100644 plugins/out_chronicle/chronicle_conf.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 6672ad01206..4a49cca8d25 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -261,6 +261,7 @@ option(FLB_OUT_PROMETHEUS_REMOTE_WRITE "Enable Prometheus remote write plugin" option(FLB_OUT_S3 "Enable AWS S3 output plugin" Yes) option(FLB_OUT_VIVO_EXPORTER "Enabel Vivo exporter output plugin" Yes) option(FLB_OUT_WEBSOCKET "Enable Websocket output plugin" Yes) +option(FLB_OUT_CHRONICLE "Enable Google Chronicle output plugin" Yes) option(FLB_FILTER_ALTER_SIZE "Enable alter_size filter" Yes) option(FLB_FILTER_AWS "Enable aws filter" Yes) option(FLB_FILTER_ECS "Enable AWS ECS filter" Yes) diff --git a/cmake/windows-setup.cmake b/cmake/windows-setup.cmake index 853d1cda4dd..dbd7f4a4a2d 100644 --- a/cmake/windows-setup.cmake +++ b/cmake/windows-setup.cmake @@ -71,6 +71,7 @@ if(FLB_WINDOWS_DEFAULTS) set(FLB_OUT_AZURE_KUSTO Yes) set(FLB_OUT_BIGQUERY No) set(FLB_OUT_COUNTER Yes) + set(FLB_OUT_CHRONICLE Yes) set(FLB_OUT_DATADOG Yes) set(FLB_OUT_ES Yes) set(FLB_OUT_EXIT No) diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index ef92b37c6e7..2715876119d 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -332,6 +332,7 @@ REGISTER_OUT_PLUGIN("out_prometheus_exporter") REGISTER_OUT_PLUGIN("out_prometheus_remote_write") REGISTER_OUT_PLUGIN("out_s3") REGISTER_OUT_PLUGIN("out_vivo_exporter") +REGISTER_OUT_PLUGIN("out_chronicle") # FILTERS # ======= diff --git a/plugins/out_chronicle/CMakeLists.txt b/plugins/out_chronicle/CMakeLists.txt new file mode 100644 index 00000000000..ca91803055b --- /dev/null +++ b/plugins/out_chronicle/CMakeLists.txt @@ -0,0 +1,6 @@ +set(src + chronicle_conf.c + chronicle.c + ) + +FLB_PLUGIN(out_chronicle "${src}" "") diff --git a/plugins/out_chronicle/chronicle.c b/plugins/out_chronicle/chronicle.c new file mode 100644 index 00000000000..479dd803566 --- /dev/null +++ b/plugins/out_chronicle/chronicle.c @@ -0,0 +1,962 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Fluent Bit + * ========== + * Copyright (C) 2015-2023 The Fluent Bit Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "chronicle.h" +#include "chronicle_conf.h" + +// TODO: The following code is copied from the Stackdriver plugin and should be +// factored into common library functions. + +/* + * Base64 Encoding in JWT must: + * + * - remove any trailing padding '=' character + * - replace '+' with '-' + * - replace '/' with '_' + * + * ref: https://www.rfc-editor.org/rfc/rfc7515.txt Appendix C + */ +int chronicle_jwt_base64_url_encode(unsigned char *out_buf, size_t out_size, + unsigned char *in_buf, size_t in_size, + size_t *olen) + +{ + int i; + size_t len; + int result; + + /* do normal base64 encoding */ + result = flb_base64_encode((unsigned char *) out_buf, out_size - 1, + &len, in_buf, in_size); + if (result != 0) { + return -1; + } + + /* Replace '+' and '/' characters */ + for (i = 0; i < len && out_buf[i] != '='; i++) { + if (out_buf[i] == '+') { + out_buf[i] = '-'; + } + else if (out_buf[i] == '/') { + out_buf[i] = '_'; + } + } + + /* Now 'i' becomes the new length */ + *olen = i; + return 0; +} + +static int chronicle_jwt_encode(struct flb_chronicle *ctx, + char *payload, char *secret, + char **out_signature, size_t *out_size) +{ + int ret; + int len; + int buf_size; + size_t olen; + char *buf; + char *sigd; + char *headers = "{\"alg\": \"RS256\", \"typ\": \"JWT\"}"; + unsigned char sha256_buf[32] = {0}; + flb_sds_t out; + unsigned char sig[256] = {0}; + size_t sig_len; + + buf_size = (strlen(payload) + strlen(secret)) * 2; + buf = flb_malloc(buf_size); + if (!buf) { + flb_errno(); + return -1; + } + + /* Encode header */ + len = strlen(headers); + ret = flb_base64_encode((unsigned char *) buf, buf_size - 1, + &olen, (unsigned char *) headers, len); + if (ret != 0) { + flb_free(buf); + + return ret; + } + + /* Create buffer to store JWT */ + out = flb_sds_create_size(2048); + if (!out) { + flb_errno(); + flb_free(buf); + return -1; + } + + /* Append header */ + flb_sds_cat(out, buf, olen); + flb_sds_cat(out, ".", 1); + + /* Encode Payload */ + len = strlen(payload); + chronicle_jwt_base64_url_encode((unsigned char *) buf, buf_size, + (unsigned char *) payload, len, &olen); + + /* Append Payload */ + flb_sds_cat(out, buf, olen); + + /* do sha256() of base64(header).base64(payload) */ + ret = flb_hash_simple(FLB_HASH_SHA256, + (unsigned char *) out, flb_sds_len(out), + sha256_buf, sizeof(sha256_buf)); + + if (ret != FLB_CRYPTO_SUCCESS) { + flb_plg_error(ctx->ins, "error hashing token"); + flb_free(buf); + flb_sds_destroy(out); + return -1; + } + + len = strlen(secret); + sig_len = sizeof(sig); + + ret = flb_crypto_sign_simple(FLB_CRYPTO_PRIVATE_KEY, + FLB_CRYPTO_PADDING_PKCS1, + FLB_HASH_SHA256, + (unsigned char *) secret, len, + sha256_buf, sizeof(sha256_buf), + sig, &sig_len); + + if (ret != FLB_CRYPTO_SUCCESS) { + flb_plg_error(ctx->ins, "error creating RSA context"); + flb_free(buf); + flb_sds_destroy(out); + return -1; + } + + sigd = flb_malloc(2048); + if (!sigd) { + flb_errno(); + flb_free(buf); + flb_sds_destroy(out); + return -1; + } + + chronicle_jwt_base64_url_encode((unsigned char *) sigd, 2048, sig, 256, &olen); + + flb_sds_cat(out, ".", 1); + flb_sds_cat(out, sigd, olen); + + *out_signature = out; + *out_size = flb_sds_len(out); + + flb_free(buf); + flb_free(sigd); + + return 0; +} + +/* Create a new oauth2 context and get a oauth2 token */ +static int chronicle_get_oauth2_token(struct flb_chronicle *ctx) +{ + int ret; + char *token; + char *sig_data; + size_t sig_size; + time_t issued; + time_t expires; + char payload[1024]; + + /* Clear any previous oauth2 payload content */ + flb_oauth2_payload_clear(ctx->o); + + /* JWT encode for oauth2 */ + issued = time(NULL); + expires = issued + FLB_CHRONICLE_TOKEN_REFRESH; + + snprintf(payload, sizeof(payload) - 1, + "{\"iss\": \"%s\", \"scope\": \"%s\", " + "\"aud\": \"%s\", \"exp\": %lu, \"iat\": %lu}", + ctx->oauth_credentials->client_email, FLB_CHRONICLE_SCOPE, + FLB_CHRONICLE_AUTH_URL, + expires, issued); + + /* Compose JWT signature */ + ret = chronicle_jwt_encode(ctx, payload, ctx->oauth_credentials->private_key, + &sig_data, &sig_size); + if (ret != 0) { + flb_plg_error(ctx->ins, "JWT signature generation failed"); + return -1; + } + + flb_plg_debug(ctx->ins, "JWT signature:\n%s", sig_data); + + ret = flb_oauth2_payload_append(ctx->o, + "grant_type", -1, + "urn%3Aietf%3Aparams%3Aoauth%3A" + "grant-type%3Ajwt-bearer", -1); + if (ret == -1) { + flb_plg_error(ctx->ins, "error appending oauth2 params"); + flb_sds_destroy(sig_data); + return -1; + } + + ret = flb_oauth2_payload_append(ctx->o, + "assertion", -1, + sig_data, sig_size); + if (ret == -1) { + flb_plg_error(ctx->ins, "error appending oauth2 params"); + flb_sds_destroy(sig_data); + return -1; + } + flb_sds_destroy(sig_data); + + /* Retrieve access token */ + token = flb_oauth2_token_get(ctx->o); + if (!token) { + flb_plg_error(ctx->ins, "error retrieving oauth2 access token"); + return -1; + } + + return 0; +} + +static flb_sds_t get_google_token(struct flb_chronicle *ctx) +{ + int ret = 0; + flb_sds_t output = NULL; + + if (pthread_mutex_lock(&ctx->token_mutex)){ + flb_plg_error(ctx->ins, "error locking mutex"); + return NULL; + } + + if (flb_oauth2_token_expired(ctx->o) == FLB_TRUE) { + ret = chronicle_get_oauth2_token(ctx); + } + + /* Copy string to prevent race conditions (get_oauth2 can free the string) */ + if (ret == 0) { + output = flb_sds_create(ctx->o->token_type); + flb_sds_printf(&output, " %s", ctx->o->access_token); + } + + if (pthread_mutex_unlock(&ctx->token_mutex)){ + flb_plg_error(ctx->ins, "error unlocking mutex"); + if (output) { + flb_sds_destroy(output); + } + return NULL; + } + + return output; +} + +static int validate_log_type(struct flb_chronicle *ctx, struct flb_config *config, + const char *body, size_t len) +{ + int ret = -1; + int root_type; + char *msgpack_buf = NULL; + size_t msgpack_size; + size_t off = 0; + msgpack_unpacked result; + int i, j, k; + msgpack_object key; + msgpack_object val; + msgpack_object root; + msgpack_object *array; + msgpack_object *supported_type; + int root_map_size; + int array_size = 0; + + + ret = flb_pack_json(body, len, + &msgpack_buf, &msgpack_size, + &root_type, NULL); + + if (ret != 0 || root_type != JSMN_OBJECT) { + flb_plg_error(ctx->ins, "json to msgpack conversion error"); + } + + ret = -1; + msgpack_unpacked_init(&result); + while (msgpack_unpack_next(&result, msgpack_buf, msgpack_size, &off) == MSGPACK_UNPACK_SUCCESS) { + if (result.data.type != MSGPACK_OBJECT_MAP) { + flb_plg_error(ctx->ins, "Invalid log_type payload"); + ret = -2; + + goto cleanup; + } + + root = result.data; + root_map_size = root.via.map.size; + + for (i = 0; i < root_map_size; i++) { + key = root.via.map.ptr[i].key; + val = root.via.map.ptr[i].val; + + if (val.type != MSGPACK_OBJECT_ARRAY) { + flb_plg_error(ctx->ins, "Invalid inner array type of log_type payload"); + ret = -2; + + goto cleanup; + } + + array = val.via.array.ptr; + array_size = val.via.array.size; + + for (j = 0; j < array_size; j++) { + supported_type = &array[j]; + + if (supported_type->type != MSGPACK_OBJECT_MAP) { + flb_plg_error(ctx->ins, "Invalid inner maps of log_type payload"); + ret = -2; + + continue; + } + + for (k = 0; k < supported_type->via.map.size; k++) { + key = supported_type->via.map.ptr[k].key; + val = supported_type->via.map.ptr[k].val; + + if (strncmp("logType", key.via.str.ptr, key.via.str.size) == 0) { + if (strncmp(ctx->log_type, val.via.bin.ptr, val.via.str.size) == 0) { + ret = 0; + goto cleanup; + } + } + } + } + } + } + +cleanup: + msgpack_unpacked_destroy(&result); + + /* release 'out_buf' if it was allocated */ + if (msgpack_buf) { + flb_free(msgpack_buf); + } + + return ret; +} + +static int check_chronicle_log_type(struct flb_chronicle *ctx, struct flb_config *config) +{ + int ret; + size_t b_sent; + flb_sds_t token; + struct flb_connection *u_conn; + struct flb_http_client *c; + + /* Get upstream connection */ + u_conn = flb_upstream_conn_get(ctx->u); + if (!u_conn) { + return -1; + } + + /* Get or renew Token */ + token = get_google_token(ctx); + + if (!token) { + flb_plg_error(ctx->ins, "cannot retrieve oauth2 token"); + flb_upstream_conn_release(u_conn); + return -1; + } + + /* Compose HTTP Client request */ + c = flb_http_client(u_conn, FLB_HTTP_GET, FLB_CHRONICLE_LOG_TYPE_ENDPOINT, + NULL, 0, NULL, 0, NULL, 0); + if (!c) { + flb_plg_error(ctx->ins, "cannot create HTTP client context"); + flb_upstream_conn_release(u_conn); + flb_sds_destroy(token); + + return -1; + } + + /* Chronicle supported types are growing. Not to specify the read limit. */ + flb_http_buffer_size(c, 0); + flb_http_add_header(c, "User-Agent", 10, "Fluent-Bit", 10); + flb_http_add_header(c, "Content-Type", 12, "application/json", 16); + + /* Compose and append Authorization header */ + flb_http_add_header(c, "Authorization", 13, token, flb_sds_len(token)); + + /* Send HTTP request */ + ret = flb_http_do(c, &b_sent); + + /* validate response */ + if (ret != 0) { + flb_plg_warn(ctx->ins, "http_do=%i", ret); + goto cleanup; + } + else { + /* The request was issued successfully, validate the 'error' field */ + flb_plg_debug(ctx->ins, "HTTP Status=%i", c->resp.status); + if (c->resp.status == 200) { + ret = validate_log_type(ctx, config, c->resp.payload, c->resp.payload_size); + if (ret != 0) { + flb_plg_error(ctx->ins, "Validate log_type is failed"); + goto cleanup; + } + } + else { + if (c->resp.payload && c->resp.payload_size > 0) { + /* we got an error */ + flb_plg_warn(ctx->ins, "response\n%s", c->resp.payload); + } + + goto cleanup; + } + } + +cleanup: + + /* Cleanup */ + flb_sds_destroy(token); + flb_http_client_destroy(c); + flb_upstream_conn_release(u_conn); + + return ret; +} + +static int cb_chronicle_init(struct flb_output_instance *ins, + struct flb_config *config, void *data) +{ + char *token; + int io_flags = FLB_IO_TLS; + struct flb_chronicle *ctx; + int ret; + + /* Create config context */ + ctx = flb_chronicle_conf_create(ins, config); + if (!ctx) { + flb_plg_error(ins, "configuration failed"); + return -1; + } + + flb_output_set_context(ins, ctx); + + /* Network mode IPv6 */ + if (ins->host.ipv6 == FLB_TRUE) { + io_flags |= FLB_IO_IPV6; + } + + /* Create mutex for acquiring oauth tokens (they are shared across flush coroutines) */ + pthread_mutex_init(&ctx->token_mutex, NULL); + + /* + * Create upstream context for Chronicle Streaming Inserts + * (no oauth2 service) + */ + ctx->u = flb_upstream_create_url(config, ctx->uri, + io_flags, ins->tls); + if (!ctx->u) { + flb_plg_error(ctx->ins, "upstream creation failed"); + return -1; + } + + /* Create oauth2 context */ + ctx->o = flb_oauth2_create(ctx->config, FLB_CHRONICLE_AUTH_URL, 3000); + if (!ctx->o) { + flb_plg_error(ctx->ins, "cannot create oauth2 context"); + return -1; + } + flb_output_upstream_set(ctx->u, ins); + + /* Get or renew the OAuth2 token */ + token = get_google_token(ctx); + + if (!token) { + flb_plg_warn(ctx->ins, "token retrieval failed"); + } + else { + flb_sds_destroy(token); + } + + ret = check_chronicle_log_type(ctx, config); + if (ret != 0) { + flb_plg_error(ctx->ins, "Validate log_type failed. '%s' is not supported. ret = %d", + ctx->log_type, ret); + return -1; + } + + return 0; +} + +static flb_sds_t flb_pack_msgpack_extract_log_key(void *out_context, uint64_t bytes, struct flb_log_event log_event) +{ + int i; + int map_size; + int check = FLB_FALSE; + int found = FLB_FALSE; + int log_key_missing = 0; + int ret; + struct flb_chronicle *ctx = out_context; + char *val_buf; + char *key_str = NULL; + size_t key_str_size = 0; + size_t msgpack_size = bytes + bytes / 4; + size_t val_offset = 0; + flb_sds_t out_buf; + msgpack_object map; + msgpack_object key; + msgpack_object val; + + /* Allocate buffer to store log_key contents */ + val_buf = flb_calloc(1, msgpack_size); + if (val_buf == NULL) { + flb_plg_error(ctx->ins, "Could not allocate enough " + "memory to read record"); + flb_errno(); + return NULL; + } + + /* Get the record/map */ + map = *log_event.body; + + if (map.type != MSGPACK_OBJECT_MAP) { + return NULL; + } + + map_size = map.via.map.size; + + /* Reset variables for found log_key and correct type */ + found = FLB_FALSE; + check = FLB_FALSE; + + /* Extract log_key from record and append to output buffer */ + for (i = 0; i < map_size; i++) { + key = map.via.map.ptr[i].key; + val = map.via.map.ptr[i].val; + + if (key.type == MSGPACK_OBJECT_BIN) { + key_str = (char *) key.via.bin.ptr; + key_str_size = key.via.bin.size; + check = FLB_TRUE; + } + if (key.type == MSGPACK_OBJECT_STR) { + key_str = (char *) key.via.str.ptr; + key_str_size = key.via.str.size; + check = FLB_TRUE; + } + + if (check == FLB_TRUE) { + if (strncmp(ctx->log_key, key_str, key_str_size) == 0) { + found = FLB_TRUE; + + /* + * Copy contents of value into buffer. Necessary to copy + * strings because flb_msgpack_to_json does not handle nested + * JSON gracefully and double escapes them. + */ + if (val.type == MSGPACK_OBJECT_BIN) { + memcpy(val_buf + val_offset, val.via.bin.ptr, val.via.bin.size); + val_offset += val.via.bin.size; + val_buf[val_offset] = '\0'; + val_offset++; + } + else if (val.type == MSGPACK_OBJECT_STR) { + memcpy(val_buf + val_offset, val.via.str.ptr, val.via.str.size); + val_offset += val.via.str.size; + val_buf[val_offset] = '\0'; + val_offset++; + } + else { + ret = flb_msgpack_to_json(val_buf + val_offset, + msgpack_size - val_offset, &val); + if (ret < 0) { + break; + } + val_offset += ret; + val_buf[val_offset] = '\0'; + val_offset++; + } + /* Exit early once log_key has been found for current record */ + break; + } + } + + /* If log_key was not found in the current record, mark log key as missing */ + if (found == FLB_FALSE) { + log_key_missing++; + } + } + + if (log_key_missing > 0) { + flb_plg_error(ctx->ins, "Could not find log_key '%s' in %d records", + ctx->log_key, log_key_missing); + } + + /* If nothing was read, destroy buffer */ + if (val_offset == 0) { + flb_free(val_buf); + return NULL; + } + val_buf[val_offset] = '\0'; + + /* Create output buffer to store contents */ + out_buf = flb_sds_create(val_buf); + if (out_buf == NULL) { + flb_plg_error(ctx->ins, "Error creating buffer to store log_key contents."); + flb_errno(); + } + flb_free(val_buf); + + return out_buf; +} + +static int chronicle_format(const void *data, size_t bytes, + const char *tag, size_t tag_len, + char **out_data, size_t *out_size, + struct flb_chronicle *ctx) +{ + int len; + int ret; + int array_size = 0; + size_t off = 0; + size_t last_off = 0; + size_t alloc_size = 0; + size_t s; + char time_formatted[255]; + /* Parameters for Timestamp */ + struct tm tm; + flb_sds_t out_buf; + struct flb_log_event_decoder log_decoder; + struct flb_log_event log_event; + msgpack_sbuffer mp_sbuf; + msgpack_packer mp_pck; + flb_sds_t log_text = NULL; + int log_text_size; + + /* Count number of records */ + ret = flb_log_event_decoder_init(&log_decoder, (char *) data, bytes); + + if (ret != FLB_EVENT_DECODER_SUCCESS) { + flb_plg_error(ctx->ins, + "Log event decoder initialization error : %d", ret); + + return -1; + } + + array_size = flb_mp_count(data, bytes); + + /* Create temporary msgpack buffer */ + msgpack_sbuffer_init(&mp_sbuf); + msgpack_packer_init(&mp_pck, &mp_sbuf, msgpack_sbuffer_write); + + /* + * Pack root map (unstructured log): + * see: https://cloud.google.com/chronicle/docs/reference/ingestion-api#request_body_2 + * { + * "customer_id": "c8c65bfa-5f2c-42d4-9189-64bb7b939f2c", + * "log_type": "BIND_DNS", + * "entries": [ + * { + * "log_text": "26-Feb-2019 13:35:02.187 client 10.120.20.32#4238: query: altostrat.com IN A + (203.0.113.102)", + * "ts_epoch_microseconds": 1551188102187000 + * }, + * { + * "log_text": "26-Feb-2019 13:37:04.523 client 10.50.100.33#1116: query: examplepetstore.com IN A + (203.0.113.102)", + * "ts_rfc3339": "2019-26-02T13:37:04.523-08:00" + * }, + * { + * "log_text": "26-Feb-2019 13:39:01.115 client 10.1.2.3#3333: query: www.example.com IN A + (203.0.113.102)" + * }, + * ] + * } + */ + msgpack_pack_map(&mp_pck, 3); + + msgpack_pack_str(&mp_pck, 11); + msgpack_pack_str_body(&mp_pck, "customer_id", 11); + + msgpack_pack_str(&mp_pck, strlen(ctx->customer_id)); + msgpack_pack_str_body(&mp_pck, ctx->customer_id, strlen(ctx->customer_id)); + + msgpack_pack_str(&mp_pck, 8); + msgpack_pack_str_body(&mp_pck, "log_type", 8); + + msgpack_pack_str(&mp_pck, strlen(ctx->log_type)); + msgpack_pack_str_body(&mp_pck, ctx->log_type, strlen(ctx->log_type)); + + msgpack_pack_str(&mp_pck, 7); + msgpack_pack_str_body(&mp_pck, "entries", 7); + + /* Append entries */ + msgpack_pack_array(&mp_pck, array_size); + + while ((ret = flb_log_event_decoder_next( + &log_decoder, + &log_event)) == FLB_EVENT_DECODER_SUCCESS) { + off = log_decoder.offset; + alloc_size = (off - last_off) + 128; /* JSON is larger than msgpack */ + last_off = off; + + /* + * Pack entries + * + * { + * "log_text": {...}, + * "ts_rfc3339": "..." + * } + * + */ + msgpack_pack_map(&mp_pck, 2); + + /* log_text */ + msgpack_pack_str(&mp_pck, 8); + msgpack_pack_str_body(&mp_pck, "log_text", 8); + if (ctx->log_key != NULL) { + log_text = flb_pack_msgpack_extract_log_key(ctx, bytes, log_event); + log_text_size = flb_sds_len(log_text); + } + else { + log_text = flb_msgpack_to_json_str(alloc_size, log_event.body); + log_text_size = strlen(log_text); + } + + if (log_text == NULL) { + flb_plg_error(ctx->ins, "Could not marshal msgpack to output string"); + return -1; + } + msgpack_pack_str(&mp_pck, log_text_size); + msgpack_pack_str_body(&mp_pck, log_text, log_text_size); + + if (ctx->log_key != NULL) { + flb_sds_destroy(log_text); + } + else { + flb_free(log_text); + } + /* timestamp */ + msgpack_pack_str(&mp_pck, 10); + msgpack_pack_str_body(&mp_pck, "ts_rfc3339", 10); + + gmtime_r(&log_event.timestamp.tm.tv_sec, &tm); + s = strftime(time_formatted, sizeof(time_formatted) - 1, + FLB_STD_TIME_FMT, &tm); + len = snprintf(time_formatted + s, sizeof(time_formatted) - 1 - s, + ".%03" PRIu64 "Z", + (uint64_t) log_event.timestamp.tm.tv_nsec); + s += len; + + msgpack_pack_str(&mp_pck, s); + msgpack_pack_str_body(&mp_pck, time_formatted, s); + } + + /* Convert from msgpack to JSON */ + out_buf = flb_msgpack_raw_to_json_sds(mp_sbuf.data, mp_sbuf.size); + + flb_log_event_decoder_destroy(&log_decoder); + msgpack_sbuffer_destroy(&mp_sbuf); + + if (!out_buf) { + flb_plg_error(ctx->ins, "error formatting JSON payload"); + return -1; + } + + *out_data = out_buf; + *out_size = flb_sds_len(out_buf); + + return 0; +} + +static void cb_chronicle_flush(struct flb_event_chunk *event_chunk, + struct flb_output_flush *out_flush, + struct flb_input_instance *i_ins, + void *out_context, + struct flb_config *config) +{ + (void) i_ins; + (void) config; + int ret; + int ret_code = FLB_RETRY; + size_t b_sent; + flb_sds_t token; + flb_sds_t payload_buf; + size_t payload_size; + struct flb_chronicle *ctx = out_context; + struct flb_connection *u_conn; + struct flb_http_client *c; + + flb_plg_trace(ctx->ins, "flushing bytes %zu", event_chunk->size); + + /* Get upstream connection */ + u_conn = flb_upstream_conn_get(ctx->u); + if (!u_conn) { + FLB_OUTPUT_RETURN(FLB_RETRY); + } + + /* Get or renew Token */ + token = get_google_token(ctx); + + if (!token) { + flb_plg_error(ctx->ins, "cannot retrieve oauth2 token"); + flb_upstream_conn_release(u_conn); + FLB_OUTPUT_RETURN(FLB_RETRY); + } + + /* Reformat msgpack to chronicle JSON payload */ + ret = chronicle_format(event_chunk->data, event_chunk->size, + event_chunk->tag, flb_sds_len(event_chunk->tag), + &payload_buf, &payload_size, ctx); + if (ret != 0) { + flb_upstream_conn_release(u_conn); + flb_sds_destroy(token); + FLB_OUTPUT_RETURN(FLB_RETRY); + } + + /* Compose HTTP Client request */ + c = flb_http_client(u_conn, FLB_HTTP_POST, ctx->endpoint, + payload_buf, payload_size, NULL, 0, NULL, 0); + if (!c) { + flb_plg_error(ctx->ins, "cannot create HTTP client context"); + flb_upstream_conn_release(u_conn); + flb_sds_destroy(token); + flb_sds_destroy(payload_buf); + FLB_OUTPUT_RETURN(FLB_RETRY); + } + + flb_http_buffer_size(c, 4192); + flb_http_add_header(c, "User-Agent", 10, "Fluent-Bit", 10); + flb_http_add_header(c, "Content-Type", 12, "application/json", 16); + + /* Compose and append Authorization header */ + flb_http_add_header(c, "Authorization", 13, token, flb_sds_len(token)); + + /* Send HTTP request */ + ret = flb_http_do(c, &b_sent); + + /* validate response */ + if (ret != 0) { + flb_plg_warn(ctx->ins, "http_do=%i", ret); + ret_code = FLB_RETRY; + } + else { + /* The request was issued successfully, validate the 'error' field */ + flb_plg_debug(ctx->ins, "HTTP Status=%i", c->resp.status); + if (c->resp.status == 200) { + ret_code = FLB_OK; + } + else { + if (c->resp.payload && c->resp.payload_size > 0) { + /* we got an error */ + flb_plg_warn(ctx->ins, "response\n%s", c->resp.payload); + } + ret_code = FLB_RETRY; + } + } + + /* Cleanup */ + flb_sds_destroy(payload_buf); + flb_sds_destroy(token); + flb_http_client_destroy(c); + flb_upstream_conn_release(u_conn); + + /* Done */ + FLB_OUTPUT_RETURN(ret_code); +} + +static int cb_chronicle_exit(void *data, struct flb_config *config) +{ + struct flb_chronicle *ctx = data; + + if (!ctx) { + return -1; + } + + if (ctx->u) { + flb_upstream_destroy(ctx->u); + } + + flb_chronicle_conf_destroy(ctx); + return 0; +} + +static struct flb_config_map config_map[] = { + { + FLB_CONFIG_MAP_STR, "google_service_credentials", (char *)NULL, + 0, FLB_TRUE, offsetof(struct flb_chronicle, credentials_file), + "Set the path for the google service credentials file" + }, + // set in flb_chronicle_oauth_credentials + { + FLB_CONFIG_MAP_STR, "service_account_email", (char *)NULL, + 0, FLB_FALSE, 0, + "Set the service account email" + }, + // set in flb_chronicle_oauth_credentials + { + FLB_CONFIG_MAP_STR, "service_account_secret", (char *)NULL, + 0, FLB_FALSE, 0, + "Set the service account secret" + }, + { + FLB_CONFIG_MAP_STR, "project_id", (char *)NULL, + 0, FLB_TRUE, offsetof(struct flb_chronicle, project_id), + "Set the project id" + }, + { + FLB_CONFIG_MAP_STR, "customer_id", (char *)NULL, + 0, FLB_TRUE, offsetof(struct flb_chronicle, customer_id), + "Set the customer id" + }, + { + FLB_CONFIG_MAP_STR, "log_type", (char *)NULL, + 0, FLB_TRUE, offsetof(struct flb_chronicle, log_type), + "Set the log type" + }, + { + FLB_CONFIG_MAP_STR, "region", (char *)NULL, + 0, FLB_TRUE, offsetof(struct flb_chronicle, region), + "Set the region" + }, + { + FLB_CONFIG_MAP_STR, "log_key", NULL, + 0, FLB_TRUE, offsetof(struct flb_chronicle, log_key), + "Set the log key" + }, + /* EOF */ + {0} +}; + +struct flb_output_plugin out_chronicle_plugin = { + .name = "chronicle", + .description = "Send logs to Google Chronicle as unstructured log", + .cb_init = cb_chronicle_init, + .cb_flush = cb_chronicle_flush, + .cb_exit = cb_chronicle_exit, + .config_map = config_map, + /* Plugin flags */ + .flags = FLB_OUTPUT_NET | FLB_IO_TLS, +}; diff --git a/plugins/out_chronicle/chronicle.h b/plugins/out_chronicle/chronicle.h new file mode 100644 index 00000000000..0243223f0ab --- /dev/null +++ b/plugins/out_chronicle/chronicle.h @@ -0,0 +1,96 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Fluent Bit + * ========== + * Copyright (C) 2015-2023 The Fluent Bit Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLB_OUT_CHRONICLE +#define FLB_OUT_CHRONICLE + +#include +#include +#include +#include + +/* refresh token every 50 minutes */ +#define FLB_CHRONICLE_TOKEN_REFRESH 3000 + +/* Timestamp format */ +#define FLB_STD_TIME_FMT "%Y-%m-%dT%H:%M:%S" + +/* Chronicle unstructureed logs oauth scope */ +#define FLB_CHRONICLE_SCOPE "https://www.googleapis.com/auth/malachite-ingestion" + +/* Chronicle authorization URL */ +#define FLB_CHRONICLE_AUTH_URL "https://oauth2.googleapis.com/token" + +#define FLB_CHRONICLE_UNSTRUCTURED_ENDPOINT "/v2/unstructuredlogentries:batchCreate" +#define FLB_CHRONICLE_LOG_TYPE_ENDPOINT "/v2/logtypes" +#define FLB_CHRONICLE_URL_BASE "https://malachiteingestion-pa.googleapis.com" +#define FLB_CHRONICLE_URL_BASE_EU "https://europe-malachiteingestion-pa.googleapis.com" +#define FLB_CHRONICLE_URL_BASE_UK "https://europe-west2-malachiteingestion-pa.googleapis.com" +#define FLB_CHRONICLE_URL_BASE_ASIA "https://asia-southeast1-malachiteingestion-pa.googleapis.com" + +struct flb_chronicle_oauth_credentials { + /* parsed credentials file */ + flb_sds_t type; + flb_sds_t project_id; + flb_sds_t private_key_id; + flb_sds_t private_key; + flb_sds_t client_email; + flb_sds_t client_id; + flb_sds_t auth_uri; + flb_sds_t token_uri; +}; + +struct flb_chronicle { + /* credentials */ + flb_sds_t credentials_file; + + struct flb_chronicle_oauth_credentials *oauth_credentials; + + /* chronicle configuration */ + flb_sds_t project_id; + flb_sds_t customer_id; + flb_sds_t log_type; + + flb_sds_t uri; + flb_sds_t health_uri; + flb_sds_t endpoint; + flb_sds_t region; + flb_sds_t log_key; + + int json_date_format; + flb_sds_t json_date_key; + flb_sds_t date_key; + + /* oauth2 context */ + struct flb_oauth2 *o; + + /* mutex for acquiring oauth tokens */ + pthread_mutex_t token_mutex; + + /* Upstream connection to the backend server */ + struct flb_upstream *u; + + /* Fluent Bit context */ + struct flb_config *config; + + /* Plugin output instance reference */ + struct flb_output_instance *ins; +}; + +#endif diff --git a/plugins/out_chronicle/chronicle_conf.c b/plugins/out_chronicle/chronicle_conf.c new file mode 100644 index 00000000000..5d6cdf9b230 --- /dev/null +++ b/plugins/out_chronicle/chronicle_conf.c @@ -0,0 +1,421 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Fluent Bit + * ========== + * Copyright (C) 2015-2023 The Fluent Bit Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "chronicle.h" +#include "chronicle_conf.h" + + +static inline int key_cmp(char *str, int len, char *cmp) { + + if (strlen(cmp) != len) { + return -1; + } + + return strncasecmp(str, cmp, len); +} + +static int flb_chronicle_read_credentials_file(struct flb_chronicle *ctx, + char *creds, + struct flb_chronicle_oauth_credentials *ctx_creds) +{ + int i; + int ret; + int len; + int key_len; + int val_len; + int tok_size = 32; + char *buf; + char *key; + char *val; + flb_sds_t tmp; + struct stat st; + jsmn_parser parser; + jsmntok_t *t; + jsmntok_t *tokens; + + /* Validate credentials path */ + ret = stat(creds, &st); + if (ret == -1) { + flb_errno(); + flb_plg_error(ctx->ins, "cannot open credentials file: %s", + creds); + return -1; + } + + if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) { + flb_plg_error(ctx->ins, "credentials file " + "is not a valid file: %s", creds); + return -1; + } + + /* Read file content */ + buf = mk_file_to_buffer(creds); + if (!buf) { + flb_plg_error(ctx->ins, "error reading credentials file: %s", + creds); + return -1; + } + + /* Parse content */ + jsmn_init(&parser); + tokens = flb_calloc(1, sizeof(jsmntok_t) * tok_size); + if (!tokens) { + flb_errno(); + flb_free(buf); + return -1; + } + + ret = jsmn_parse(&parser, buf, st.st_size, tokens, tok_size); + if (ret <= 0) { + flb_plg_error(ctx->ins, "invalid JSON credentials file: %s", + creds); + flb_free(buf); + flb_free(tokens); + return -1; + } + + t = &tokens[0]; + if (t->type != JSMN_OBJECT) { + flb_plg_error(ctx->ins, "invalid JSON map on file: %s", + creds); + flb_free(buf); + flb_free(tokens); + return -1; + } + + /* Parse JSON tokens */ + for (i = 1; i < ret; i++) { + t = &tokens[i]; + if (t->type != JSMN_STRING) { + continue; + } + + if (t->start == -1 || t->end == -1 || (t->start == 0 && t->end == 0)){ + break; + } + + /* Key */ + key = buf + t->start; + key_len = (t->end - t->start); + + /* Value */ + i++; + t = &tokens[i]; + val = buf + t->start; + val_len = (t->end - t->start); + + if (key_cmp(key, key_len, "type") == 0) { + ctx_creds->type = flb_sds_create_len(val, val_len); + } + else if (key_cmp(key, key_len, "project_id") == 0) { + ctx_creds->project_id = flb_sds_create_len(val, val_len); + } + else if (key_cmp(key, key_len, "private_key_id") == 0) { + ctx_creds->private_key_id = flb_sds_create_len(val, val_len); + } + else if (key_cmp(key, key_len, "private_key") == 0) { + tmp = flb_sds_create_len(val, val_len); + if (tmp) { + /* Unescape private key */ + len = flb_sds_len(tmp); + ctx_creds->private_key = flb_sds_create_size(len); + flb_unescape_string(tmp, len, + &ctx_creds->private_key); + flb_sds_destroy(tmp); + } + } + else if (key_cmp(key, key_len, "client_email") == 0) { + ctx_creds->client_email = flb_sds_create_len(val, val_len); + } + else if (key_cmp(key, key_len, "client_id") == 0) { + ctx_creds->client_id = flb_sds_create_len(val, val_len); + } + else if (key_cmp(key, key_len, "auth_uri") == 0) { + ctx_creds->auth_uri = flb_sds_create_len(val, val_len); + } + else if (key_cmp(key, key_len, "token_uri") == 0) { + ctx_creds->token_uri = flb_sds_create_len(val, val_len); + } + } + + flb_free(buf); + flb_free(tokens); + + return 0; +} + + +struct flb_chronicle *flb_chronicle_conf_create(struct flb_output_instance *ins, + struct flb_config *config) +{ + int ret; + const char *tmp; + struct flb_chronicle *ctx; + struct flb_chronicle_oauth_credentials *creds; + + /* Allocate config context */ + ctx = flb_calloc(1, sizeof(struct flb_chronicle)); + if (!ctx) { + flb_errno(); + return NULL; + } + ctx->ins = ins; + ctx->config = config; + + ret = flb_output_config_map_set(ins, (void *)ctx); + if (ret == -1) { + flb_plg_error(ins, "unable to load configuration"); + flb_free(ctx); + return NULL; + } + + /* Lookup credentials file */ + creds = flb_calloc(1, sizeof(struct flb_chronicle_oauth_credentials)); + if (!creds) { + flb_errno(); + flb_free(ctx); + return NULL; + } + ctx->oauth_credentials = creds; + + if (ctx->credentials_file == NULL) { + tmp = getenv("GOOGLE_SERVICE_CREDENTIALS"); + if (tmp) { + ctx->credentials_file = flb_sds_create(tmp); + } + } + + if (ctx->credentials_file) { + ret = flb_chronicle_read_credentials_file(ctx, + ctx->credentials_file, + ctx->oauth_credentials); + if (ret != 0) { + flb_chronicle_conf_destroy(ctx); + return NULL; + } + } + else if (!ctx->credentials_file) { + /* + * If no credentials file has been defined, do manual lookup of the + * client email and the private key. + */ + + /* Service Account Email */ + tmp = flb_output_get_property("service_account_email", ins); + if (tmp) { + creds->client_email = flb_sds_create(tmp); + } + else { + tmp = getenv("SERVICE_ACCOUNT_EMAIL"); + if (tmp) { + creds->client_email = flb_sds_create(tmp); + } + } + + /* Service Account Secret */ + tmp = flb_output_get_property("service_account_secret", ins); + if (tmp) { + creds->private_key = flb_sds_create(tmp); + } + else { + tmp = getenv("SERVICE_ACCOUNT_SECRET"); + if (tmp) { + creds->private_key = flb_sds_create(tmp); + } + } + + if (!creds->client_email) { + flb_plg_error(ctx->ins, "service_account_email/client_email is not defined"); + flb_chronicle_conf_destroy(ctx); + return NULL; + } + + if (!creds->private_key) { + flb_plg_error(ctx->ins, "service_account_secret/private_key is not defined"); + flb_chronicle_conf_destroy(ctx); + return NULL; + } + } + + /* config: 'project_id' */ + if (ctx->project_id == NULL) { + if (creds->project_id) { + /* flb_config_map_destroy uses the pointer within the config_map struct to + * free the value so if we assign it here it is safe to free later with the + * creds struct. If we do not we will leak here. + */ + ctx->project_id = creds->project_id; + if (!ctx->project_id) { + flb_plg_error(ctx->ins, + "failed extracting 'project_id' from credentials."); + flb_chronicle_conf_destroy(ctx); + return NULL; + } + } + else { + flb_plg_error(ctx->ins, + "no 'project_id' configured or present in credentials."); + flb_chronicle_conf_destroy(ctx); + return NULL; + } + } + + /* config: 'customer_id' */ + if (ctx->customer_id == NULL) { + flb_plg_error(ctx->ins, "property 'customer_id' is not defined"); + flb_chronicle_conf_destroy(ctx); + return NULL; + } + + /* config: 'log_type' */ + if (ctx->log_type == NULL) { + flb_plg_error(ctx->ins, "property 'log_type' is not defined"); + flb_chronicle_conf_destroy(ctx); + return NULL; + } + + /* Date key */ + ctx->date_key = ctx->json_date_key; + tmp = flb_output_get_property("json_date_key", ins); + if (tmp) { + /* Just check if we have to disable it */ + if (flb_utils_bool(tmp) == FLB_FALSE) { + ctx->date_key = NULL; + } + } + + /* Date format for JSON output */ + ctx->json_date_format = FLB_PACK_JSON_DATE_ISO8601; + tmp = flb_output_get_property("json_date_format", ins); + if (tmp) { + ret = flb_pack_to_json_date_type(tmp); + if (ret == -1) { + flb_plg_error(ctx->ins, "invalid json_date_format '%s'. ", tmp); + return NULL; + } + else { + ctx->json_date_format = ret; + } + } + + /* Create the target endpoint URI */ + ctx->endpoint = flb_sds_create_size(sizeof(FLB_CHRONICLE_UNSTRUCTURED_ENDPOINT)); + if (!ctx->endpoint) { + flb_errno(); + flb_chronicle_conf_destroy(ctx); + return NULL; + } + ctx->endpoint = flb_sds_printf(&ctx->endpoint, FLB_CHRONICLE_UNSTRUCTURED_ENDPOINT); + + /* Create the base URI */ + if (ctx->region == NULL || strncasecmp(ctx->region, "US", 2) == 0) { + ctx->uri = flb_sds_create_size(sizeof(FLB_CHRONICLE_URL_BASE)); + if (!ctx->uri) { + flb_errno(); + flb_chronicle_conf_destroy(ctx); + return NULL; + } + ctx->uri = flb_sds_printf(&ctx->uri, FLB_CHRONICLE_URL_BASE); + } + else if (strncasecmp(ctx->region, "EU", 2) == 0){ + ctx->uri = flb_sds_create_size(sizeof(FLB_CHRONICLE_URL_BASE_EU)); + if (!ctx->uri) { + flb_errno(); + flb_chronicle_conf_destroy(ctx); + return NULL; + } + ctx->uri = flb_sds_printf(&ctx->uri, FLB_CHRONICLE_URL_BASE_EU); + } + else if (strncasecmp(ctx->region, "UK", 2) == 0) { + ctx->uri = flb_sds_create_size(sizeof(FLB_CHRONICLE_URL_BASE_UK)); + if (!ctx->uri) { + flb_errno(); + flb_chronicle_conf_destroy(ctx); + return NULL; + } + ctx->uri = flb_sds_printf(&ctx->uri, FLB_CHRONICLE_URL_BASE_UK); + } + else if (strncasecmp(ctx->region, "ASIA", 4) == 0) { + ctx->uri = flb_sds_create_size(sizeof(FLB_CHRONICLE_URL_BASE_ASIA)); + if (!ctx->uri) { + flb_errno(); + flb_chronicle_conf_destroy(ctx); + return NULL; + } + ctx->uri = flb_sds_printf(&ctx->uri, FLB_CHRONICLE_URL_BASE_ASIA); + } + else { + flb_plg_error(ctx->ins, "unsupported region"); + flb_chronicle_conf_destroy(ctx); + return NULL; + } + flb_plg_info(ctx->ins, "project='%s' custumer_id='%s' region='%s'", + ctx->project_id, ctx->customer_id, ctx->region); + + return ctx; +} + + +int flb_chronicle_oauth_credentials_destroy(struct flb_chronicle_oauth_credentials *creds) +{ + if (!creds) { + return -1; + } + flb_sds_destroy(creds->type); + flb_sds_destroy(creds->project_id); + flb_sds_destroy(creds->private_key_id); + flb_sds_destroy(creds->private_key); + flb_sds_destroy(creds->client_email); + flb_sds_destroy(creds->client_id); + flb_sds_destroy(creds->auth_uri); + flb_sds_destroy(creds->token_uri); + + flb_free(creds); + + return 0; +} + +int flb_chronicle_conf_destroy(struct flb_chronicle *ctx) +{ + if (!ctx) { + return -1; + } + + flb_chronicle_oauth_credentials_destroy(ctx->oauth_credentials); + + flb_sds_destroy(ctx->endpoint); + flb_sds_destroy(ctx->uri); + + if (ctx->o) { + flb_oauth2_destroy(ctx->o); + } + + flb_free(ctx); + return 0; +} diff --git a/plugins/out_chronicle/chronicle_conf.h b/plugins/out_chronicle/chronicle_conf.h new file mode 100644 index 00000000000..76dcfb3d25f --- /dev/null +++ b/plugins/out_chronicle/chronicle_conf.h @@ -0,0 +1,29 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Fluent Bit + * ========== + * Copyright (C) 2015-2023 The Fluent Bit Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLB_OUT_CHRONICLE_CONF_H +#define FLB_OUT_CHRONICLE_CONF_H + +#include "chronicle.h" + +struct flb_chronicle *flb_chronicle_conf_create(struct flb_output_instance *ins, + struct flb_config *config); +int flb_chronicle_conf_destroy(struct flb_chronicle *ctx); + +#endif From 80e09ab7f216675f5aee351a779e542942e0be3b Mon Sep 17 00:00:00 2001 From: CatherineF-dev Date: Wed, 12 Jul 2023 14:56:20 -0400 Subject: [PATCH 078/315] out_stackdriver: support gzip compression (#7101) Implement gzip compression Signed-off-by: Catherine Fang Co-authored-by: igorpeshansky --- plugins/out_stackdriver/stackdriver.c | 38 +++++++++++++++++++--- plugins/out_stackdriver/stackdriver.h | 3 ++ plugins/out_stackdriver/stackdriver_conf.c | 7 ++++ 3 files changed, 44 insertions(+), 4 deletions(-) diff --git a/plugins/out_stackdriver/stackdriver.c b/plugins/out_stackdriver/stackdriver.c index d36d3142643..f375417a81e 100644 --- a/plugins/out_stackdriver/stackdriver.c +++ b/plugins/out_stackdriver/stackdriver.c @@ -32,6 +32,7 @@ #include #include #include +#include #include @@ -2522,10 +2523,12 @@ static void cb_stackdriver_flush(struct flb_event_chunk *event_chunk, size_t b_sent; flb_sds_t token; flb_sds_t payload_buf; - size_t payload_size; + void *compressed_payload_buffer = NULL; + size_t compressed_payload_size; struct flb_stackdriver *ctx = out_context; struct flb_connection *u_conn; struct flb_http_client *c; + int compressed = FLB_FALSE; #ifdef FLB_HAVE_METRICS char *name = (char *) flb_output_name(ctx->ins); uint64_t ts = cfl_time_now(); @@ -2563,7 +2566,6 @@ static void cb_stackdriver_flush(struct flb_event_chunk *event_chunk, flb_upstream_conn_release(u_conn); FLB_OUTPUT_RETURN(FLB_RETRY); } - payload_size = flb_sds_len(payload_buf); /* Get or renew Token */ token = get_google_token(ctx); @@ -2581,9 +2583,22 @@ static void cb_stackdriver_flush(struct flb_event_chunk *event_chunk, FLB_OUTPUT_RETURN(FLB_RETRY); } + compressed_payload_buffer = payload_buf; + compressed_payload_size = flb_sds_len(payload_buf); + if (ctx->compress_gzip == FLB_TRUE) { + ret = flb_gzip_compress((void *) payload_buf, flb_sds_len(payload_buf), + &compressed_payload_buffer, &compressed_payload_size); + if (ret == -1) { + flb_plg_error(ctx->ins, "cannot gzip payload, disabling compression"); + } else { + compressed = FLB_TRUE; + flb_sds_destroy(payload_buf); + } + } + /* Compose HTTP Client request */ c = flb_http_client(u_conn, FLB_HTTP_POST, FLB_STD_WRITE_URI, - payload_buf, payload_size, NULL, 0, NULL, 0); + compressed_payload_buffer, compressed_payload_size, NULL, 0, NULL, 0); flb_http_buffer_size(c, 4192); @@ -2598,6 +2613,10 @@ static void cb_stackdriver_flush(struct flb_event_chunk *event_chunk, flb_http_add_header(c, "Content-Type", 12, "application/json", 16); flb_http_add_header(c, "Authorization", 13, token, flb_sds_len(token)); + /* Content Encoding: gzip */ + if (compressed == FLB_TRUE) { + flb_http_set_content_encoding_gzip(c); + } /* Send HTTP request */ ret = flb_http_do(c, &b_sent); @@ -2661,8 +2680,14 @@ static void cb_stackdriver_flush(struct flb_event_chunk *event_chunk, update_retry_metric(ctx, event_chunk, ts, c->resp.status, ret_code); #endif + /* Cleanup */ - flb_sds_destroy(payload_buf); + if (compressed == FLB_TRUE) { + flb_free(compressed_payload_buffer); + } + else { + flb_sds_destroy(payload_buf); + } flb_sds_destroy(token); flb_http_client_destroy(c); flb_upstream_conn_release(u_conn); @@ -2785,6 +2810,11 @@ static struct flb_config_map config_map[] = { 0, FLB_TRUE, offsetof(struct flb_stackdriver, task_id), "Set the resource task id" }, + { + FLB_CONFIG_MAP_STR, "compress", NULL, + 0, FLB_FALSE, 0, + "Set log payload compression method. Option available is 'gzip'" + }, { FLB_CONFIG_MAP_CLIST, "labels", NULL, 0, FLB_TRUE, offsetof(struct flb_stackdriver, labels), diff --git a/plugins/out_stackdriver/stackdriver.h b/plugins/out_stackdriver/stackdriver.h index fe43fb3bfe1..239a3ee318a 100644 --- a/plugins/out_stackdriver/stackdriver.h +++ b/plugins/out_stackdriver/stackdriver.h @@ -160,6 +160,9 @@ struct flb_stackdriver { flb_sds_t job; flb_sds_t task_id; + /* Internal variable to reduce string comparisons */ + int compress_gzip; + /* other */ flb_sds_t export_to_project_id; flb_sds_t resource; diff --git a/plugins/out_stackdriver/stackdriver_conf.c b/plugins/out_stackdriver/stackdriver_conf.c index a3986e58397..9f3f28a354c 100644 --- a/plugins/out_stackdriver/stackdriver_conf.c +++ b/plugins/out_stackdriver/stackdriver_conf.c @@ -279,6 +279,13 @@ struct flb_stackdriver *flb_stackdriver_conf_create(struct flb_output_instance * return NULL; } + /* Compress (gzip) */ + tmp = flb_output_get_property("compress", ins); + ctx->compress_gzip = FLB_FALSE; + if (tmp && strcasecmp(tmp, "gzip") == 0) { + ctx->compress_gzip = FLB_TRUE; + } + /* labels */ flb_kv_init(&ctx->config_labels); ret = parse_configuration_labels((void *)ctx); From 0af74160146f97442a38b54873085ffa603919f7 Mon Sep 17 00:00:00 2001 From: Braydon Kains <93549768+braydonk@users.noreply.github.com> Date: Wed, 12 Jul 2023 14:22:50 -0500 Subject: [PATCH 079/315] CODEOWNERS: Add codeowners for out_stackdriver (#7693) Signed-off-by: braydonk --- CODEOWNERS | 1 + 1 file changed, 1 insertion(+) diff --git a/CODEOWNERS b/CODEOWNERS index d790a27a94f..5d0c21f2f48 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -69,6 +69,7 @@ /plugins/out_kinesis_firehose @pettitwesley /plugins/out_kinesis_streams @pettitwesley /plugins/out_opensearch @pettitwesley @edsiper +/plugins/out_stackdriver @braydonk @igorpeshansky @qingling128 # AWS test code /tests/internal/aws @pettitwesley From 0e45937f36b944d8214b5d75c5aa88206b6bcc40 Mon Sep 17 00:00:00 2001 From: Phillip Whelan Date: Wed, 12 Jul 2023 17:47:35 -0500 Subject: [PATCH 080/315] codeowners: add pwhelan for calyptia and calyptia fleet. (#7692) Signed-off-by: Phillip Whelan --- CODEOWNERS | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CODEOWNERS b/CODEOWNERS index 5d0c21f2f48..a119d003f1a 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -84,3 +84,7 @@ # Devcontainer /.devcontainer @patrick-stephens @niedbalski @edsiper + +# Calytia Fleet +/plugins/custom_calyptia/ @pwhelan +/plugins/in_calyptia_fleet/ @pwhelan From efe997305ef7a8bf253aab5ea56801abaaf62e10 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 13 Jul 2023 10:27:59 +0100 Subject: [PATCH 081/315] release: update to 2.1.8 (#7698) Signed-off-by: GitHub Co-authored-by: edsiper --- CMakeLists.txt | 2 +- dockerfiles/Dockerfile | 2 +- fluent-bit-2.1.7.bb => fluent-bit-2.1.8.bb | 2 +- snap/snapcraft.yaml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) rename fluent-bit-2.1.7.bb => fluent-bit-2.1.8.bb (99%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4a49cca8d25..14b69ba5ca8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,7 @@ set(CMAKE_POLICY_DEFAULT_CMP0069 NEW) # Fluent Bit Version set(FLB_VERSION_MAJOR 2) set(FLB_VERSION_MINOR 1) -set(FLB_VERSION_PATCH 7) +set(FLB_VERSION_PATCH 8) set(FLB_VERSION_STR "${FLB_VERSION_MAJOR}.${FLB_VERSION_MINOR}.${FLB_VERSION_PATCH}") set(CMAKE_POSITION_INDEPENDENT_CODE ON) diff --git a/dockerfiles/Dockerfile b/dockerfiles/Dockerfile index 63bbbbfc2cf..8d583901296 100644 --- a/dockerfiles/Dockerfile +++ b/dockerfiles/Dockerfile @@ -11,7 +11,7 @@ # docker buildx build --platform "linux/amd64,linux/arm64,linux/arm/v7" -f ./dockerfiles/Dockerfile.multiarch --build-arg FLB_TARBALL=https://github.com/fluent/fluent-bit/archive/v1.8.11.tar.gz ./dockerfiles/ # Set this to the current release version: it gets done so as part of the release. -ARG RELEASE_VERSION=2.1.7 +ARG RELEASE_VERSION=2.1.8 # For multi-arch builds - assumption is running on an AMD64 host FROM multiarch/qemu-user-static:x86_64-arm as qemu-arm32 diff --git a/fluent-bit-2.1.7.bb b/fluent-bit-2.1.8.bb similarity index 99% rename from fluent-bit-2.1.7.bb rename to fluent-bit-2.1.8.bb index e24e552e96c..9096e336753 100644 --- a/fluent-bit-2.1.7.bb +++ b/fluent-bit-2.1.8.bb @@ -16,7 +16,7 @@ LIC_FILES_CHKSUM = "file://LICENSE;md5=2ee41112a44fe7014dce33e26468ba93" SECTION = "net" PR = "r0" -PV = "2.1.7" +PV = "2.1.8" SRCREV = "v${PV}" SRC_URI = "git://github.com/fluent/fluent-bit.git;nobranch=1" diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index bce1ce569cb..891d71e33f1 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -1,6 +1,6 @@ name: fluent-bit base: core18 -version: '2.1.7' +version: '2.1.8' summary: High performance logs and stream processor description: | Fluent Bit is a high performance log processor and stream processor for Linux. From 69e6bb6faabe5c67fad2baabc4cc938d7f94745b Mon Sep 17 00:00:00 2001 From: Josh Baird Date: Tue, 11 Jul 2023 09:12:50 -0400 Subject: [PATCH 082/315] aws: imds: set length when initializing token to dummy value Signed-off-by: Josh Baird --- src/aws/flb_aws_imds.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/aws/flb_aws_imds.c b/src/aws/flb_aws_imds.c index 12277f3b487..0e54db161c1 100644 --- a/src/aws/flb_aws_imds.c +++ b/src/aws/flb_aws_imds.c @@ -70,6 +70,7 @@ struct flb_aws_imds *flb_aws_imds_create(const struct flb_aws_imds_config *imds_ */ ctx->imds_version = imds_config->use_imds_version; ctx->imds_v2_token = flb_sds_create_len("INVALID_TOKEN", 13); + ctx->imds_v2_token_len = 13; /* Detect IMDS support */ if (!ec2_imds_client->upstream) { From 5a333a24e481433332a1d8d9e0d30150731d9b63 Mon Sep 17 00:00:00 2001 From: Leonardo Alminana Date: Wed, 14 Jun 2023 19:54:48 +0200 Subject: [PATCH 083/315] in_node_exporter_metrics: updated renamed function reference Signed-off-by: Leonardo Alminana --- plugins/in_node_exporter_metrics/ne_textfile_linux.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/plugins/in_node_exporter_metrics/ne_textfile_linux.c b/plugins/in_node_exporter_metrics/ne_textfile_linux.c index 05f5f82a210..8d66bc58fec 100644 --- a/plugins/in_node_exporter_metrics/ne_textfile_linux.c +++ b/plugins/in_node_exporter_metrics/ne_textfile_linux.c @@ -144,13 +144,6 @@ static int textfile_update(struct flb_ne *ctx) entry = mk_list_entry(head, struct flb_slist_entry, _head); /* Update metrics from text file */ contents = flb_file_read_contents(entry->str); - - if (contents == NULL) { - flb_plg_debug(ctx->ins, "skip invalid file of prometheus: %s", - entry->str); - continue; - } - if (flb_sds_len(contents) == 0) { flb_plg_debug(ctx->ins, "skip empty payload of prometheus: %s", entry->str); From 7a8861ec483b1367cfe36026f8122f12cf6dd075 Mon Sep 17 00:00:00 2001 From: Braydon Kains <93549768+braydonk@users.noreply.github.com> Date: Mon, 17 Jul 2023 09:26:25 -0400 Subject: [PATCH 084/315] CODEOWNERS: Google owners for out_stackdriver test (#7694) Signed-off-by: braydonk --- CODEOWNERS | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CODEOWNERS b/CODEOWNERS index a119d003f1a..469ffcc7e11 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -63,13 +63,14 @@ /plugins/out_datadog @nokute78 @edsiper /plugins/out_es @pettitwesley @edsiper /plugins/out_pgsql @sxd +/plugins/out_stackdriver @braydonk @igorpeshansky @qingling128 + # AWS Plugins /plugins/out_s3 @pettitwesley /plugins/out_cloudwatch_logs @pettitwesley /plugins/out_kinesis_firehose @pettitwesley /plugins/out_kinesis_streams @pettitwesley /plugins/out_opensearch @pettitwesley @edsiper -/plugins/out_stackdriver @braydonk @igorpeshansky @qingling128 # AWS test code /tests/internal/aws @pettitwesley @@ -82,6 +83,10 @@ /tests/runtime/out_opensearch.c @pettitwesley @edsiper /tests/runtime/out_s3.c @pettitwesley +# Google test code +# -------------- +/tests/runtime/out_stackdriver.c @braydonk @igorpeshansky @qingling128 + # Devcontainer /.devcontainer @patrick-stephens @niedbalski @edsiper From ec5647660b6285e38a0a2930a4d3a27bd8d161a4 Mon Sep 17 00:00:00 2001 From: Leonardo Alminana Date: Mon, 17 Jul 2023 11:00:40 +0200 Subject: [PATCH 085/315] output: added metrics for upstream connections Signed-off-by: Leonardo Alminana --- include/fluent-bit/flb_output.h | 6 ++++++ src/flb_output.c | 36 +++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/include/fluent-bit/flb_output.h b/include/fluent-bit/flb_output.h index 0b244107d56..5fe13f99c18 100644 --- a/include/fluent-bit/flb_output.h +++ b/include/fluent-bit/flb_output.h @@ -50,6 +50,7 @@ #include #include +#include #include #include #include @@ -360,6 +361,11 @@ struct flb_output_instance { struct cmt_counter *cmt_dropped_records; /* m: output_dropped_records */ struct cmt_counter *cmt_retried_records; /* m: output_retried_records */ + /* m: output_upstream_total_connections */ + struct cmt_gauge *cmt_upstream_total_connections; + /* m: output_upstream_busy_connections */ + struct cmt_gauge *cmt_upstream_busy_connections; + /* OLD Metrics API */ #ifdef FLB_HAVE_METRICS struct flb_metrics *metrics; /* metrics */ diff --git a/src/flb_output.c b/src/flb_output.c index f06ba4f43f0..b1548f60dfa 100644 --- a/src/flb_output.c +++ b/src/flb_output.c @@ -1176,6 +1176,30 @@ int flb_output_init_all(struct flb_config *config) 1, (char *[]) {"name"}); cmt_counter_set(ins->cmt_retried_records, ts, 0, 1, (char *[]) {name}); + /* output_upstream_total_connections */ + ins->cmt_upstream_total_connections = cmt_gauge_create(ins->cmt, + "fluentbit", + "output", + "upstream_total_connections", + "Total Connection count.", + 1, (char *[]) {"name"}); + cmt_gauge_set(ins->cmt_upstream_total_connections, + ts, + 0, + 1, (char *[]) {name}); + + /* output_upstream_total_connections */ + ins->cmt_upstream_busy_connections = cmt_gauge_create(ins->cmt, + "fluentbit", + "output", + "upstream_busy_connections", + "Busy Connection count.", + 1, (char *[]) {"name"}); + cmt_gauge_set(ins->cmt_upstream_busy_connections, + ts, + 0, + 1, (char *[]) {name}); + /* old API */ ins->metrics = flb_metrics_create(name); if (ins->metrics) { @@ -1365,6 +1389,18 @@ int flb_output_upstream_set(struct flb_upstream *u, struct flb_output_instance * /* Set flags */ flb_stream_enable_flags(&u->base, flags); + flb_upstream_set_total_connections_label(u, + flb_output_name(ins)); + + flb_upstream_set_total_connections_gauge(u, + ins->cmt_upstream_total_connections); + + flb_upstream_set_busy_connections_label(u, + flb_output_name(ins)); + + flb_upstream_set_busy_connections_gauge(u, + ins->cmt_upstream_busy_connections); + /* * If the output plugin flush callbacks will run in multiple threads, enable * the thread safe mode for the Upstream context. From 464dfe268855c83da75b1dc877ecccf62262ef2a Mon Sep 17 00:00:00 2001 From: Leonardo Alminana Date: Mon, 17 Jul 2023 11:00:58 +0200 Subject: [PATCH 086/315] upstream: added metrics for upstream connections Signed-off-by: Leonardo Alminana --- include/fluent-bit/flb_upstream.h | 22 +++++ src/flb_upstream.c | 133 ++++++++++++++++++++++++++++++ 2 files changed, 155 insertions(+) diff --git a/include/fluent-bit/flb_upstream.h b/include/fluent-bit/flb_upstream.h index 56325250be9..ad23238e2ea 100644 --- a/include/fluent-bit/flb_upstream.h +++ b/include/fluent-bit/flb_upstream.h @@ -30,6 +30,9 @@ #include #include +#include +#include + /* * Upstream creation FLAGS set by Fluent Bit sub-components * ======================================================== @@ -63,6 +66,11 @@ struct flb_upstream { int ha_mode; void *ha_ctx; + struct cmt_gauge *cmt_total_connections; + struct cmt_gauge *cmt_busy_connections; + const char *cmt_total_connections_label; + const char *cmt_busy_connections_label; + /* * If the connections will be in separate threads, this flag is * enabled and all lists management are protected through mutexes. @@ -98,4 +106,18 @@ void flb_upstream_thread_safe(struct flb_upstream *u); struct mk_list *flb_upstream_get_config_map(struct flb_config *config); int flb_upstream_needs_proxy(const char *host, const char *proxy, const char *no_proxy); +void flb_upstream_set_total_connections_label( + struct flb_upstream *stream, + const char *label_value); +void flb_upstream_set_total_connections_gauge( + struct flb_upstream *stream, + struct cmt_gauge *gauge_instance); + +void flb_upstream_set_busy_connections_label( + struct flb_upstream *stream, + const char *label_value); +void flb_upstream_set_busy_connections_gauge( + struct flb_upstream *stream, + struct cmt_gauge *gauge_instance); + #endif diff --git a/src/flb_upstream.c b/src/flb_upstream.c index b46388ebf30..7cd292a97df 100644 --- a/src/flb_upstream.c +++ b/src/flb_upstream.c @@ -111,6 +111,18 @@ struct flb_config_map upstream_net[] = { int flb_upstream_needs_proxy(const char *host, const char *proxy, const char *no_proxy); +static void flb_upstream_increment_busy_connections_count( + struct flb_upstream *stream); + +static void flb_upstream_decrement_busy_connections_count( + struct flb_upstream *stream); + +static void flb_upstream_increment_total_connections_count( + struct flb_upstream *stream); + +static void flb_upstream_decrement_total_connections_count( + struct flb_upstream *stream); + /* Enable thread-safe mode for upstream connection */ void flb_upstream_thread_safe(struct flb_upstream *u) { @@ -463,6 +475,8 @@ static int prepare_destroy_conn(struct flb_connection *u_conn) /* Add node to destroy queue */ mk_list_add(&u_conn->_head, &uq->destroy_queue); + flb_upstream_decrement_total_connections_count(u); + /* * note: the connection context is destroyed by the engine once all events * have been processed. @@ -531,6 +545,8 @@ static struct flb_connection *create_conn(struct flb_upstream *u) uq = flb_upstream_queue_get(u); mk_list_add(&conn->_head, &uq->busy_queue); + flb_upstream_increment_total_connections_count(u); + flb_stream_release_lock(&u->base); flb_connection_reset_connection_timeout(conn); @@ -730,6 +746,7 @@ struct flb_connection *flb_upstream_conn_get(struct flb_upstream *u) if (conn != NULL) { flb_connection_reset_io_timeout(conn); + flb_upstream_increment_busy_connections_count(u); } return conn; @@ -757,6 +774,8 @@ int flb_upstream_conn_release(struct flb_connection *conn) struct flb_upstream *u = conn->upstream; struct flb_upstream_queue *uq; + flb_upstream_decrement_busy_connections_count(u); + uq = flb_upstream_queue_get(u); /* If this is a valid KA connection just recycle */ @@ -897,6 +916,8 @@ int flb_upstream_conn_timeouts(struct mk_list *list) u_conn->event.mask, FLB_TRUE); } + + flb_upstream_decrement_busy_connections_count(u); } } @@ -994,3 +1015,115 @@ int flb_upstream_is_async(struct flb_upstream *u) { return flb_stream_is_async(&u->base); } + +void flb_upstream_set_total_connections_label( + struct flb_upstream *stream, + const char *label_value) +{ + stream->cmt_total_connections_label = label_value; +} + +void flb_upstream_set_total_connections_gauge( + struct flb_upstream *stream, + struct cmt_gauge *gauge_instance) +{ + stream->cmt_total_connections = gauge_instance; +} + +static void flb_upstream_increment_total_connections_count( + struct flb_upstream *stream) +{ + if (stream->cmt_total_connections != NULL) { + if (stream->cmt_total_connections_label != NULL) { + cmt_gauge_inc( + stream->cmt_total_connections, + cfl_time_now(), + 1, + (char *[]) { + (char *) stream->cmt_total_connections_label + }); + } + else { + cmt_gauge_inc(stream->cmt_total_connections, + cfl_time_now(), + 0, NULL); + } + } +} + +static void flb_upstream_decrement_total_connections_count( + struct flb_upstream *stream) +{ + if (stream->cmt_total_connections != NULL) { + if (stream->cmt_total_connections_label != NULL) { + cmt_gauge_dec( + stream->cmt_total_connections, + cfl_time_now(), + 1, + (char *[]) { + (char *) stream->cmt_total_connections_label + }); + } + else { + cmt_gauge_dec(stream->cmt_total_connections, + cfl_time_now(), + 0, NULL); + } + } +} + +void flb_upstream_set_busy_connections_label( + struct flb_upstream *stream, + const char *label_value) +{ + stream->cmt_busy_connections_label = label_value; +} + +void flb_upstream_set_busy_connections_gauge( + struct flb_upstream *stream, + struct cmt_gauge *gauge_instance) +{ + stream->cmt_busy_connections = gauge_instance; +} + +static void flb_upstream_increment_busy_connections_count( + struct flb_upstream *stream) +{ + if (stream->cmt_busy_connections != NULL) { + if (stream->cmt_busy_connections_label != NULL) { + cmt_gauge_inc( + stream->cmt_busy_connections, + cfl_time_now(), + 1, + (char *[]) { + (char *) stream->cmt_busy_connections_label + }); + } + else { + cmt_gauge_inc(stream->cmt_busy_connections, + cfl_time_now(), + 0, NULL); + } + } +} + +static void flb_upstream_decrement_busy_connections_count( + struct flb_upstream *stream) +{ + if (stream->cmt_busy_connections != NULL) { + if (stream->cmt_busy_connections_label != NULL) { + cmt_gauge_dec( + stream->cmt_busy_connections, + cfl_time_now(), + 1, + (char *[]) { + (char *) stream->cmt_busy_connections_label + }); + } + else { + cmt_gauge_dec(stream->cmt_busy_connections, + cfl_time_now(), + 0, NULL); + } + } +} From 8182f257cc6f9c04af6ec24bad25c2545fe9d0cd Mon Sep 17 00:00:00 2001 From: Leonardo Alminana Date: Mon, 17 Jul 2023 11:23:54 +0200 Subject: [PATCH 087/315] upstream: added parent upstream transversal to the metrics functions Signed-off-by: Leonardo Alminana --- src/flb_upstream.c | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/src/flb_upstream.c b/src/flb_upstream.c index 7cd292a97df..4701cc3d68f 100644 --- a/src/flb_upstream.c +++ b/src/flb_upstream.c @@ -1033,6 +1033,11 @@ void flb_upstream_set_total_connections_gauge( static void flb_upstream_increment_total_connections_count( struct flb_upstream *stream) { + if (stream->parent_upstream != NULL) { + stream = (struct flb_upstream *) stream->parent_upstream; + + flb_upstream_increment_total_connections_count(stream); + } if (stream->cmt_total_connections != NULL) { if (stream->cmt_total_connections_label != NULL) { cmt_gauge_inc( @@ -1054,7 +1059,12 @@ static void flb_upstream_increment_total_connections_count( static void flb_upstream_decrement_total_connections_count( struct flb_upstream *stream) { - if (stream->cmt_total_connections != NULL) { + if (stream->parent_upstream != NULL) { + stream = (struct flb_upstream *) stream->parent_upstream; + + flb_upstream_decrement_total_connections_count(stream); + } + else if (stream->cmt_total_connections != NULL) { if (stream->cmt_total_connections_label != NULL) { cmt_gauge_dec( stream->cmt_total_connections, @@ -1089,7 +1099,12 @@ void flb_upstream_set_busy_connections_gauge( static void flb_upstream_increment_busy_connections_count( struct flb_upstream *stream) { - if (stream->cmt_busy_connections != NULL) { + if (stream->parent_upstream != NULL) { + stream = (struct flb_upstream *) stream->parent_upstream; + + flb_upstream_increment_busy_connections_count(stream); + } + else if (stream->cmt_busy_connections != NULL) { if (stream->cmt_busy_connections_label != NULL) { cmt_gauge_inc( stream->cmt_busy_connections, @@ -1110,7 +1125,12 @@ static void flb_upstream_increment_busy_connections_count( static void flb_upstream_decrement_busy_connections_count( struct flb_upstream *stream) { - if (stream->cmt_busy_connections != NULL) { + if (stream->parent_upstream != NULL) { + stream = (struct flb_upstream *) stream->parent_upstream; + + flb_upstream_decrement_busy_connections_count(stream); + } + else if (stream->cmt_busy_connections != NULL) { if (stream->cmt_busy_connections_label != NULL) { cmt_gauge_dec( stream->cmt_busy_connections, From 149ccd6eea18f5d088a01c743b5f6f5b968c8f1a Mon Sep 17 00:00:00 2001 From: Takahiro Yamashita Date: Sat, 15 Jul 2023 07:07:58 +0900 Subject: [PATCH 088/315] downstream: remove not used variable Signed-off-by: Takahiro Yamashita --- src/flb_downstream.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/flb_downstream.c b/src/flb_downstream.c index 21af230338e..e4b7e19ef50 100644 --- a/src/flb_downstream.c +++ b/src/flb_downstream.c @@ -181,10 +181,6 @@ struct flb_downstream *flb_downstream_create(int transport, int flags, */ static int prepare_destroy_conn(struct flb_connection *connection) { - struct flb_stream *stream; - - stream = connection->stream; - flb_trace("[downstream] destroy connection #%i to %s", connection->fd, flb_connection_get_remote_address(connection)); From 0104b0be046eb40b5fc834dae1c00cbdba57b51a Mon Sep 17 00:00:00 2001 From: Prateek Mishra Date: Tue, 18 Jul 2023 21:48:06 +0530 Subject: [PATCH 089/315] build: fix typo in CMakeLists.txt for Kubernetes Event (#7700) nothing much was just exploring the undocumented code and came across this Signed-off-by: Prateek Mishra --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 14b69ba5ca8..90f489c64b5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -180,7 +180,7 @@ option(FLB_IN_FORWARD "Enable Forward input plugin" option(FLB_IN_HEALTH "Enable Health input plugin" Yes) option(FLB_IN_HTTP "Enable HTTP input plugin" Yes) option(FLB_IN_MEM "Enable Memory input plugin" Yes) -option(FLB_IN_KUBERNETES_EVENTS "Enabke Kubernetes Events plugin" Yes) +option(FLB_IN_KUBERNETES_EVENTS "Enable Kubernetes Events plugin" Yes) option(FLB_IN_KAFKA "Enable Kafka input plugin" Yes) option(FLB_IN_KMSG "Enable Kernel log input plugin" Yes) option(FLB_IN_LIB "Enable library mode input plugin" Yes) From 30b27cee89a16590cb8ea528e67039df2f00526f Mon Sep 17 00:00:00 2001 From: Hiroshi Hatake Date: Wed, 19 Jul 2023 01:19:28 +0900 Subject: [PATCH 090/315] build: test: Fix an invalid constant for filter_rewrite_tag (#7675) Signed-off-by: Hiroshi Hatake --- tests/runtime/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/runtime/CMakeLists.txt b/tests/runtime/CMakeLists.txt index 125b0055b83..8fc75339adc 100644 --- a/tests/runtime/CMakeLists.txt +++ b/tests/runtime/CMakeLists.txt @@ -66,7 +66,7 @@ if(FLB_IN_LIB AND FLB_OUT_LIB) FLB_RT_TEST(FLB_FILTER_THROTTLE "filter_throttle.c") FLB_RT_TEST(FLB_FILTER_THROTTLE_SIZE "filter_throttle_size.c") FLB_RT_TEST(FLB_FILTER_NEST "filter_nest.c") - FLB_RT_TEST(FLB_FILTER_NEST "filter_rewrite_tag.c") + FLB_RT_TEST(FLB_FILTER_REWRITE_TAG "filter_rewrite_tag.c") FLB_RT_TEST(FLB_FILTER_KUBERNETES "filter_kubernetes.c") FLB_RT_TEST(FLB_FILTER_PARSER "filter_parser.c") FLB_RT_TEST(FLB_FILTER_MODIFY "filter_modify.c") From f4926d4ea041d0ed0d8e9d937f4bd7471575c181 Mon Sep 17 00:00:00 2001 From: Hiroshi Hatake Date: Wed, 19 Jul 2023 18:55:11 +0900 Subject: [PATCH 091/315] build: Install OpenSSL with chocolatey only for x64 (#7719) * build: Install OpenSSL with chocolatey only for x64 This is because Chocolatey only supports x64 installation after OpenSSL 3.1.1 package. ref: https://community.chocolatey.org/packages/openssl/3.1.1#files Signed-off-by: Hiroshi Hatake * build: Use the correct directory to refer the installed place of OpenSSL Signed-off-by: Hiroshi Hatake --------- Signed-off-by: Hiroshi Hatake --- .github/workflows/call-build-windows.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/call-build-windows.yaml b/.github/workflows/call-build-windows.yaml index 28a5604d966..d15af8c9a4f 100644 --- a/.github/workflows/call-build-windows.yaml +++ b/.github/workflows/call-build-windows.yaml @@ -72,7 +72,7 @@ jobs: config: - name: "Windows 32bit" arch: x86 - openssl_dir: C:\Program Files (x86)\OpenSSL-Win32 + openssl_dir: C:\vcpkg\packages\openssl_x86-windows-static chocolatey_opt: --x86 cmake_additional_opt: "" vcpkg_triplet: x86-windows-static @@ -111,7 +111,7 @@ jobs: shell: pwsh - name: Get dependencies w/ chocolatey - if: ${{ matrix.config.arch != 'amd64_arm64' }} + if: ${{ matrix.config.arch == 'x64' }} uses: crazy-max/ghaction-chocolatey@v2 with: args: install ${{ matrix.config.chocolatey_opt }} openssl -y @@ -122,7 +122,7 @@ jobs: arch: ${{ matrix.config.arch }} - name: Build openssl with vcpkg - if: ${{ matrix.config.arch == 'amd64_arm64' }} + if: ${{ matrix.config.arch != 'x64' }} run: | C:\vcpkg\vcpkg install --recurse openssl --triplet ${{ matrix.config.vcpkg_triplet }} shell: cmd From 8dad57544d3326f3295e06f152fd87dcdba80295 Mon Sep 17 00:00:00 2001 From: Daniel Lenar Date: Wed, 19 Jul 2023 21:07:43 -0500 Subject: [PATCH 092/315] in_tail: don't append records if sl_log_event_encoder buffer is 0 (#7723) Signed-off-by: Daniel Lenar --- plugins/in_tail/tail_file.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/plugins/in_tail/tail_file.c b/plugins/in_tail/tail_file.c index 5dc69230800..d2694d5a744 100644 --- a/plugins/in_tail/tail_file.c +++ b/plugins/in_tail/tail_file.c @@ -588,14 +588,16 @@ static int process_content(struct flb_tail_file *file, size_t *bytes) /* Append buffer content to a chunk */ *bytes = processed_bytes; - flb_input_log_append_records(ctx->ins, - lines, - file->tag_buf, - file->tag_len, - file->sl_log_event_encoder->output_buffer, - file->sl_log_event_encoder->output_length); - - flb_log_event_encoder_reset(file->sl_log_event_encoder); + if (file->sl_log_event_encoder->output_length > 0) { + flb_input_log_append_records(ctx->ins, + lines, + file->tag_buf, + file->tag_len, + file->sl_log_event_encoder->output_buffer, + file->sl_log_event_encoder->output_length); + + flb_log_event_encoder_reset(file->sl_log_event_encoder); + } } else if (file->skip_next) { *bytes = file->buf_len; From 9c94898b03e189aa72bc5cc85f46a24ff97ae558 Mon Sep 17 00:00:00 2001 From: Phillip Whelan Date: Tue, 18 Jul 2023 10:54:07 -0400 Subject: [PATCH 093/315] calyptia_fleet: fix to use custom calyptia plugin on reload. Signed-off-by: Phillip Whelan --- plugins/in_calyptia_fleet/in_calyptia_fleet.c | 28 ++++++++----------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/plugins/in_calyptia_fleet/in_calyptia_fleet.c b/plugins/in_calyptia_fleet/in_calyptia_fleet.c index a2821a31095..1c3322e8dc8 100644 --- a/plugins/in_calyptia_fleet/in_calyptia_fleet.c +++ b/plugins/in_calyptia_fleet/in_calyptia_fleet.c @@ -349,6 +349,14 @@ static int execute_reload(struct flb_in_calyptia_fleet_config *ctx, flb_sds_t cf return FLB_TRUE; } +static char *tls_setting_string(int use_tls) +{ + if (use_tls) { + return "On"; + } + return "Off"; +} + /* cb_collect callback */ static int in_calyptia_fleet_collect(struct flb_input_instance *ins, struct flb_config *config, void *in_context) @@ -435,35 +443,22 @@ static int in_calyptia_fleet_collect(struct flb_input_instance *ins, } header = flb_sds_create_size(4096); flb_sds_printf(&header, - "[INPUT]\n" - " Name calyptia_fleet\n" - " Api_Key %s\n" - " fleet_id %s\n" - " Host %s\n" - " Port %d\n" - " Config_Dir %s\n" - " TLS %s\n" "[CUSTOM]\n" " Name calyptia\n" " api_key %s\n" - " log_level debug\n" " fleet_id %s\n" " add_label fleet_id %s\n" + " Fleet.Config_Dir %s\n" " calyptia_host %s\n" " calyptia_port %d\n" " calyptia_tls %s\n", ctx->api_key, ctx->fleet_id, - ctx->ins->host.name, - ctx->ins->host.port, - ctx->config_dir, - (ctx->ins->tls ? "On" : "Off"), - ctx->api_key, - ctx->fleet_id, ctx->fleet_id, + ctx->config_dir, ctx->ins->host.name, ctx->ins->host.port, - (ctx->ins->tls ? "On" : "Off") + tls_setting_string(ctx->ins->use_tls) ); fwrite(header, strlen(header), 1, cfgfp); flb_sds_destroy(header); @@ -596,7 +591,6 @@ static int in_calyptia_fleet_init(struct flb_input_instance *in, upstream_flags = FLB_IO_TCP; if (in->use_tls) { - flb_plg_error(in, "using TLS"); upstream_flags |= FLB_IO_TLS; } From 000156891a81e8480aaad90a638db185ac7d7d58 Mon Sep 17 00:00:00 2001 From: Phillip Whelan Date: Tue, 18 Jul 2023 10:55:29 -0400 Subject: [PATCH 094/315] calyptia_fleet: fix problems with valgrind. Signed-off-by: Phillip Whelan --- plugins/in_calyptia_fleet/in_calyptia_fleet.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/plugins/in_calyptia_fleet/in_calyptia_fleet.c b/plugins/in_calyptia_fleet/in_calyptia_fleet.c index 1c3322e8dc8..ffba76bbb7a 100644 --- a/plugins/in_calyptia_fleet/in_calyptia_fleet.c +++ b/plugins/in_calyptia_fleet/in_calyptia_fleet.c @@ -270,6 +270,7 @@ static void *do_reload(void *data) { struct reload_ctx *reload = (struct reload_ctx *)data; // avoid reloading the current configuration... just use our new one! + flb_context_set(reload->flb); reload->flb->config->enable_hot_reload = FLB_TRUE; reload->flb->config->conf_path_file = reload->cfg_path; sleep(5); @@ -328,6 +329,10 @@ static int execute_reload(struct flb_in_calyptia_fleet_config *ctx, flb_sds_t cf flb_ctx_t *flb = flb_context_get(); + if (flb == NULL) { + flb_plg_error(ctx->ins, "unable to get fluent-bit context."); + return FLB_FALSE; + } // fix execution in valgrind... // otherwise flb_reload errors out with: // [error] [reload] given flb context is NULL @@ -372,7 +377,7 @@ static int in_calyptia_fleet_collect(struct flb_input_instance *ins, FILE *cfgfp; const char *fbit_last_modified; int fbit_last_modified_len; - struct flb_tm tm_last_modified; + struct flb_tm tm_last_modified = { 0 }; time_t time_last_modified; char *data; size_t b_sent; From 523de853330d4ffbd1d09623af1832597d387e5b Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Tue, 18 Jul 2023 10:07:07 -0600 Subject: [PATCH 095/315] lib: monkey: upgrade to v1.7.0 Signed-off-by: Eduardo Silva --- lib/monkey/mk_core/mk_utils.c | 2 +- lib/monkey/mk_server/monkey.c | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/monkey/mk_core/mk_utils.c b/lib/monkey/mk_core/mk_utils.c index af733073398..54cdd39388d 100644 --- a/lib/monkey/mk_core/mk_utils.c +++ b/lib/monkey/mk_core/mk_utils.c @@ -329,7 +329,7 @@ int mk_utils_register_pid(char *path) { int fd; int ret; - char pidstr[MK_MAX_PID_LEN]; + char pidstr[MK_MAX_PID_LEN + 1]; struct flock lock; struct stat sb; diff --git a/lib/monkey/mk_server/monkey.c b/lib/monkey/mk_server/monkey.c index a3e79ede13b..68513d21b40 100644 --- a/lib/monkey/mk_server/monkey.c +++ b/lib/monkey/mk_server/monkey.c @@ -199,7 +199,6 @@ int mk_server_setup(struct mk_server *server) /* Clock init that must happen before starting threads */ mk_clock_sequential_init(server); -printf("MK SERVER SETUP CALLED\n"); /* Load plugins */ mk_plugin_api_init(server); mk_plugin_load_all(server); From 7e6451de369a52e5d559d3106c8c4a1e26a6b223 Mon Sep 17 00:00:00 2001 From: Takahiro Yamashita Date: Sat, 15 Jul 2023 07:23:13 +0900 Subject: [PATCH 096/315] in_splunk: fix unused arg Signed-off-by: Takahiro Yamashita --- plugins/in_splunk/splunk_prot.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/in_splunk/splunk_prot.c b/plugins/in_splunk/splunk_prot.c index 82afa6efc83..f547c95c65c 100644 --- a/plugins/in_splunk/splunk_prot.c +++ b/plugins/in_splunk/splunk_prot.c @@ -715,10 +715,10 @@ int splunk_prot_handle(struct flb_splunk *ctx, struct splunk_conn *conn, if (ret < 0){ send_response(conn, 401, "error: unauthroized\n"); if (ret == SPLUNK_AUTH_MISSING_CRED) { - flb_plg_warn(ctx->ins, "missing credentials in request headers", ret); + flb_plg_warn(ctx->ins, "missing credentials in request headers"); } else if (ret == SPLUNK_AUTH_UNAUTHORIZED) { - flb_plg_warn(ctx->ins, "wrong credentials in request headers", ret); + flb_plg_warn(ctx->ins, "wrong credentials in request headers"); } flb_sds_destroy(tag); From de3da374e0daaca939c8f57e1f83d7ecb2cc3551 Mon Sep 17 00:00:00 2001 From: Takahiro Yamashita Date: Sat, 15 Jul 2023 07:33:09 +0900 Subject: [PATCH 097/315] in_splunk: remove not used variables Signed-off-by: Takahiro Yamashita --- plugins/in_splunk/splunk_prot.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/plugins/in_splunk/splunk_prot.c b/plugins/in_splunk/splunk_prot.c index f547c95c65c..f6636706359 100644 --- a/plugins/in_splunk/splunk_prot.c +++ b/plugins/in_splunk/splunk_prot.c @@ -314,7 +314,6 @@ static void process_flb_log_append(struct flb_splunk *ctx, msgpack_object *recor static int process_json_payload_pack(struct flb_splunk *ctx, flb_sds_t tag, char *buf, size_t size) { - int ret; size_t off = 0; msgpack_unpacked result; struct flb_time tm; @@ -546,7 +545,6 @@ static int process_hec_raw_payload(struct flb_splunk *ctx, struct splunk_conn *c struct mk_http_request *request) { int ret = -1; - int type = -1; struct mk_http_header *header; header = &session->parser.headers[MK_HEADER_CONTENT_TYPE]; @@ -554,14 +552,10 @@ static int process_hec_raw_payload(struct flb_splunk *ctx, struct splunk_conn *c send_response(conn, 400, "error: header 'Content-Type' is not set\n"); return -1; } - else if (header->val.len == 10 && - strncasecmp(header->val.data, "text/plain", 10) == 0) { - type = HTTP_CONTENT_TEXT; - } - else { + else if (header->val.len != 10 || + strncasecmp(header->val.data, "text/plain", 10) != 0) { /* Not neccesary to specify content-type for Splunk HEC. */ flb_plg_debug(ctx->ins, "Mark as unknown type for ingested payloads"); - type = HTTP_CONTENT_UNKNOWN; } if (request->data.len <= 0) { From 2b55d111e85f1b8937195015f2864a026c9fff0f Mon Sep 17 00:00:00 2001 From: lecaros Date: Wed, 12 Jul 2023 21:17:32 -0400 Subject: [PATCH 098/315] in_tail: fix ignore_older description. Signed-off-by: lecaros --- plugins/in_tail/tail.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/plugins/in_tail/tail.c b/plugins/in_tail/tail.c index 18e4ce30e01..d87cdc11de4 100644 --- a/plugins/in_tail/tail.c +++ b/plugins/in_tail/tail.c @@ -621,10 +621,8 @@ static struct flb_config_map config_map[] = { { FLB_CONFIG_MAP_TIME, "ignore_older", "0", 0, FLB_TRUE, offsetof(struct flb_tail_config, ignore_older), - "ignore records older than 'ignore_older'. Supports m,h,d (minutes, " - "hours, days) syntax. Default behavior is to read all records. Option " - "only available when a Parser is specified and it can parse the time " - "of a record." + "ignore files older than 'ignore_older'. Supports m,h,d (minutes, " + "hours, days) syntax. Default behavior is to read all the files." }, { FLB_CONFIG_MAP_SIZE, "buffer_chunk_size", FLB_TAIL_CHUNK, From 7cc4be9bd762fd985e45157805ed0f2e84ec9f26 Mon Sep 17 00:00:00 2001 From: Thiago Padilha Date: Mon, 29 May 2023 09:08:50 -0300 Subject: [PATCH 099/315] in_kafka: Fix json packing Signed-off-by: Thiago Padilha --- plugins/in_kafka/in_kafka.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/in_kafka/in_kafka.c b/plugins/in_kafka/in_kafka.c index 5bdbf84d84d..9cc70316684 100644 --- a/plugins/in_kafka/in_kafka.c +++ b/plugins/in_kafka/in_kafka.c @@ -51,7 +51,7 @@ static int try_json(struct flb_log_event_encoder *log_encoder, } return ret; } - flb_log_event_encoder_append_body_binary_body(log_encoder, buf, bufsize); + flb_log_event_encoder_append_body_raw_msgpack(log_encoder, buf, bufsize); flb_free(buf); return 0; } From 74895a5529f4705a944df576d8465b88f4982af9 Mon Sep 17 00:00:00 2001 From: Thiago Padilha Date: Mon, 29 May 2023 09:18:44 -0300 Subject: [PATCH 100/315] in_kafka: Implement "data_format" config option. This option allows automatic parsing of kafka messages payload with the specified format. Right now only "json" is supported. Signed-off-by: Thiago Padilha --- plugins/in_kafka/in_kafka.c | 29 ++++++++++++++++++++++++++--- plugins/in_kafka/in_kafka.h | 9 ++++++++- 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/plugins/in_kafka/in_kafka.c b/plugins/in_kafka/in_kafka.c index 9cc70316684..8ae1cf47a07 100644 --- a/plugins/in_kafka/in_kafka.c +++ b/plugins/in_kafka/in_kafka.c @@ -56,9 +56,10 @@ static int try_json(struct flb_log_event_encoder *log_encoder, return 0; } -static int process_message(struct flb_log_event_encoder *log_encoder, +static int process_message(struct flb_in_kafka_config *ctx, rd_kafka_message_t *rkm) { + struct flb_log_event_encoder *log_encoder = ctx->log_encoder; int ret; ret = flb_log_event_encoder_begin_record(log_encoder); @@ -128,7 +129,8 @@ static int process_message(struct flb_log_event_encoder *log_encoder, if (ret == FLB_EVENT_ENCODER_SUCCESS) { if (rkm->payload) { - if (try_json(log_encoder, rkm)) { + if (ctx->data_format != FLB_IN_KAFKA_DATA_FORMAT_JSON || + try_json(log_encoder, rkm)) { ret = flb_log_event_encoder_append_body_string(log_encoder, rkm->payload, rkm->len); @@ -168,7 +170,7 @@ static int in_kafka_collect(struct flb_input_instance *ins, flb_plg_debug(ins, "kafka message received"); - ret = process_message(ctx->log_encoder, rkm); + ret = process_message(ctx, rkm); rd_kafka_message_destroy(rkm); @@ -246,6 +248,22 @@ static int in_kafka_init(struct flb_input_instance *ins, goto init_error; } + conf = flb_input_get_property("data_format", ins); + if (!conf) { + conf = "none"; + } + + if (strcasecmp(conf, "none") == 0) { + ctx->data_format = FLB_IN_KAFKA_DATA_FORMAT_NONE; + } + else if (strcasecmp(conf, "json") == 0) { + ctx->data_format = FLB_IN_KAFKA_DATA_FORMAT_JSON; + } + else { + flb_plg_error(ins, "config: invalid data_format \"%s\"", conf); + goto init_error; + } + if ((err = rd_kafka_subscribe(ctx->kafka.rk, kafka_topics))) { flb_plg_error(ins, "Failed to start consuming topics: %s", rd_kafka_err2str(err)); goto init_error; @@ -327,6 +345,11 @@ static struct flb_config_map config_map[] = { 0, FLB_FALSE, 0, "Set the kafka topics, delimited by commas." }, + { + FLB_CONFIG_MAP_STR, "data_format", (char *)NULL, + 0, FLB_FALSE, 0, + "Set the data format which will be used for parsing records." + }, { FLB_CONFIG_MAP_STR, "brokers", (char *)NULL, 0, FLB_FALSE, 0, diff --git a/plugins/in_kafka/in_kafka.h b/plugins/in_kafka/in_kafka.h index 25b114fa40e..c1db9fdf5b3 100644 --- a/plugins/in_kafka/in_kafka.h +++ b/plugins/in_kafka/in_kafka.h @@ -28,13 +28,20 @@ #include -#define FLB_IN_KAFKA_DEFAULT_POLL_MS "500" +#define FLB_IN_KAFKA_DEFAULT_POLL_MS "500" +#define FLB_IN_KAFKA_DEFAULT_DATA_FORMAT "none" + +enum { + FLB_IN_KAFKA_DATA_FORMAT_NONE, + FLB_IN_KAFKA_DATA_FORMAT_JSON, +}; struct flb_in_kafka_config { struct flb_kafka kafka; struct flb_input_instance *ins; struct flb_log_event_encoder *log_encoder; int poll_ms; + int data_format; }; #endif From 9b348d1dfa614bbc78c1565ba6c39c721ff39c8d Mon Sep 17 00:00:00 2001 From: Thiago Padilha Date: Mon, 29 May 2023 12:28:41 -0300 Subject: [PATCH 101/315] examples: Update kafka_filter example conf Signed-off-by: Thiago Padilha --- examples/kafka_filter/Dockerfile | 4 ++-- examples/kafka_filter/kafka.conf | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/kafka_filter/Dockerfile b/examples/kafka_filter/Dockerfile index 8e9aeffb927..5a18e63e617 100644 --- a/examples/kafka_filter/Dockerfile +++ b/examples/kafka_filter/Dockerfile @@ -1,7 +1,7 @@ FROM debian:bullseye-slim as builder ENV DEBIAN_FRONTEND noninteractive -ENV KAFKA_URL https://downloads.apache.org/kafka/3.4.0/kafka_2.13-3.4.0.tgz -ENV KAFKA_SHA256 67025feb03eb963a8852d4adc5b2810744f493a672c5992728955e38bed43da8 +ENV KAFKA_URL https://downloads.apache.org/kafka/3.4.1/kafka_2.13-3.4.1.tgz +ENV KAFKA_SHA256 a76f17a52b8f2cd31de11571ff366a714820b6e4e02893b0159d09db0edaf998 # hadolint ignore=DL3008 RUN apt-get update && \ diff --git a/examples/kafka_filter/kafka.conf b/examples/kafka_filter/kafka.conf index b7fd3afcecd..23992ffed9c 100644 --- a/examples/kafka_filter/kafka.conf +++ b/examples/kafka_filter/kafka.conf @@ -8,6 +8,7 @@ brokers kafka-broker:9092 topics fb-source poll_ms 100 + data_format json [FILTER] Name lua From 9bae8f09eb34f76e416591199ca99ceb48f55a8b Mon Sep 17 00:00:00 2001 From: Thiago Padilha Date: Tue, 20 Jun 2023 09:06:41 -0300 Subject: [PATCH 102/315] in_kafka: Use config map to fetch data_format option Signed-off-by: Thiago Padilha --- plugins/in_kafka/in_kafka.c | 15 +++++---------- plugins/in_kafka/in_kafka.h | 1 + 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/plugins/in_kafka/in_kafka.c b/plugins/in_kafka/in_kafka.c index 8ae1cf47a07..acd08fcb3bb 100644 --- a/plugins/in_kafka/in_kafka.c +++ b/plugins/in_kafka/in_kafka.c @@ -248,19 +248,14 @@ static int in_kafka_init(struct flb_input_instance *ins, goto init_error; } - conf = flb_input_get_property("data_format", ins); - if (!conf) { - conf = "none"; - } - - if (strcasecmp(conf, "none") == 0) { + if (strcasecmp(ctx->data_format_str, "none") == 0) { ctx->data_format = FLB_IN_KAFKA_DATA_FORMAT_NONE; } - else if (strcasecmp(conf, "json") == 0) { + else if (strcasecmp(ctx->data_format_str, "json") == 0) { ctx->data_format = FLB_IN_KAFKA_DATA_FORMAT_JSON; } else { - flb_plg_error(ins, "config: invalid data_format \"%s\"", conf); + flb_plg_error(ins, "config: invalid data_format \"%s\"", ctx->data_format_str); goto init_error; } @@ -346,8 +341,8 @@ static struct flb_config_map config_map[] = { "Set the kafka topics, delimited by commas." }, { - FLB_CONFIG_MAP_STR, "data_format", (char *)NULL, - 0, FLB_FALSE, 0, + FLB_CONFIG_MAP_STR, "data_format", FLB_IN_KAFKA_DEFAULT_DATA_FORMAT, + 0, FLB_TRUE, offsetof(struct flb_in_kafka_config, data_format_str), "Set the data format which will be used for parsing records." }, { diff --git a/plugins/in_kafka/in_kafka.h b/plugins/in_kafka/in_kafka.h index c1db9fdf5b3..7ec50c214a5 100644 --- a/plugins/in_kafka/in_kafka.h +++ b/plugins/in_kafka/in_kafka.h @@ -42,6 +42,7 @@ struct flb_in_kafka_config { struct flb_log_event_encoder *log_encoder; int poll_ms; int data_format; + char *data_format_str; }; #endif From d810d5fcf59ddb7afbe50260e1f67a68e96facf3 Mon Sep 17 00:00:00 2001 From: Thiago Padilha Date: Sun, 16 Jul 2023 23:09:13 -0300 Subject: [PATCH 103/315] in_kafka: rename data_format to format Signed-off-by: Thiago Padilha --- examples/kafka_filter/kafka.conf | 2 +- plugins/in_kafka/in_kafka.c | 17 ++++++++--------- plugins/in_kafka/in_kafka.h | 10 +++++----- 3 files changed, 14 insertions(+), 15 deletions(-) diff --git a/examples/kafka_filter/kafka.conf b/examples/kafka_filter/kafka.conf index 23992ffed9c..2c3daf7823f 100644 --- a/examples/kafka_filter/kafka.conf +++ b/examples/kafka_filter/kafka.conf @@ -8,7 +8,7 @@ brokers kafka-broker:9092 topics fb-source poll_ms 100 - data_format json + format json [FILTER] Name lua diff --git a/plugins/in_kafka/in_kafka.c b/plugins/in_kafka/in_kafka.c index acd08fcb3bb..972ae41706d 100644 --- a/plugins/in_kafka/in_kafka.c +++ b/plugins/in_kafka/in_kafka.c @@ -19,7 +19,6 @@ */ #include -#include #include #include #include @@ -129,7 +128,7 @@ static int process_message(struct flb_in_kafka_config *ctx, if (ret == FLB_EVENT_ENCODER_SUCCESS) { if (rkm->payload) { - if (ctx->data_format != FLB_IN_KAFKA_DATA_FORMAT_JSON || + if (ctx->format != FLB_IN_KAFKA_FORMAT_JSON || try_json(log_encoder, rkm)) { ret = flb_log_event_encoder_append_body_string(log_encoder, rkm->payload, @@ -248,14 +247,14 @@ static int in_kafka_init(struct flb_input_instance *ins, goto init_error; } - if (strcasecmp(ctx->data_format_str, "none") == 0) { - ctx->data_format = FLB_IN_KAFKA_DATA_FORMAT_NONE; + if (strcasecmp(ctx->format_str, "none") == 0) { + ctx->format = FLB_IN_KAFKA_FORMAT_NONE; } - else if (strcasecmp(ctx->data_format_str, "json") == 0) { - ctx->data_format = FLB_IN_KAFKA_DATA_FORMAT_JSON; + else if (strcasecmp(ctx->format_str, "json") == 0) { + ctx->format = FLB_IN_KAFKA_FORMAT_JSON; } else { - flb_plg_error(ins, "config: invalid data_format \"%s\"", ctx->data_format_str); + flb_plg_error(ins, "config: invalid format \"%s\"", ctx->format_str); goto init_error; } @@ -341,8 +340,8 @@ static struct flb_config_map config_map[] = { "Set the kafka topics, delimited by commas." }, { - FLB_CONFIG_MAP_STR, "data_format", FLB_IN_KAFKA_DEFAULT_DATA_FORMAT, - 0, FLB_TRUE, offsetof(struct flb_in_kafka_config, data_format_str), + FLB_CONFIG_MAP_STR, "format", FLB_IN_KAFKA_DEFAULT_FORMAT, + 0, FLB_TRUE, offsetof(struct flb_in_kafka_config, format_str), "Set the data format which will be used for parsing records." }, { diff --git a/plugins/in_kafka/in_kafka.h b/plugins/in_kafka/in_kafka.h index 7ec50c214a5..2992efff152 100644 --- a/plugins/in_kafka/in_kafka.h +++ b/plugins/in_kafka/in_kafka.h @@ -29,11 +29,11 @@ #define FLB_IN_KAFKA_DEFAULT_POLL_MS "500" -#define FLB_IN_KAFKA_DEFAULT_DATA_FORMAT "none" +#define FLB_IN_KAFKA_DEFAULT_FORMAT "none" enum { - FLB_IN_KAFKA_DATA_FORMAT_NONE, - FLB_IN_KAFKA_DATA_FORMAT_JSON, + FLB_IN_KAFKA_FORMAT_NONE, + FLB_IN_KAFKA_FORMAT_JSON, }; struct flb_in_kafka_config { @@ -41,8 +41,8 @@ struct flb_in_kafka_config { struct flb_input_instance *ins; struct flb_log_event_encoder *log_encoder; int poll_ms; - int data_format; - char *data_format_str; + int format; + char *format_str; }; #endif From 14f995ffc4363d2e91665dbcb6a3429d9f22ddc7 Mon Sep 17 00:00:00 2001 From: Phillip Whelan Date: Thu, 20 Jul 2023 10:25:10 -0400 Subject: [PATCH 104/315] in_http: add support for form/url_encoded payloads. (#6960) --------- Signed-off-by: Phillip Whelan --- plugins/in_http/http_prot.c | 145 +++++++++++++++++++++++++++++++++++- 1 file changed, 144 insertions(+), 1 deletion(-) diff --git a/plugins/in_http/http_prot.c b/plugins/in_http/http_prot.c index 4ae4f35d245..ab16eb328c5 100644 --- a/plugins/in_http/http_prot.c +++ b/plugins/in_http/http_prot.c @@ -28,7 +28,52 @@ #include "http.h" #include "http_conn.h" -#define HTTP_CONTENT_JSON 0 +#define HTTP_CONTENT_JSON 0 +#define HTTP_CONTENT_URLENCODED 1 + +static inline char hex2nibble(char c) +{ + if ((c >= 0x30) && (c <= '9')) { + return c - 0x30; + } + // 0x30-0x39 are digits, 0x41-0x46 A-F, + // so there is a gap at 0x40 + if ((c >= 'A') && (c <= 'F')) { + return (c - 'A') + 10; + } + if ((c >= 'a') && (c <= 'f')) { + return (c - 'a') + 10; + } + return 0; +} + +static int sds_uri_decode(flb_sds_t s) +{ + char buf[1024]; + char *optr; + char *iptr; + + + for (optr = buf, iptr = s; iptr < s + flb_sds_len(s) && optr-buf < sizeof(buf); iptr++) { + if (*iptr == '%') { + if (iptr+2 > (s + flb_sds_len(s))) { + return -1; + } + *optr++ = hex2nibble(*(iptr+1)) << 4 | hex2nibble(*(iptr+2)); + iptr+=2; + } else if (*iptr == '+') { + *optr++ = ' '; + } else { + *optr++ = *iptr; + } + } + + memcpy(s, buf, optr-buf); + s[optr-buf] = '\0'; + flb_sds_len_set(s, (optr-buf)); + + return 0; +} static int send_response(struct http_conn *conn, int http_status, char *message) { @@ -350,6 +395,97 @@ static ssize_t parse_payload_json(struct flb_http *ctx, flb_sds_t tag, return 0; } +static ssize_t parse_payload_urlencoded(struct flb_http *ctx, flb_sds_t tag, + char *payload, size_t size) +{ + struct mk_list *kvs; + struct mk_list *head = NULL; + struct flb_split_entry *cur = NULL; + char **keys = NULL; + char **vals = NULL; + char *sep; + char *start; + int idx = 0; + int ret = -1; + msgpack_packer pck; + msgpack_sbuffer sbuf; + + + /* initialize buffers */ + msgpack_sbuffer_init(&sbuf); + msgpack_packer_init(&pck, &sbuf, msgpack_sbuffer_write); + + kvs = flb_utils_split(payload, '&', -1 ); + if (kvs == NULL) { + goto split_error; + } + + keys = flb_calloc(mk_list_size(kvs), sizeof(char *)); + if (keys == NULL) { + goto keys_calloc_error; + } + + vals = flb_calloc(mk_list_size(kvs), sizeof(char *)); + if (vals == NULL) { + goto vals_calloc_error; + } + + mk_list_foreach(head, kvs) { + cur = mk_list_entry(head, struct flb_split_entry, _head); + if (cur->value[0] == '\n') { + start = &cur->value[1]; + } else { + start = cur->value; + } + sep = strchr(start, '='); + if (sep == NULL) { + vals[idx] = NULL; + continue; + } + *sep++ = '\0'; + + keys[idx] = flb_sds_create_len(start, strlen(start)); + vals[idx] = flb_sds_create_len(sep, strlen(sep)); + + flb_sds_trim(keys[idx]); + flb_sds_trim(vals[idx]); + idx++; + } + + msgpack_pack_map(&pck, mk_list_size(kvs)); + for (idx = 0; idx < mk_list_size(kvs); idx++) { + msgpack_pack_str(&pck, flb_sds_len(keys[idx])); + msgpack_pack_str_body(&pck, keys[idx], flb_sds_len(keys[idx])); + + if (sds_uri_decode(vals[idx]) != 0) { + goto decode_error; + } else { + msgpack_pack_str(&pck, flb_sds_len(vals[idx])); + msgpack_pack_str_body(&pck, vals[idx], strlen(vals[idx])); + } + } + + ret = process_pack(ctx, tag, sbuf.data, sbuf.size); + +decode_error: + for (idx = 0; idx < mk_list_size(kvs); idx++) { + if (keys[idx]) { + flb_sds_destroy(keys[idx]); + } + if (vals[idx]) { + flb_sds_destroy(vals[idx]); + } + } + flb_free(vals); +vals_calloc_error: + flb_free(keys); +keys_calloc_error: + flb_utils_split_free(kvs); +split_error: + msgpack_sbuffer_destroy(&sbuf); + return ret; +} + static int process_payload(struct flb_http *ctx, struct http_conn *conn, flb_sds_t tag, struct mk_http_session *session, @@ -369,6 +505,11 @@ static int process_payload(struct flb_http *ctx, struct http_conn *conn, type = HTTP_CONTENT_JSON; } + if (header->val.len == 33 && + strncasecmp(header->val.data, "application/x-www-form-urlencoded", 33) == 0) { + type = HTTP_CONTENT_URLENCODED; + } + if (type == -1) { send_response(conn, 400, "error: invalid 'Content-Type'\n"); return -1; @@ -381,6 +522,8 @@ static int process_payload(struct flb_http *ctx, struct http_conn *conn, if (type == HTTP_CONTENT_JSON) { parse_payload_json(ctx, tag, request->data.data, request->data.len); + } else if (type == HTTP_CONTENT_URLENCODED) { + parse_payload_urlencoded(ctx, tag, request->data.data, request->data.len); } return 0; From 6b786046033b4a9ada5794ae0794c862facfca6a Mon Sep 17 00:00:00 2001 From: Phillip Whelan Date: Tue, 18 Jul 2023 21:42:49 -0400 Subject: [PATCH 105/315] out_statsd: add missing FLB_INPUT_NET_SERVER flag. Signed-off-by: Phillip Whelan --- plugins/in_statsd/statsd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/in_statsd/statsd.c b/plugins/in_statsd/statsd.c index 171f364a2bb..0cccb679af1 100644 --- a/plugins/in_statsd/statsd.c +++ b/plugins/in_statsd/statsd.c @@ -382,5 +382,5 @@ struct flb_input_plugin in_statsd_plugin = { .cb_resume = cb_statsd_resume, .cb_exit = cb_statsd_exit, .config_map = config_map, - .flags = 0 + .flags = FLB_INPUT_NET_SERVER, }; From 013b1adcf573b59f1acd32e326a939bbb79ab372 Mon Sep 17 00:00:00 2001 From: Phillip Whelan Date: Tue, 18 Jul 2023 21:43:25 -0400 Subject: [PATCH 106/315] in_collectd: add missing FLB_INPUT_NET_SERVER flag. Signed-off-by: Phillip Whelan --- plugins/in_collectd/in_collectd.c | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/in_collectd/in_collectd.c b/plugins/in_collectd/in_collectd.c index 70cf9d0bb16..06ef5ae8a53 100644 --- a/plugins/in_collectd/in_collectd.c +++ b/plugins/in_collectd/in_collectd.c @@ -221,5 +221,6 @@ struct flb_input_plugin in_collectd_plugin = { .cb_pause = NULL, .cb_resume = NULL, .config_map = config_map, + .flags = FLB_INPUT_NET_SERVER, .cb_exit = in_collectd_exit }; From 9e5d567aaed75ff2b6cc8a6b9913bb69d4b4d044 Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Thu, 20 Jul 2023 22:24:52 -0600 Subject: [PATCH 107/315] lib: monkey: upgrade to v1.7.1 (fix warnings) Signed-off-by: Eduardo Silva --- lib/monkey/CMakeLists.txt | 2 +- lib/monkey/include/monkey/mk_config.h | 4 ++-- lib/monkey/include/monkey/mk_mimetype.h | 4 ++-- lib/monkey/include/monkey/mk_plugin.h | 4 ++-- lib/monkey/include/monkey/mk_server.h | 4 ++-- lib/monkey/include/monkey/monkey.h | 2 +- lib/monkey/mk_bin/mk_signals.h | 2 +- lib/monkey/mk_server/mk_server.c | 2 -- 8 files changed, 11 insertions(+), 13 deletions(-) diff --git a/lib/monkey/CMakeLists.txt b/lib/monkey/CMakeLists.txt index 198251d8e8e..6211abaaf5a 100644 --- a/lib/monkey/CMakeLists.txt +++ b/lib/monkey/CMakeLists.txt @@ -23,7 +23,7 @@ endif() # Monkey Version set(MK_VERSION_MAJOR 1) set(MK_VERSION_MINOR 7) -set(MK_VERSION_PATCH 0) +set(MK_VERSION_PATCH 1) set(MK_VERSION_STR "${MK_VERSION_MAJOR}.${MK_VERSION_MINOR}.${MK_VERSION_PATCH}") # Output paths diff --git a/lib/monkey/include/monkey/mk_config.h b/lib/monkey/include/monkey/mk_config.h index 349743de9cc..f6552815347 100644 --- a/lib/monkey/include/monkey/mk_config.h +++ b/lib/monkey/include/monkey/mk_config.h @@ -216,8 +216,8 @@ void mk_config_error(const char *path, int line, const char *msg); struct mk_config_listener *mk_config_listener_add(char *address, char *port, int flags, struct mk_server *server); -int mk_config_listen_check_busy(); -void mk_config_listeners_free(); +int mk_config_listen_check_busy(struct mk_server *server); +void mk_config_listeners_free(struct mk_server *server); int mk_config_get_bool(char *value); void mk_config_read_hosts(char *path); diff --git a/lib/monkey/include/monkey/mk_mimetype.h b/lib/monkey/include/monkey/mk_mimetype.h index 71d253f8747..4c45cbde3af 100644 --- a/lib/monkey/include/monkey/mk_mimetype.h +++ b/lib/monkey/include/monkey/mk_mimetype.h @@ -37,9 +37,9 @@ struct mk_mimetype int mk_mimetype_init(struct mk_server *server); int mk_mimetype_add(struct mk_server *server, char *name, const char *type); -int mk_mimetype_read_config(); +int mk_mimetype_read_config(struct mk_server *server); struct mk_mimetype *mk_mimetype_find(struct mk_server *server, mk_ptr_t *filename); struct mk_mimetype *mk_mimetype_lookup(struct mk_server *server, char *name); -void mk_mimetype_free_all(); +void mk_mimetype_free_all(struct mk_server *server); #endif diff --git a/lib/monkey/include/monkey/mk_plugin.h b/lib/monkey/include/monkey/mk_plugin.h index 76d54025d99..c180c143ae5 100644 --- a/lib/monkey/include/monkey/mk_plugin.h +++ b/lib/monkey/include/monkey/mk_plugin.h @@ -273,7 +273,7 @@ struct mk_plugin { /* Init Levels */ int (*master_init) (struct mk_server *); - void (*worker_init) (); + void (*worker_init) (struct mk_server *); /* Callback references for plugin type */ struct mk_plugin_network *network; /* MK_NETWORK_LAYER */ @@ -328,7 +328,7 @@ int mk_plugin_stage_run(unsigned int stage, struct mk_http_session *cs, struct mk_http_request *sr); void mk_plugin_core_process(struct mk_server *server); -void mk_plugin_core_thread(); +void mk_plugin_core_thread(struct mk_server *server); void mk_plugin_preworker_calls(struct mk_server *server); diff --git a/lib/monkey/include/monkey/mk_server.h b/lib/monkey/include/monkey/mk_server.h index a524f18fa67..f84a7d632e2 100644 --- a/lib/monkey/include/monkey/mk_server.h +++ b/lib/monkey/include/monkey/mk_server.h @@ -68,8 +68,8 @@ struct mk_list *mk_server_listen_init(struct mk_server *server); unsigned int mk_server_capacity(struct mk_server *server); void mk_server_launch_workers(struct mk_server *server); void mk_server_worker_loop(struct mk_server *server); -void mk_server_loop_balancer(); -void mk_server_worker_loop(); +void mk_server_loop_balancer(struct mk_server *server); +void mk_server_worker_loop(struct mk_server *server); void mk_server_loop(struct mk_server *server); #endif diff --git a/lib/monkey/include/monkey/monkey.h b/lib/monkey/include/monkey/monkey.h index 8eb28302bf7..0da8901e3ae 100644 --- a/lib/monkey/include/monkey/monkey.h +++ b/lib/monkey/include/monkey/monkey.h @@ -64,7 +64,7 @@ extern const mk_ptr_t mk_monkey_protocol; struct mk_server *mk_server_init(); -void mk_server_info(); +void mk_server_info(struct mk_server *server); int mk_server_setup(struct mk_server *server); void mk_thread_keys_init(); void mk_exit_all(struct mk_server *config); diff --git a/lib/monkey/mk_bin/mk_signals.h b/lib/monkey/mk_bin/mk_signals.h index f0fdc85f19c..a1eb731d544 100644 --- a/lib/monkey/mk_bin/mk_signals.h +++ b/lib/monkey/mk_bin/mk_signals.h @@ -20,7 +20,7 @@ #ifndef MK_SIGNAL_H #define MK_SIGNAL_H -void mk_signal_init(); +void mk_signal_init(struct mk_server *server); void mk_signal_context(struct mk_server *ctx); void mk_signal_thread_sigpipe_safe(void); diff --git a/lib/monkey/mk_server/mk_server.c b/lib/monkey/mk_server/mk_server.c index 557fe8faf24..a84ef448571 100644 --- a/lib/monkey/mk_server/mk_server.c +++ b/lib/monkey/mk_server/mk_server.c @@ -167,7 +167,6 @@ void mk_server_listen_exit(struct mk_list *list) struct mk_list *mk_server_listen_init(struct mk_server *server) { - int i = 0; int server_fd; int reuse_port = MK_FALSE; struct mk_list *head; @@ -254,7 +253,6 @@ struct mk_list *mk_server_listen_init(struct mk_server *server) listen->port); return NULL; } - i += 1; } if (reuse_port == MK_TRUE) { From 295d9eedbc20dc3423af3950f530bed0b8f7c367 Mon Sep 17 00:00:00 2001 From: Phillip Whelan Date: Fri, 21 Jul 2023 15:43:49 -0400 Subject: [PATCH 108/315] trace: add new command line options for enabling tracing at startup. (#6726) Add new command line options to enable tracing from the start: * --trace: define a complete trace pipeline in a single line. * --trace-input: define the input to trace. * --trace-output: define the trace output. * --trace-output-property: define a trace output property. Signed-off-by: Phillip Whelan --- include/fluent-bit/flb_lib.h | 1 + src/flb_chunk_trace.c | 2 +- src/flb_lib.c | 24 +++- src/fluent-bit.c | 231 +++++++++++++++++++++++++++++++++ src/http_server/api/v1/trace.c | 2 +- 5 files changed, 255 insertions(+), 5 deletions(-) diff --git a/include/fluent-bit/flb_lib.h b/include/fluent-bit/flb_lib.h index eb32ad6258e..b5383dace3f 100644 --- a/include/fluent-bit/flb_lib.h +++ b/include/fluent-bit/flb_lib.h @@ -72,6 +72,7 @@ FLB_EXPORT double flb_time_now(); /* start stop the engine */ FLB_EXPORT int flb_start(flb_ctx_t *ctx); +FLB_EXPORT int flb_start_trace(flb_ctx_t *ctx); FLB_EXPORT int flb_stop(flb_ctx_t *ctx); FLB_EXPORT int flb_loop(flb_ctx_t *ctx); diff --git a/src/flb_chunk_trace.c b/src/flb_chunk_trace.c index f3198964ebb..adacb73f21a 100644 --- a/src/flb_chunk_trace.c +++ b/src/flb_chunk_trace.c @@ -230,7 +230,7 @@ struct flb_chunk_trace_context *flb_chunk_trace_context_new(void *trace_input, ctx->input = (void *)input; ctx->trace_prefix = flb_sds_create(trace_prefix); - flb_start(ctx->flb); + flb_start_trace(ctx->flb); in->chunk_trace_ctxt = ctx; pthread_mutex_unlock(&in->chunk_trace_lock); diff --git a/src/flb_lib.c b/src/flb_lib.c index 7ac336d7529..882faa54757 100644 --- a/src/flb_lib.c +++ b/src/flb_lib.c @@ -653,8 +653,7 @@ double flb_time_now() return flb_time_to_double(&t); } -/* Start the engine */ -int flb_start(flb_ctx_t *ctx) +int static do_start(flb_ctx_t *ctx) { int fd; int bytes; @@ -669,7 +668,6 @@ int flb_start(flb_ctx_t *ctx) flb_debug("[lib] context set: %p", ctx); /* set context as the last active one */ - flb_context_set(ctx); /* spawn worker thread */ config = ctx->config; @@ -715,6 +713,26 @@ int flb_start(flb_ctx_t *ctx) return 0; } +/* Start the engine */ +int flb_start(flb_ctx_t *ctx) +{ + int ret; + + ret = do_start(ctx); + if (ret == 0) { + /* set context as the last active one */ + flb_context_set(ctx); + } + + return ret; +} + +/* Start the engine without setting the global context */ +int flb_start_trace(flb_ctx_t *ctx) +{ + return do_start(ctx); +} + int flb_loop(flb_ctx_t *ctx) { while (ctx->status == FLB_LIB_OK) { diff --git a/src/fluent-bit.c b/src/fluent-bit.c index 46e159b2159..12fc8d09de9 100644 --- a/src/fluent-bit.c +++ b/src/fluent-bit.c @@ -78,6 +78,17 @@ volatile sig_atomic_t flb_bin_restarting = FLB_RELOAD_IDLE; struct flb_stacktrace flb_st; #endif +#ifdef FLB_HAVE_CHUNK_TRACE + +#include + +#define FLB_LONG_TRACE (1024 + 1) +#define FLB_LONG_TRACE_INPUT (1024 + 2) +#define FLB_LONG_TRACE_OUTPUT (1024 + 3) +#define FLB_LONG_TRACE_OUTPUT_PROPERTY (1024 + 4) + +#endif + #define FLB_HELP_TEXT 0 #define FLB_HELP_JSON 1 @@ -138,6 +149,10 @@ static void flb_help(int rc, struct flb_config *config) #endif #ifdef FLB_HAVE_CHUNK_TRACE print_opt("-Z, --enable-chunk-trace", "enable chunk tracing. activating it requires using the HTTP Server API."); + print_opt("--trace-input", "input to start tracing on startup."); + print_opt("--trace-output", "output to use for tracing on startup."); + print_opt("--trace-output-property", "set a property for output tracing on startup."); + print_opt("--trace", "setup a trace pipeline on startup. Uses a single line, ie: \"input=dummy.0 output=stdout output.format='json'\""); #endif print_opt("-w, --workdir", "set the working directory"); #ifdef FLB_HAVE_HTTP_SERVER @@ -726,6 +741,173 @@ static struct flb_cf *service_configure(struct flb_cf *cf, return cf; } +#ifdef FLB_HAVE_CHUNK_TRACE +static struct flb_input_instance *find_input(flb_ctx_t *ctx, const char *name) +{ + struct mk_list *head; + struct flb_input_instance *in; + + + mk_list_foreach(head, &ctx->config->inputs) { + in = mk_list_entry(head, struct flb_input_instance, _head); + if (strcmp(name, in->name) == 0) { + return in; + } + if (in->alias) { + if (strcmp(name, in->alias) == 0) { + return in; + } + } + } + return NULL; +} + +static int enable_trace_input(flb_ctx_t *ctx, const char *name, const char *prefix, const char *output_name, struct mk_list *props) +{ + struct flb_input_instance *in; + + + in = find_input(ctx, name); + if (in == NULL) { + return FLB_ERROR; + } + + flb_chunk_trace_context_new(in, output_name, prefix, NULL, props); + return (in->chunk_trace_ctxt == NULL ? FLB_ERROR : FLB_OK); +} + +static int disable_trace_input(flb_ctx_t *ctx, const char *name) +{ + struct flb_input_instance *in; + + + in = find_input(ctx, name); + if (in == NULL) { + return FLB_ERROR; + } + + if (in->chunk_trace_ctxt != NULL) { + flb_chunk_trace_context_destroy(in); + } + return FLB_OK; +} + +static int set_trace_property(struct mk_list *props, char *kv) +{ + int len; + int sep; + char *key; + char *value; + + len = strlen(kv); + sep = mk_string_char_search(kv, '=', len); + if (sep == -1) { + return -1; + } + + key = mk_string_copy_substr(kv, 0, sep); + value = kv + sep + 1; + + if (!key) { + return -1; + } + + flb_kv_item_create_len(props, + (char *)key, strlen(key), + (char *)value, strlen(value)); + + mk_mem_free(key); + return 0; +} + +static int parse_trace_pipeline_prop(flb_ctx_t *ctx, const char *kv, char **key, char **value) +{ + int len; + int sep; + + len = strlen(kv); + sep = mk_string_char_search(kv, '=', len); + if (sep == -1) { + return FLB_ERROR; + } + + *key = mk_string_copy_substr(kv, 0, sep); + if (!key) { + return FLB_ERROR; + } + + *value = flb_strdup(kv + sep + 1); + return FLB_OK; +} + +static int parse_trace_pipeline(flb_ctx_t *ctx, const char *pipeline, char **trace_input, char **trace_output, struct mk_list **props) +{ + struct mk_list *parts = NULL; + struct mk_list *cur; + struct flb_split_entry *part; + char *key; + char *value; + const char *propname; + const char *propval; + + + parts = flb_utils_split(pipeline, (int)' ', 0); + if (parts == NULL) { + return FLB_ERROR; + } + + mk_list_foreach(cur, parts) { + key = NULL; + value = NULL; + part = mk_list_entry(cur, struct flb_split_entry, _head); + if (parse_trace_pipeline_prop(ctx, part->value, &key, &value) == FLB_ERROR) { + return FLB_ERROR; + } + if (strcmp(key, "input") == 0) { + if (*trace_input != NULL) { + flb_free(*trace_input); + } + *trace_input = flb_strdup(value); + } + else if (strcmp(key, "output") == 0) { + if (*trace_output != NULL) { + flb_free(*trace_output); + } + *trace_output = flb_strdup(value); + } + else if (strncmp(key, "output.", strlen("output.")) == 0) { + propname = mk_string_copy_substr(key, strlen("output."), strlen(key)); + if (propname == NULL) { + return FLB_ERROR; + } + + propval = flb_strdup(value); + if (propval == NULL) { + return FLB_ERROR; + } + + if (*props == NULL) { + *props = flb_calloc(1, sizeof(struct mk_list)); + flb_kv_init(*props); + } + + flb_kv_item_create_len(*props, + (char *)propname, strlen(propname), + (char *)propval, strlen(propval)); + } + if (key != NULL) { + mk_mem_free(key); + } + if (value != NULL) { + flb_free(value); + } + } + + flb_utils_split_free(parts); + return FLB_OK; +} +#endif + int flb_main(int argc, char **argv) { int opt; @@ -762,6 +944,12 @@ int flb_main(int argc, char **argv) flb_stacktrace_init(argv[0], &flb_st); #endif +#ifdef FLB_HAVE_CHUNK_TRACE + char *trace_input = NULL; + char *trace_output = flb_strdup("stdout"); + struct mk_list *trace_props = NULL; +#endif + /* Setup long-options */ static const struct option long_opts[] = { { "storage_path", required_argument, NULL, 'b' }, @@ -804,6 +992,10 @@ int flb_main(int argc, char **argv) { "enable-hot-reload", no_argument, NULL, 'Y' }, #ifdef FLB_HAVE_CHUNK_TRACE { "enable-chunk-trace", no_argument, NULL, 'Z' }, + { "trace", required_argument, NULL, FLB_LONG_TRACE }, + { "trace-input", required_argument, NULL, FLB_LONG_TRACE_INPUT }, + { "trace-output", required_argument, NULL, FLB_LONG_TRACE_OUTPUT }, + { "trace-output-property", required_argument, NULL, FLB_LONG_TRACE_OUTPUT_PROPERTY }, #endif { "disable-thread-safety-on-hot-reload", no_argument, NULL, 'W' }, { NULL, 0, NULL, 0 } @@ -998,6 +1190,28 @@ int flb_main(int argc, char **argv) case 'Z': flb_cf_section_property_add(cf_opts, service->properties, FLB_CONF_STR_ENABLE_CHUNK_TRACE, 0, "on", 0); break; + case FLB_LONG_TRACE: + parse_trace_pipeline(ctx, optarg, &trace_input, &trace_output, &trace_props); + break; + case FLB_LONG_TRACE_INPUT: + if (trace_input != NULL) { + flb_free(trace_input); + } + trace_input = flb_strdup(optarg); + break; + case FLB_LONG_TRACE_OUTPUT: + if (trace_output != NULL) { + flb_free(trace_output); + } + trace_output = flb_strdup(optarg); + break; + case FLB_LONG_TRACE_OUTPUT_PROPERTY: + if (trace_props == NULL) { + trace_props = flb_calloc(1, sizeof(struct mk_list)); + flb_kv_init(trace_props); + } + set_trace_property(trace_props, optarg); + break; #endif /* FLB_HAVE_CHUNK_TRACE */ default: flb_help(EXIT_FAILURE, config); @@ -1113,6 +1327,12 @@ int flb_main(int argc, char **argv) */ ctx = flb_context_get(); +#ifdef FLB_HAVE_CHUNK_TRACE + if (trace_input != NULL) { + enable_trace_input(ctx, trace_input, NULL /* prefix ... */, trace_output, trace_props); + } +#endif + while (ctx->status == FLB_LIB_OK && exit_signal == 0) { sleep(1); @@ -1130,6 +1350,17 @@ int flb_main(int argc, char **argv) if (cf_opts != NULL) { flb_cf_destroy(cf_opts); } + +#ifdef FLB_HAVE_CHUNK_TRACE + if (trace_input != NULL) { + disable_trace_input(ctx, trace_input); + flb_free(trace_input); + } + if (trace_output) { + flb_free(trace_output); + } +#endif + flb_stop(ctx); flb_destroy(ctx); diff --git a/src/http_server/api/v1/trace.c b/src/http_server/api/v1/trace.c index 1101b06d9b4..95da1734383 100644 --- a/src/http_server/api/v1/trace.c +++ b/src/http_server/api/v1/trace.c @@ -31,7 +31,7 @@ #include -struct flb_input_instance *find_input(struct flb_hs *hs, const char *name) +static struct flb_input_instance *find_input(struct flb_hs *hs, const char *name) { struct mk_list *head; struct flb_input_instance *in; From 1d61d70a0801af723e1ff5de93803ca917d302da Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Thu, 20 Jul 2023 08:35:23 -0600 Subject: [PATCH 109/315] sp: remove unused variable Signed-off-by: Eduardo Silva --- src/stream_processor/flb_sp.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/stream_processor/flb_sp.c b/src/stream_processor/flb_sp.c index d50232194cb..26f9d75865d 100644 --- a/src/stream_processor/flb_sp.c +++ b/src/stream_processor/flb_sp.c @@ -1393,7 +1393,6 @@ int sp_process_data_aggr(const char *buf_data, size_t buf_size, int ret; int map_size; int key_id; - int values_found; size_t off; int64_t ival; double dval; @@ -1455,7 +1454,6 @@ int sp_process_data_aggr(const char *buf_data, size_t buf_size, nums = aggr_node->nums; - values_found = 0; /* Iterate each map key and see if it matches any command key */ for (i = 0; i < map_size; i++) { key = map.via.map.ptr[i].key; @@ -1492,8 +1490,6 @@ int sp_process_data_aggr(const char *buf_data, size_t buf_size, continue; } - values_found++; - /* * Convert value to a numeric representation only if key has an * assigned aggregation function From 3d9d872a2725175cf292b020f083e074b2b91a49 Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Thu, 20 Jul 2023 08:39:28 -0600 Subject: [PATCH 110/315] callback: fix function prototype Signed-off-by: Eduardo Silva --- include/fluent-bit/flb_callback.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/fluent-bit/flb_callback.h b/include/fluent-bit/flb_callback.h index 983ad36e278..e76b8fffd47 100644 --- a/include/fluent-bit/flb_callback.h +++ b/include/fluent-bit/flb_callback.h @@ -37,7 +37,7 @@ struct flb_callback { struct flb_config *config; /* Fluent Bit context */ }; -struct flb_callback *flb_callback_create(); +struct flb_callback *flb_callback_create(char *name); void flb_callback_destroy(struct flb_callback *ctx); int flb_callback_set(struct flb_callback *ctx, char *name, void (*cb)(char *, void *, void *)); From c28d1686eb34184838c7ddc44cbcc70549c4f6a2 Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Thu, 20 Jul 2023 08:42:35 -0600 Subject: [PATCH 111/315] network: initialize result var for unix socket Signed-off-by: Eduardo Silva --- src/flb_network.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/flb_network.c b/src/flb_network.c index f3a0fd2a471..9609e5a0393 100644 --- a/src/flb_network.c +++ b/src/flb_network.c @@ -1806,7 +1806,7 @@ static int net_address_unix_socket_peer_pid_raw(flb_sockfd_t fd, struct ucred peer_credentials; #endif size_t required_buffer_size; - int result; + int result = 0; if (address->ss_family != AF_UNIX) { return -1; From e0a6324349d05c1ee4e031d241c0ead8625f8c5e Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Thu, 20 Jul 2023 08:47:53 -0600 Subject: [PATCH 112/315] utils: fix function prototype Signed-off-by: Eduardo Silva --- include/fluent-bit/flb_utils.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/fluent-bit/flb_utils.h b/include/fluent-bit/flb_utils.h index 0dcbe2e0029..5bc790bab9d 100644 --- a/include/fluent-bit/flb_utils.h +++ b/include/fluent-bit/flb_utils.h @@ -38,7 +38,7 @@ void flb_utils_warn_c(const char *msg); void flb_message(int type, const char *file, int line, const char *fmt, ...); #ifdef FLB_HAVE_FORK -int flb_utils_set_daemon(); +int flb_utils_set_daemon(struct flb_config *config); #endif void flb_utils_print_setup(struct flb_config *config); From b48a9cb4b801751ce398f86cc364dc5fb125333b Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Thu, 20 Jul 2023 08:48:10 -0600 Subject: [PATCH 113/315] time: fix size_t formatter Signed-off-by: Eduardo Silva --- src/flb_time.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/flb_time.c b/src/flb_time.c index 2477c51ccd8..624b70d0209 100644 --- a/src/flb_time.c +++ b/src/flb_time.c @@ -368,7 +368,7 @@ int flb_time_pop_from_mpack(struct flb_time *time, mpack_reader_t *reader) case mpack_type_ext: ext_len = mpack_tag_ext_length(&tag); if (ext_len != 8) { - flb_warn("expecting ext_len is 8, got %" PRId64, ext_len); + flb_warn("expecting ext_len is 8, got %ld", ext_len); return -1; } mpack_read_bytes(reader, extbuf, ext_len); From a840027dc230558b08455a771fdfba9becfdc3c9 Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Thu, 20 Jul 2023 08:50:12 -0600 Subject: [PATCH 114/315] tp: fix function prototype Signed-off-by: Eduardo Silva --- include/fluent-bit/flb_thread_pool.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/fluent-bit/flb_thread_pool.h b/include/fluent-bit/flb_thread_pool.h index 55e2cbb51ef..0ae9df5be66 100644 --- a/include/fluent-bit/flb_thread_pool.h +++ b/include/fluent-bit/flb_thread_pool.h @@ -64,7 +64,7 @@ struct flb_tp_thread *flb_tp_thread_get_rr(struct flb_tp *tp); int flb_tp_thread_start(struct flb_tp *tp, struct flb_tp_thread *th); int flb_tp_thread_start_id(struct flb_tp *tp, int id); int flb_tp_thread_start_all(struct flb_tp *tp); -int flb_tp_thread_stop(); +int flb_tp_thread_stop(struct flb_tp *tp, struct flb_tp_thread *th); int flb_tp_thread_stop_all(struct flb_tp *tp); int flb_tp_thread_destroy(); From 3fa9d1865cd0c9ba50e19c7f806ac2e01ff92fcc Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Thu, 20 Jul 2023 15:43:51 -0600 Subject: [PATCH 115/315] snappy: initialize variable Signed-off-by: Eduardo Silva --- src/flb_snappy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/flb_snappy.c b/src/flb_snappy.c index f74a053ca5d..865e183992a 100644 --- a/src/flb_snappy.c +++ b/src/flb_snappy.c @@ -124,7 +124,7 @@ int flb_snappy_uncompress_framed_data(char *in_data, size_t in_len, size_t uncompressed_chunk_count; int stream_identifier_found; char *aggregated_data_buffer; - size_t aggregated_data_length; + size_t aggregated_data_length = 0; size_t aggregated_data_offset; size_t compressed_chunk_count; struct cfl_list *iterator_backup; From 1b6668e4120a289b0d753038a0cf74bd7d0bef01 Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Thu, 20 Jul 2023 22:23:18 -0600 Subject: [PATCH 116/315] input: remove unused variable Signed-off-by: Eduardo Silva --- src/flb_input.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/flb_input.c b/src/flb_input.c index 9f39c0ebbb7..94aa52cbc43 100644 --- a/src/flb_input.c +++ b/src/flb_input.c @@ -1528,7 +1528,6 @@ static int collector_start(struct flb_input_collector *coll, int flb_input_collector_start(int coll_id, struct flb_input_instance *in) { int ret; - int c = 0; struct mk_list *head; struct flb_input_collector *coll; @@ -1542,7 +1541,6 @@ int flb_input_collector_start(int coll_id, struct flb_input_instance *in) } return ret; } - c++; } return -1; From a55ad3563c4db1672dec52c101bdc0d6f08747e1 Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Thu, 20 Jul 2023 23:10:33 -0600 Subject: [PATCH 117/315] help: initialize variable Signed-off-by: Eduardo Silva --- src/flb_help.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/flb_help.c b/src/flb_help.c index 9247733f6ac..d93f9680be9 100644 --- a/src/flb_help.c +++ b/src/flb_help.c @@ -460,7 +460,7 @@ int flb_help_output(struct flb_output_instance *ins, void **out_buf, size_t *out static int build_plugin_help(struct flb_config *config, int type, char *name, char **out_buf, size_t *out_size) { - void *help_buf; + void *help_buf = NULL; size_t help_size = 0; struct flb_custom_instance *c = NULL; struct flb_input_instance *i = NULL; From 0dd6d4007c11434a50b4fd59d20cedcd1a6249b0 Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Thu, 20 Jul 2023 23:11:15 -0600 Subject: [PATCH 118/315] reload: fix format and remove unused variable Signed-off-by: Eduardo Silva --- src/flb_reload.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/flb_reload.c b/src/flb_reload.c index 6931b71704c..27c5b7f1520 100644 --- a/src/flb_reload.c +++ b/src/flb_reload.c @@ -367,7 +367,6 @@ int flb_reload(flb_ctx_t *ctx, struct flb_cf *cf_opts) struct flb_cf *new_cf; struct flb_cf *original_cf; int verbose; - int enable_reloading; if (ctx == NULL) { flb_error("[reload] given flb context is NULL"); @@ -394,7 +393,7 @@ int flb_reload(flb_ctx_t *ctx, struct flb_cf *cf_opts) return -1; } - flb_info("reloading instance pid=%lu tid=%u", getpid(), pthread_self()); + flb_info("reloading instance pid=%lu tid=%p", (long unsigned) getpid(), pthread_self()); if (old_config->conf_path_file) { file = flb_sds_create(old_config->conf_path_file); From 0e3ac824a3851087ff07a8b6bd3344751d398815 Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Thu, 20 Jul 2023 23:11:36 -0600 Subject: [PATCH 119/315] storage: remove unused variable Signed-off-by: Eduardo Silva --- src/flb_storage.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/flb_storage.c b/src/flb_storage.c index 41bbd9fabc6..3535fae3a4c 100644 --- a/src/flb_storage.c +++ b/src/flb_storage.c @@ -143,7 +143,6 @@ static void metrics_append_input(msgpack_packer *mp_pck, int up; int down; int busy; - int busy_size_err; char *name; ssize_t busy_size; struct mk_list *head; @@ -274,7 +273,6 @@ static void metrics_append_input(msgpack_packer *mp_pck, */ busy = 0; busy_size = 0; - busy_size_err = 0; /* up/down */ up = 0; @@ -289,9 +287,6 @@ static void metrics_append_input(msgpack_packer *mp_pck, if (size >= 0) { busy_size += size; } - else { - busy_size_err++; - } } if (cio_chunk_is_up(ic->chunk) == CIO_TRUE) { From 08d060cfce519d1683dc7e47c9fa02a799b7ca44 Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Thu, 20 Jul 2023 23:12:16 -0600 Subject: [PATCH 120/315] strptime: add variable cast to gmtime_r call Signed-off-by: Eduardo Silva --- src/flb_strptime.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/flb_strptime.c b/src/flb_strptime.c index ae0760937cc..492a6ee7476 100644 --- a/src/flb_strptime.c +++ b/src/flb_strptime.c @@ -402,7 +402,7 @@ again: switch (c = *fmt++) { int64_t i64; if (!(_conv_num64(&bp, &i64, 0, INT64_MAX))) return (NULL); - if (!gmtime_r(&i64, &tm->tm)) + if (!gmtime_r((const time_t *) &i64, &tm->tm)) return (NULL); fields = 0xffff; /* everything */ } From 5acb5490b28e812a837d5e9dff8d4cc0b84009bc Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Thu, 20 Jul 2023 23:12:30 -0600 Subject: [PATCH 121/315] luajit: fix function prototype Signed-off-by: Eduardo Silva --- include/fluent-bit/flb_luajit.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/fluent-bit/flb_luajit.h b/include/fluent-bit/flb_luajit.h index 1586a48c222..440455d83bd 100644 --- a/include/fluent-bit/flb_luajit.h +++ b/include/fluent-bit/flb_luajit.h @@ -34,7 +34,7 @@ struct flb_luajit { struct mk_list _head; /* Link to flb_config->lua */ }; -struct flb_luajit *flb_luajit_create(); +struct flb_luajit *flb_luajit_create(struct flb_config *config); int flb_luajit_load_script(struct flb_luajit *lj, char *script); int flb_luajit_load_buffer(struct flb_luajit *lj, char *string, size_t len, char *name); From f832b7caf33cf541b6045393c0756c931910c5d1 Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Thu, 20 Jul 2023 23:13:02 -0600 Subject: [PATCH 122/315] filter_kubernetes: remove unused variabe Signed-off-by: Eduardo Silva --- plugins/filter_kubernetes/kubernetes.c | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/plugins/filter_kubernetes/kubernetes.c b/plugins/filter_kubernetes/kubernetes.c index e504b40c585..f54e0848316 100644 --- a/plugins/filter_kubernetes/kubernetes.c +++ b/plugins/filter_kubernetes/kubernetes.c @@ -225,7 +225,6 @@ static int pack_map_content(struct flb_log_event_encoder *log_encoder, int i; int map_size = 0; int merge_status = -1; - int new_map_size = 0; int log_index = -1; int log_buf_entries = 0; size_t off = 0; @@ -295,9 +294,6 @@ static int pack_map_content(struct flb_log_event_encoder *log_encoder, return -1; } - /* Determinate the size of the new map */ - new_map_size = map_size; - /* If a merged status exists, check the number of entries to merge */ if (log_index != -1) { if (merge_status == MERGE_PARSED) { @@ -316,23 +312,8 @@ static int pack_map_content(struct flb_log_event_encoder *log_encoder, } } - /* Kubernetes metadata */ - if (kube_buf && kube_size > 0) { - new_map_size++; - } - - if (log_buf_entries > 0) { - if (ctx->merge_log_key != NULL) { - new_map_size++; - } - else { - new_map_size += log_buf_entries; - } - } - if ((merge_status == MERGE_PARSED || merge_status == MERGE_MAP) && ctx->keep_log == FLB_FALSE) { - new_map_size--; } /* Original map */ From c86fab981153e100e9f3e3f0f9f60f13501836ea Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Thu, 20 Jul 2023 23:13:32 -0600 Subject: [PATCH 123/315] filter_multiline: remove unused variable Signed-off-by: Eduardo Silva --- plugins/filter_multiline/ml.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/plugins/filter_multiline/ml.c b/plugins/filter_multiline/ml.c index 79385e123a8..2980de89f0a 100644 --- a/plugins/filter_multiline/ml.c +++ b/plugins/filter_multiline/ml.c @@ -551,7 +551,6 @@ static int ml_filter_partial(const void *data, size_t bytes, msgpack_sbuffer tmp_sbuf; msgpack_packer tmp_pck; int partial_records = 0; - int total_records = 0; int return_records = 0; int partial = FLB_FALSE; int is_last_partial = FLB_FALSE; @@ -619,8 +618,6 @@ static int ml_filter_partial(const void *data, size_t bytes, while ((ret = flb_log_event_decoder_next( &log_decoder, &log_event)) == FLB_EVENT_DECODER_SUCCESS) { - total_records++; - partial = ml_is_partial(log_event.body); if (partial == FLB_TRUE) { partial_records++; From 04b82cb00b680def480210a80ae81ab5a8e06548 Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Thu, 20 Jul 2023 23:14:01 -0600 Subject: [PATCH 124/315] filter_modify: remove unused variab;e Signed-off-by: Eduardo Silva --- plugins/filter_modify/modify.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/plugins/filter_modify/modify.c b/plugins/filter_modify/modify.c index 4bc1a28514b..22d2e21c027 100644 --- a/plugins/filter_modify/modify.c +++ b/plugins/filter_modify/modify.c @@ -682,12 +682,6 @@ static inline bool kv_key_matches_str(msgpack_object_kv * kv, return helper_msgpack_object_matches_str(&kv->key, str, len); } -static inline bool kv_val_matches_str(msgpack_object_kv * kv, - char *str, int len) -{ - return helper_msgpack_object_matches_str(&kv->val, str, len); -} - static inline bool kv_key_matches_str_rule_key(msgpack_object_kv * kv, struct modify_rule *rule) { From d7648e5dc675704fa0bb4f7eb8fdc8425c903540 Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Thu, 20 Jul 2023 23:14:46 -0600 Subject: [PATCH 125/315] filter_nightfall: initialize variable Signed-off-by: Eduardo Silva --- plugins/filter_nightfall/nightfall.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/filter_nightfall/nightfall.c b/plugins/filter_nightfall/nightfall.c index 0cf4c68e495..3e37d2a0bc4 100644 --- a/plugins/filter_nightfall/nightfall.c +++ b/plugins/filter_nightfall/nightfall.c @@ -465,7 +465,7 @@ static int cb_nightfall_filter(const void *data, size_t bytes, int ret; char is_modified = FLB_FALSE; - struct flb_time tmp; + struct flb_time tmp = {0}; char *to_redact; size_t to_redact_size; From 738835fa6233d2822752bcdb89f0f0a0657993d3 Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Thu, 20 Jul 2023 23:15:05 -0600 Subject: [PATCH 126/315] in_forward: remove unused variable Signed-off-by: Eduardo Silva --- plugins/in_forward/fw_prot.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/plugins/in_forward/fw_prot.c b/plugins/in_forward/fw_prot.c index ac1e7408869..2a23b625441 100644 --- a/plugins/in_forward/fw_prot.c +++ b/plugins/in_forward/fw_prot.c @@ -455,7 +455,6 @@ int fw_prot_process(struct flb_input_instance *ins, struct fw_conn *conn) { int ret; int stag_len; - int c = 0; int event_type; int contain_options = FLB_FALSE; size_t index = 0; @@ -705,8 +704,6 @@ int fw_prot_process(struct flb_input_instance *ins, struct fw_conn *conn) out_tag, flb_sds_len(out_tag), &root, &entry, &map, chunk_id, metadata_id); - - c++; } else if (entry.type == MSGPACK_OBJECT_STR || entry.type == MSGPACK_OBJECT_BIN) { From 3fb29b4e10e89249597c530c8dc5236d252692a8 Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Thu, 20 Jul 2023 23:15:58 -0600 Subject: [PATCH 127/315] out_azure_logs_ingestion: initialize variable Signed-off-by: Eduardo Silva --- plugins/out_azure_logs_ingestion/azure_logs_ingestion.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/out_azure_logs_ingestion/azure_logs_ingestion.c b/plugins/out_azure_logs_ingestion/azure_logs_ingestion.c index d2731cfe134..90504537627 100644 --- a/plugins/out_azure_logs_ingestion/azure_logs_ingestion.c +++ b/plugins/out_azure_logs_ingestion/azure_logs_ingestion.c @@ -251,7 +251,7 @@ static void cb_azure_logs_ingestion_flush(struct flb_event_chunk *event_chunk, size_t final_payload_size; flb_sds_t token; struct flb_connection *u_conn; - struct flb_http_client *c; + struct flb_http_client *c = NULL; int is_compressed = FLB_FALSE; flb_sds_t json_payload = NULL; struct flb_az_li *ctx = out_context; From ce495a02fcba5a67d7076a7dc1e692b6fa21c965 Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Thu, 20 Jul 2023 23:16:40 -0600 Subject: [PATCH 128/315] out_prometheus_remote_write: add cast to variable Signed-off-by: Eduardo Silva --- plugins/out_prometheus_remote_write/remote_write.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/out_prometheus_remote_write/remote_write.c b/plugins/out_prometheus_remote_write/remote_write.c index 15422a9db49..2349afd61a0 100644 --- a/plugins/out_prometheus_remote_write/remote_write.c +++ b/plugins/out_prometheus_remote_write/remote_write.c @@ -72,7 +72,7 @@ static int http_post(struct prometheus_remote_write_context *ctx, &payload_buf, &payload_size); } else { - payload_buf = body; + payload_buf = (void *) body; payload_size = body_len; ret = 0; From 9760562859892e4cc5c0f1a32794b393171147ec Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Thu, 20 Jul 2023 23:16:52 -0600 Subject: [PATCH 129/315] out_splunk: remove unused variable Signed-off-by: Eduardo Silva --- plugins/out_splunk/splunk.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/plugins/out_splunk/splunk.c b/plugins/out_splunk/splunk.c index 41cb9938a2f..e9ce5a1bc13 100644 --- a/plugins/out_splunk/splunk.c +++ b/plugins/out_splunk/splunk.c @@ -59,7 +59,6 @@ static int pack_map_meta(struct flb_splunk *ctx, msgpack_object map, char *tag, int tag_len) { - int c = 0; int index_key_set = FLB_FALSE; int sourcetype_key_set = FLB_FALSE; flb_sds_t str; @@ -81,7 +80,6 @@ static int pack_map_meta(struct flb_splunk *ctx, sizeof(FLB_SPLUNK_DEFAULT_EVENT_HOST) - 1); msgpack_pack_str(mp_pck, flb_sds_len(str)); msgpack_pack_str_body(mp_pck, str, flb_sds_len(str)); - c++; } flb_sds_destroy(str); } @@ -100,7 +98,6 @@ static int pack_map_meta(struct flb_splunk *ctx, sizeof(FLB_SPLUNK_DEFAULT_EVENT_SOURCE) - 1); msgpack_pack_str(mp_pck, flb_sds_len(str)); msgpack_pack_str_body(mp_pck, str, flb_sds_len(str)); - c++; } flb_sds_destroy(str); } @@ -121,7 +118,6 @@ static int pack_map_meta(struct flb_splunk *ctx, msgpack_pack_str(mp_pck, flb_sds_len(str)); msgpack_pack_str_body(mp_pck, str, flb_sds_len(str)); sourcetype_key_set = FLB_TRUE; - c++; } flb_sds_destroy(str); } @@ -137,7 +133,6 @@ static int pack_map_meta(struct flb_splunk *ctx, msgpack_pack_str(mp_pck, flb_sds_len(ctx->event_sourcetype)); msgpack_pack_str_body(mp_pck, ctx->event_sourcetype, flb_sds_len(ctx->event_sourcetype)); - c++; } /* event index (key lookup) */ @@ -155,7 +150,6 @@ static int pack_map_meta(struct flb_splunk *ctx, msgpack_pack_str(mp_pck, flb_sds_len(str)); msgpack_pack_str_body(mp_pck, str, flb_sds_len(str)); index_key_set = FLB_TRUE; - c++; } flb_sds_destroy(str); } @@ -171,7 +165,6 @@ static int pack_map_meta(struct flb_splunk *ctx, msgpack_pack_str(mp_pck, flb_sds_len(ctx->event_index)); msgpack_pack_str_body(mp_pck, ctx->event_index, flb_sds_len(ctx->event_index)); - c++; } /* event 'fields' */ @@ -203,7 +196,6 @@ static int pack_map_meta(struct flb_splunk *ctx, flb_ra_key_value_destroy(rval); } flb_mp_map_header_end(&mh_fields); - c++; } return 0; From 12ef1271f16b021dcf3152aefbaeb2c326791767 Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Thu, 20 Jul 2023 23:18:42 -0600 Subject: [PATCH 130/315] in_mqtt: remove unused variable Signed-off-by: Eduardo Silva --- plugins/in_mqtt/mqtt_prot.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/plugins/in_mqtt/mqtt_prot.c b/plugins/in_mqtt/mqtt_prot.c index bc65bd0a4ff..a072cbfe588 100644 --- a/plugins/in_mqtt/mqtt_prot.c +++ b/plugins/in_mqtt/mqtt_prot.c @@ -338,7 +338,6 @@ static int mqtt_handle_ping(struct mqtt_conn *conn) int mqtt_prot_parser(struct mqtt_conn *conn) { int ret; - int bytes = 0; int length = 0; int pos = conn->buf_pos; int mult; @@ -370,7 +369,7 @@ int mqtt_prot_parser(struct mqtt_conn *conn) /* Get the remaining length */ mult = 1; length = 0; - bytes = 0; + do { if (conn->buf_pos + 1 > conn->buf_len) { conn->buf_pos = pos; @@ -379,7 +378,6 @@ int mqtt_prot_parser(struct mqtt_conn *conn) return MQTT_MORE; } - bytes++; length += (BUFC() & 127) * mult; mult *= 128; if (mult > 128*128*128) { From 2a1f2b92edaac86f8aefe562e273712c68732f85 Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Thu, 20 Jul 2023 23:20:12 -0600 Subject: [PATCH 131/315] in_event_type: fix cfl function prototype Signed-off-by: Eduardo Silva --- plugins/in_event_type/event_type.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/in_event_type/event_type.c b/plugins/in_event_type/event_type.c index aa050664b53..bfad258c21e 100644 --- a/plugins/in_event_type/event_type.c +++ b/plugins/in_event_type/event_type.c @@ -313,7 +313,7 @@ static int send_traces(struct flb_input_instance *ins) ctr_span_event_set_attribute_string(event, "syscall 3", "write()"); /* add a key/value pair list */ - kv = cfl_kvlist_create(1); + kv = cfl_kvlist_create(); cfl_kvlist_insert_string(kv, "language", "c"); ctr_span_set_attribute_kvlist(span_root, "my-list", kv); From dd02955102eaa8e6013349c6f9d602e5d373f885 Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Thu, 20 Jul 2023 23:21:30 -0600 Subject: [PATCH 132/315] in_splunk: initialize variable Signed-off-by: Eduardo Silva --- plugins/in_splunk/splunk_prot.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/in_splunk/splunk_prot.c b/plugins/in_splunk/splunk_prot.c index f6636706359..5b0606083da 100644 --- a/plugins/in_splunk/splunk_prot.c +++ b/plugins/in_splunk/splunk_prot.c @@ -446,7 +446,7 @@ static int validate_auth_header(struct flb_splunk *ctx, struct mk_http_request * static int handle_hec_payload(struct flb_splunk *ctx, int content_type, flb_sds_t tag, char *buf, size_t size) { - int ret; + int ret = -1; if (content_type == HTTP_CONTENT_JSON) { ret = parse_hec_payload_json(ctx, tag, buf, size); From 70b442ca5c030cf335b1a4a758cd2be0b246c895 Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Thu, 20 Jul 2023 23:22:19 -0600 Subject: [PATCH 133/315] in_elasticsearch: remove unused variable Signed-off-by: Eduardo Silva --- plugins/in_elasticsearch/in_elasticsearch_bulk_prot.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/plugins/in_elasticsearch/in_elasticsearch_bulk_prot.c b/plugins/in_elasticsearch/in_elasticsearch_bulk_prot.c index 7ef06146195..c7acfd67145 100644 --- a/plugins/in_elasticsearch/in_elasticsearch_bulk_prot.c +++ b/plugins/in_elasticsearch/in_elasticsearch_bulk_prot.c @@ -359,7 +359,6 @@ static int process_ndpack(struct flb_in_elasticsearch *ctx, flb_sds_t tag, char msgpack_object *obj; flb_sds_t tag_from_record = NULL; int idx = 0; - int cursor = 0; flb_sds_t write_op; size_t op_str_size = 0; int op_ret = FLB_FALSE; @@ -544,7 +543,6 @@ static int process_ndpack(struct flb_in_elasticsearch *ctx, flb_sds_t tag, char proceed: idx++; - cursor++; } else { flb_plg_error(ctx->ins, "skip record from invalid type: %i", From accfe9caede2c50a51a8ac6622ae02be944d371a Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Thu, 20 Jul 2023 23:23:52 -0600 Subject: [PATCH 134/315] in_head: remove unused variables Signed-off-by: Eduardo Silva --- plugins/in_head/in_head.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/plugins/in_head/in_head.c b/plugins/in_head/in_head.c index e0751177e12..2619d1c1864 100644 --- a/plugins/in_head/in_head.c +++ b/plugins/in_head/in_head.c @@ -109,7 +109,6 @@ static int single_value_per_record(struct flb_input_instance *i_ins, struct flb_in_head_config *ctx) { int ret = -1; - int num_map = 1; ctx->buf[0] = '\0'; /* clear buf */ ctx->buf_len = 0; @@ -124,10 +123,6 @@ static int single_value_per_record(struct flb_input_instance *i_ins, flb_plg_trace(ctx->ins, "%s read_len=%zd buf_size=%zu", __FUNCTION__, ctx->buf_len, ctx->buf_size); - if (ctx->add_path == FLB_TRUE) { - num_map++; - } - ret = flb_log_event_encoder_begin_record(&ctx->log_encoder); if (ret == FLB_EVENT_ENCODER_SUCCESS) { @@ -183,7 +178,6 @@ static int split_lines_per_record(struct flb_input_instance *i_ins, int ret; size_t str_len; size_t key_len; - int num_map = ctx->lines; char *ret_buf; char key_str[KEY_LEN_MAX] = {0}; @@ -193,10 +187,6 @@ static int split_lines_per_record(struct flb_input_instance *i_ins, return -1; } - if (ctx->add_path == FLB_TRUE) { - num_map++; - } - ret = flb_log_event_encoder_begin_record(&ctx->log_encoder); if (ret == FLB_EVENT_ENCODER_SUCCESS) { From 707e7c73ab861259eaecaa4ece7f5c0328de503f Mon Sep 17 00:00:00 2001 From: Phillip Whelan Date: Fri, 21 Jul 2023 16:33:56 -0400 Subject: [PATCH 135/315] chunk_traces: update the help for '--enable-chunk-trace'. Signed-off-by: Phillip Whelan --- src/fluent-bit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fluent-bit.c b/src/fluent-bit.c index 12fc8d09de9..c44ccd1bdd7 100644 --- a/src/fluent-bit.c +++ b/src/fluent-bit.c @@ -148,7 +148,7 @@ static void flb_help(int rc, struct flb_config *config) print_opt("-vv", "trace mode (available)"); #endif #ifdef FLB_HAVE_CHUNK_TRACE - print_opt("-Z, --enable-chunk-trace", "enable chunk tracing. activating it requires using the HTTP Server API."); + print_opt("-Z, --enable-chunk-trace", "enable chunk tracing, it can be activated either through the http api or the command line"); print_opt("--trace-input", "input to start tracing on startup."); print_opt("--trace-output", "output to use for tracing on startup."); print_opt("--trace-output-property", "set a property for output tracing on startup."); From 585e89ad69ed118edeb9214bdf0cc9a30cc1e1c8 Mon Sep 17 00:00:00 2001 From: Leonardo Alminana Date: Thu, 20 Jul 2023 13:59:13 +0200 Subject: [PATCH 136/315] connection: a shutdown guard flag was added Signed-off-by: Leonardo Alminana --- include/fluent-bit/flb_connection.h | 8 ++++++++ src/flb_connection.c | 2 ++ 2 files changed, 10 insertions(+) diff --git a/include/fluent-bit/flb_connection.h b/include/fluent-bit/flb_connection.h index b2d1e48c6a4..46fd80c4bad 100644 --- a/include/fluent-bit/flb_connection.h +++ b/include/fluent-bit/flb_connection.h @@ -95,6 +95,14 @@ struct flb_connection { */ int busy_flag; + /* This flag is used to determine if the connection was shut down to ensure we + * don't do it twice when a timeout is detected. + * + * This is required in order to overcome a limitation in the async read / write + * functions that will be addressed as soon as possible. + */ + int shutdown_flag; + /* * Recycle: if the connection is keepalive, this flag is always on, but if * the caller wants to drop the connection once is released, it can set diff --git a/src/flb_connection.c b/src/flb_connection.c index 051a6c9a305..a3ed402651b 100644 --- a/src/flb_connection.c +++ b/src/flb_connection.c @@ -24,6 +24,8 @@ int flb_connection_setup(struct flb_connection *connection, connection->tls_session = NULL; connection->ts_created = time(NULL); connection->ts_assigned = time(NULL); + connection->busy_flag = FLB_FALSE; + connection->shutdown_flag = FLB_FALSE; connection->net = &connection->stream->net; From 6e8092a4a63f106317158f3190bb88640dc91102 Mon Sep 17 00:00:00 2001 From: Leonardo Alminana Date: Thu, 20 Jul 2023 14:04:51 +0200 Subject: [PATCH 137/315] upstream: decoupled socket shutdown from upstream connection release Additionally, a flag to ensure that a socket is only shut down once has been added and the timeout based event injection and connection destruction mechanism was refactored to ensure that connections aren't prematurely destroyed and coroutines are properly resumed even when the priority event loop hits its iteration limit before the injected event is processed. Signed-off-by: Leonardo Alminana --- src/flb_upstream.c | 72 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 64 insertions(+), 8 deletions(-) diff --git a/src/flb_upstream.c b/src/flb_upstream.c index 4701cc3d68f..142f9680396 100644 --- a/src/flb_upstream.c +++ b/src/flb_upstream.c @@ -437,6 +437,23 @@ struct flb_upstream *flb_upstream_create_url(struct flb_config *config, return u; } +/* This function shuts the connection down in order to cause + * any client code trying to read or write from it to fail. + */ +static void shutdown_connection(struct flb_connection *u_conn) +{ + struct flb_upstream *u; + + u = u_conn->upstream; + + if (u_conn->fd > 0 && + !u_conn->shutdown_flag) { + shutdown(u_conn->fd, SHUT_RDWR); + + u_conn->shutdown_flag = FLB_TRUE; + } +} + /* * This function moves the 'upstream connection' into the queue to be * destroyed. Note that the caller is responsible to validate and check @@ -462,13 +479,18 @@ static int prepare_destroy_conn(struct flb_connection *u_conn) #ifdef FLB_HAVE_TLS if (u_conn->tls_session != NULL) { flb_tls_session_destroy(u_conn->tls_session); + + u_conn->tls_session = NULL; } #endif - shutdown(u_conn->fd, SHUT_RDWR); + shutdown_connection(u_conn); + flb_socket_close(u_conn->fd); + u_conn->fd = -1; u_conn->event.fd = -1; } + /* remove connection from the queue */ mk_list_del(&u_conn->_head); @@ -843,7 +865,6 @@ int flb_upstream_conn_timeouts(struct mk_list *list) { time_t now; int drop; - int inject; const char *reason; struct mk_list *head; struct mk_list *u_head; @@ -904,18 +925,53 @@ int flb_upstream_conn_timeouts(struct mk_list *list) } } - inject = FLB_FALSE; - if (u_conn->event.status != MK_EVENT_NONE) { - inject = FLB_TRUE; - } u_conn->net_error = ETIMEDOUT; - prepare_destroy_conn(u_conn); - if (inject == FLB_TRUE) { + + /* We need to shut the connection down + * in order to cause some functions that are not + * aware of the connection error signaling + * mechanism to fail and abort. + * + * These functions do not check the net_error field + * in the connection instance upon being awakened + * so we need to ensure that any read/write + * operations on the socket generate an error. + * + * net_io_write_async + * net_io_read_async + * flb_tls_net_write_async + * flb_tls_net_read_async + * + * This operation could be selectively performed for + * connections that have already been established + * with no side effects because the connection + * establishment code honors `net_error` but + * taking in account that the previous version of + * the code did it unconditionally with no noticeable + * side effects leaving it that way is the safest + * choice at the moment. + */ + + if (MK_EVENT_IS_REGISTERED((&u_conn->event))) { + shutdown_connection(u_conn); + mk_event_inject(u_conn->evl, &u_conn->event, u_conn->event.mask, FLB_TRUE); } + else { + /* I can't think of a valid reason for this code path + * to be taken but considering that it was previously + * possible for it to happen (maybe wesley can shed + * some light on it if he remembers) I'll leave this + * for the moment. + * In any case, it's proven not to interfere with the + * coroutine awakening issue this change addresses. + */ + + prepare_destroy_conn(u_conn); + } flb_upstream_decrement_busy_connections_count(u); } From 782d9ab1ab53abc9bd03343ff31b5e7d39668add Mon Sep 17 00:00:00 2001 From: Phillip Whelan Date: Fri, 7 Jul 2023 10:19:14 -0400 Subject: [PATCH 138/315] in_calyptia_fleet: add fleet_name parameter. Allow setting up fleets via name only. The plugin will then retrieve the fleet_id via the calyptia cloud API. Signed-off-by: Phillip Whelan --- plugins/custom_calyptia/calyptia.c | 18 +- plugins/in_calyptia_fleet/in_calyptia_fleet.c | 340 +++++++++++++++++- 2 files changed, 346 insertions(+), 12 deletions(-) diff --git a/plugins/custom_calyptia/calyptia.c b/plugins/custom_calyptia/calyptia.c index eb79ae7dfd8..43d167ed5ce 100644 --- a/plugins/custom_calyptia/calyptia.c +++ b/plugins/custom_calyptia/calyptia.c @@ -55,6 +55,7 @@ struct calyptia { /* Fleet configuration */ flb_sds_t fleet_id; /* fleet-id */ + flb_sds_t fleet_name; flb_sds_t fleet_config_dir; /* fleet configuration directory */ int fleet_interval_sec; int fleet_interval_nsec; @@ -326,8 +327,15 @@ static int cb_calyptia_init(struct flb_custom_instance *ins, flb_output_set_property(ctx->o, "tls.verify", "false"); } - if (ctx->fleet_id) { - flb_output_set_property(ctx->o, "fleet_id", ctx->fleet_id); + if (ctx->fleet_id || ctx->fleet_name) { + if (ctx->fleet_name) { + // TODO: set this once the fleet_id has been retrieved... + // flb_output_set_property(ctx->o, "fleet_id", ctx->fleet_id); + flb_input_set_property(ctx->fleet, "fleet_name", ctx->fleet_name); + } else { + flb_output_set_property(ctx->o, "fleet_id", ctx->fleet_id); + flb_input_set_property(ctx->fleet, "fleet_id", ctx->fleet_id); + } ctx->fleet = flb_input_new(config, "calyptia_fleet", NULL, FLB_FALSE); if (!ctx->fleet) { @@ -351,7 +359,6 @@ static int cb_calyptia_init(struct flb_custom_instance *ins, if (ctx->fleet_config_dir) { flb_input_set_property(ctx->fleet, "config_dir", ctx->fleet_config_dir); } - flb_input_set_property(ctx->fleet, "fleet_id", ctx->fleet_id); } @@ -443,6 +450,11 @@ static struct flb_config_map config_map[] = { 0, FLB_TRUE, offsetof(struct calyptia, fleet_interval_nsec), "Set the collector interval (nanoseconds)" }, + { + FLB_CONFIG_MAP_STR, "fleet_name", NULL, + 0, FLB_TRUE, offsetof(struct calyptia, fleet_name), + "Fleet name to be used when registering agent in a fleet" + }, #ifdef FLB_HAVE_CHUNK_TRACE { diff --git a/plugins/in_calyptia_fleet/in_calyptia_fleet.c b/plugins/in_calyptia_fleet/in_calyptia_fleet.c index ffba76bbb7a..358d6ba9394 100644 --- a/plugins/in_calyptia_fleet/in_calyptia_fleet.c +++ b/plugins/in_calyptia_fleet/in_calyptia_fleet.c @@ -35,6 +35,7 @@ #include #include #include +#include #define CALYPTIA_H_PROJECT "X-Project-Token" @@ -62,6 +63,7 @@ struct flb_in_calyptia_fleet_config { flb_sds_t api_key; flb_sds_t fleet_id; + flb_sds_t fleet_name; flb_sds_t config_dir; flb_sds_t cloud_host; flb_sds_t cloud_port; @@ -166,7 +168,11 @@ static flb_sds_t fleet_config_filename(struct flb_in_calyptia_fleet_config *ctx, flb_sds_t cfgname; cfgname = flb_sds_create_size(4096); - flb_sds_printf(&cfgname, "%s" PATH_SEPARATOR "%s" PATH_SEPARATOR "%s.ini", ctx->config_dir, ctx->fleet_id, fname); + if (ctx->fleet_name != NULL) { + flb_sds_printf(&cfgname, "%s" PATH_SEPARATOR "%s" PATH_SEPARATOR "%s.ini", ctx->config_dir, ctx->fleet_name, fname); + } else { + flb_sds_printf(&cfgname, "%s" PATH_SEPARATOR "%s" PATH_SEPARATOR "%s.ini", ctx->config_dir, ctx->fleet_id, fname); + } return cfgname; } @@ -362,9 +368,220 @@ static char *tls_setting_string(int use_tls) return "Off"; } +static flb_sds_t parse_api_key_json(struct flb_in_calyptia_fleet_config *ctx, + char *payload, size_t size) +{ + int ret; + int out_size; + char *pack; + struct flb_pack_state pack_state; + size_t off = 0; + msgpack_unpacked result; + msgpack_object_kv *cur; + msgpack_object_str *key; + int i = 0; + + /* Initialize packer */ + flb_pack_state_init(&pack_state); + + /* Pack JSON as msgpack */ + ret = flb_pack_json_state(payload, size, + &pack, &out_size, &pack_state); + flb_pack_state_reset(&pack_state); + + /* Handle exceptions */ + if (ret == FLB_ERR_JSON_PART) { + flb_plg_warn(ctx->ins, "JSON data is incomplete, skipping"); + return NULL; + } + else if (ret == FLB_ERR_JSON_INVAL) { + flb_plg_warn(ctx->ins, "invalid JSON message, skipping"); + return NULL; + } + else if (ret == -1) { + return NULL; + } + + msgpack_unpacked_init(&result); + while (msgpack_unpack_next(&result, pack, out_size, &off) == MSGPACK_UNPACK_SUCCESS) { + if (result.data.type == MSGPACK_OBJECT_MAP) { + for (i = 0; i < result.data.via.map.size; i++) { + cur = &result.data.via.map.ptr[i]; + key = &cur->key.via.str; + + if (strncmp(key->ptr, "ProjectID", key->size) == 0) { + if (cur->val.type != MSGPACK_OBJECT_STR) { + flb_plg_error(ctx->ins, "unable to find fleet by name"); + msgpack_unpacked_destroy(&result); + return NULL; + } + msgpack_unpacked_destroy(&result); + flb_free(pack); + return flb_sds_create(cur->val.via.str.ptr); + } + } + } + } + + msgpack_unpacked_destroy(&result); + flb_free(pack); + + return NULL; +} + +static ssize_t parse_fleet_search_json(struct flb_in_calyptia_fleet_config *ctx, + char *payload, size_t size) +{ + int ret; + int out_size; + char *pack; + struct flb_pack_state pack_state; + size_t off = 0; + msgpack_unpacked result; + msgpack_object_array *results; + msgpack_object_kv *cur; + msgpack_object_str *key; + int i = 0; + + /* Initialize packer */ + flb_pack_state_init(&pack_state); + + /* Pack JSON as msgpack */ + ret = flb_pack_json_state(payload, size, + &pack, &out_size, &pack_state); + flb_pack_state_reset(&pack_state); + + /* Handle exceptions */ + if (ret == FLB_ERR_JSON_PART) { + flb_plg_warn(ctx->ins, "JSON data is incomplete, skipping"); + return -1; + } + else if (ret == FLB_ERR_JSON_INVAL) { + flb_plg_warn(ctx->ins, "invalid JSON message, skipping"); + return -1; + } + else if (ret == -1) { + return -1; + } + + msgpack_unpacked_init(&result); + while (msgpack_unpack_next(&result, pack, out_size, &off) == MSGPACK_UNPACK_SUCCESS) { + if (result.data.type == MSGPACK_OBJECT_ARRAY) { + results = &result.data.via.array; + if (results->ptr[0].type == MSGPACK_OBJECT_MAP) { + for (i = 0; i < results->ptr[0].via.map.size; i++) { + cur = &results->ptr[0].via.map.ptr[i]; + key = &cur->key.via.str; + + if (strncasecmp(key->ptr, "id", key->size) == 0) { + if (cur->val.type != MSGPACK_OBJECT_STR) { + flb_plg_error(ctx->ins, "unable to find fleet by name"); + msgpack_unpacked_destroy(&result); + return -1; + } + ctx->fleet_id = flb_sds_create_len(cur->val.via.str.ptr, + cur->val.via.str.size); + break; + } + break; + } + break; + } + } + } + + msgpack_unpacked_destroy(&result); + flb_free(pack); + + if (ctx->fleet_id == NULL) { + return -1; + } + return 0; +} + +static int get_calyptia_fleet_id_by_name(struct flb_in_calyptia_fleet_config *ctx, + struct flb_connection *u_conn, + struct flb_config *config) +{ + struct flb_http_client *client; + flb_sds_t url; + flb_sds_t project_id; + unsigned char token[512] = {0}; + unsigned char encoded[256]; + size_t elen; + size_t tlen; + char *api_token_sep; + size_t b_sent; + int ret; + + api_token_sep = strchr(ctx->api_key, '.'); + if (api_token_sep == NULL) { + return -1; + } + + elen = api_token_sep-ctx->api_key; + elen = elen + (4 - (elen % 4)); + if (elen > sizeof(encoded)) { + flb_plg_error(ctx->ins, "API Token is too large"); + return -1; + } + + memset(encoded, '=', sizeof(encoded)); + memcpy(encoded, ctx->api_key, api_token_sep-ctx->api_key); + + ret = flb_base64_decode(token, sizeof(token)-1, &tlen, + encoded, elen); + if (ret != 0) { + return ret; + } + + project_id = parse_api_key_json(ctx, (char *)token, tlen); + if (project_id == NULL) { + return -1; + } + + url = flb_sds_create_size(4096); + flb_sds_printf(&url, "/v1/search?project_id=%s&resource=fleet&term=%s", + project_id, ctx->fleet_name); + + client = flb_http_client(u_conn, FLB_HTTP_GET, url, NULL, 0, + ctx->ins->host.name, ctx->ins->host.port, NULL, 0); + if (!client) { + flb_plg_error(ctx->ins, "unable to create http client"); + return -1; + } + + flb_http_buffer_size(client, 8192); + + flb_http_add_header(client, + CALYPTIA_H_PROJECT, sizeof(CALYPTIA_H_PROJECT) - 1, + ctx->api_key, flb_sds_len(ctx->api_key)); + + ret = flb_http_do(client, &b_sent); + if (ret != 0) { + flb_plg_error(ctx->ins, "http do error"); + return -1; + } + + if (client->resp.status != 200) { + flb_plg_error(ctx->ins, "http status code error: %d", client->resp.status); + return -1; + } + + if (client->resp.payload_size <= 0) { + flb_plg_error(ctx->ins, "empty response"); + return -1; + } + + parse_fleet_search_json(ctx, client->resp.payload, client->resp.payload_size); + + return 0; +} + /* cb_collect callback */ static int in_calyptia_fleet_collect(struct flb_input_instance *ins, - struct flb_config *config, void *in_context) + struct flb_config *config, + void *in_context) { struct flb_in_calyptia_fleet_config *ctx = in_context; struct flb_connection *u_conn; @@ -390,6 +607,15 @@ static int in_calyptia_fleet_collect(struct flb_input_instance *ins, goto conn_error; } + if (ctx->fleet_id == NULL) { + get_calyptia_fleet_id_by_name(ctx, u_conn, config); + } + + if (ctx->fleet_url == NULL) { + ctx->fleet_url = flb_sds_create_size(4096); + flb_sds_printf(&ctx->fleet_url, "/v1/fleets/%s/config?format=ini", ctx->fleet_id); + } + client = flb_http_client(u_conn, FLB_HTTP_GET, ctx->fleet_url, NULL, 0, ctx->ins->host.name, ctx->ins->host.port, NULL, 0); @@ -516,8 +742,11 @@ static void create_fleet_directory(struct flb_in_calyptia_fleet_config *ctx) } myfleetdir = flb_sds_create_size(256); - flb_sds_printf(&myfleetdir, "%s" PATH_SEPARATOR "%s", ctx->config_dir, ctx->fleet_id); - + if (ctx->fleet_name != NULL) { + flb_sds_printf(&myfleetdir, "%s" PATH_SEPARATOR "%s", ctx->config_dir, ctx->fleet_name); + } else { + flb_sds_printf(&myfleetdir, "%s" PATH_SEPARATOR "%s", ctx->config_dir, ctx->fleet_id); + } if (access(myfleetdir, F_OK)) { mkdir(myfleetdir, 0700); } @@ -541,6 +770,97 @@ static void load_fleet_config(struct flb_in_calyptia_fleet_config *ctx) } } +static ssize_t parse_fleets_json(struct flb_in_calyptia_fleet_config *ctx, uint64_t ts, + char *payload, size_t size) +{ + int ret; + int out_size; + char *pack; + struct flb_pack_state pack_state; + size_t off = 0; + msgpack_unpacked result; + msgpack_object_kv *cur; + msgpack_object_str *key; + msgpack_object_map *fleet = NULL; + int i = 0; + + /* Initialize packer */ + flb_pack_state_init(&pack_state); + + /* Pack JSON as msgpack */ + ret = flb_pack_json_state(payload, size, + &pack, &out_size, &pack_state); + flb_pack_state_reset(&pack_state); + + /* Handle exceptions */ + if (ret == FLB_ERR_JSON_PART) { + flb_plg_warn(ctx->ins, "JSON data is incomplete, skipping"); + return -1; + } + else if (ret == FLB_ERR_JSON_INVAL) { + flb_plg_warn(ctx->ins, "invalid JSON message, skipping"); + return -1; + } + else if (ret == -1) { + return -1; + } + + msgpack_unpacked_init(&result); + while (msgpack_unpack_next(&result, payload, size, &off) == MSGPACK_UNPACK_SUCCESS) { + if (result.data.type == MSGPACK_OBJECT_MAP) { + for (i = 0; i < result.data.via.map.size; i++) { + cur = &result.data.via.map.ptr[i]; + key = &cur->key.via.str; + + if (strncmp(key->ptr, "items", key->size) == 0) { + if (cur->val.type != MSGPACK_OBJECT_ARRAY || cur->val.via.array.size != 1) { + flb_plg_error(ctx->ins, "unable to find fleet by name"); + msgpack_unpacked_destroy(&result); + return -1; + } + } + + if (cur->val.via.array.ptr[0].type != MSGPACK_OBJECT_MAP) { + flb_plg_error(ctx->ins, "invalid fleet response"); + msgpack_unpacked_destroy(&result); + return -1; + } + + fleet = &cur->val.via.array.ptr[0].via.map; + break; + } + break; + } + } + + if (fleet == NULL) { + flb_plg_error(ctx->ins, "unable to find fleet in API response"); + msgpack_unpacked_destroy(&result); + return -1; + } + + for (i = 0; i < fleet->size; i++) { + cur = &fleet->ptr[i]; + key = &cur->key.via.str; + + if (strncasecmp(key->ptr, "id", key->size) == 0) { + if (ctx->fleet_id != NULL) { + flb_sds_destroy(ctx->fleet_id); + } + ctx->fleet_id = flb_sds_create_len(cur->val.via.str.ptr, + cur->val.via.str.size); + } + } + + msgpack_unpacked_destroy(&result); + flb_free(pack); + + if (ctx->fleet_id == NULL) { + return -1; + } + return 0; +} + static int in_calyptia_fleet_init(struct flb_input_instance *in, struct flb_config *config, void *data) { @@ -565,7 +885,7 @@ static int in_calyptia_fleet_init(struct flb_input_instance *in, flb_errno(); return -1; } - ctx->ins = in; + ctx->ins = in; /* Load the config map */ @@ -614,12 +934,9 @@ static int in_calyptia_fleet_init(struct flb_input_instance *in, ctx->interval_nsec = atoi(DEFAULT_INTERVAL_NSEC); } - ctx->fleet_url = flb_sds_create_size(4096); - flb_sds_printf(&ctx->fleet_url, "/v1/fleets/%s/config?format=ini", ctx->fleet_id); - /* Set the context */ flb_input_set_context(in, ctx); - + /* Set our collector based on time */ ret = flb_input_set_collector_time(in, in_calyptia_fleet_collect, @@ -679,6 +996,11 @@ static struct flb_config_map config_map[] = { 0, FLB_TRUE, offsetof(struct flb_in_calyptia_fleet_config, fleet_id), "Calyptia Fleet ID." }, + { + FLB_CONFIG_MAP_STR, "fleet_name", NULL, + 0, FLB_TRUE, offsetof(struct flb_in_calyptia_fleet_config, fleet_name), + "Calyptia Fleet Name (used to lookup the fleet ID via the cloud API)." + }, { FLB_CONFIG_MAP_INT, "event_fd", "-1", 0, FLB_TRUE, offsetof(struct flb_in_calyptia_fleet_config, event_fd), From a0e871308e0ca6d5f299023a6fb6594fcab08231 Mon Sep 17 00:00:00 2001 From: Phillip Whelan Date: Fri, 7 Jul 2023 16:51:25 -0400 Subject: [PATCH 139/315] custom_calyptia: set calyptia_name after instancing the input plugin. Signed-off-by: Phillip Whelan --- plugins/custom_calyptia/calyptia.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/plugins/custom_calyptia/calyptia.c b/plugins/custom_calyptia/calyptia.c index 43d167ed5ce..ecc1e4acad5 100644 --- a/plugins/custom_calyptia/calyptia.c +++ b/plugins/custom_calyptia/calyptia.c @@ -328,6 +328,12 @@ static int cb_calyptia_init(struct flb_custom_instance *ins, } if (ctx->fleet_id || ctx->fleet_name) { + ctx->fleet = flb_input_new(config, "calyptia_fleet", NULL, FLB_FALSE); + if (!ctx->fleet) { + flb_plg_error(ctx->ins, "could not load Calyptia Fleet plugin"); + return -1; + } + if (ctx->fleet_name) { // TODO: set this once the fleet_id has been retrieved... // flb_output_set_property(ctx->o, "fleet_id", ctx->fleet_id); @@ -337,12 +343,6 @@ static int cb_calyptia_init(struct flb_custom_instance *ins, flb_input_set_property(ctx->fleet, "fleet_id", ctx->fleet_id); } - ctx->fleet = flb_input_new(config, "calyptia_fleet", NULL, FLB_FALSE); - if (!ctx->fleet) { - flb_plg_error(ctx->ins, "could not load Calyptia Fleet plugin"); - return -1; - } - flb_input_set_property(ctx->fleet, "api_key", ctx->api_key); flb_input_set_property(ctx->fleet, "host", ctx->cloud_host); flb_input_set_property(ctx->fleet, "port", ctx->cloud_port); From e801acb167f28583df5ca102264922fda79bf305 Mon Sep 17 00:00:00 2001 From: Phillip Whelan Date: Fri, 7 Jul 2023 16:52:05 -0400 Subject: [PATCH 140/315] in_calyptia_fleet: check for search errors. Signed-off-by: Phillip Whelan --- plugins/in_calyptia_fleet/in_calyptia_fleet.c | 106 ++---------------- 1 file changed, 12 insertions(+), 94 deletions(-) diff --git a/plugins/in_calyptia_fleet/in_calyptia_fleet.c b/plugins/in_calyptia_fleet/in_calyptia_fleet.c index 358d6ba9394..d1e229de890 100644 --- a/plugins/in_calyptia_fleet/in_calyptia_fleet.c +++ b/plugins/in_calyptia_fleet/in_calyptia_fleet.c @@ -564,7 +564,7 @@ static int get_calyptia_fleet_id_by_name(struct flb_in_calyptia_fleet_config *ct } if (client->resp.status != 200) { - flb_plg_error(ctx->ins, "http status code error: %d", client->resp.status); + flb_plg_error(ctx->ins, "search http status code error: %d", client->resp.status); return -1; } @@ -573,8 +573,14 @@ static int get_calyptia_fleet_id_by_name(struct flb_in_calyptia_fleet_config *ct return -1; } - parse_fleet_search_json(ctx, client->resp.payload, client->resp.payload_size); + if (parse_fleet_search_json(ctx, client->resp.payload, client->resp.payload_size) == -1) { + flb_plg_error(ctx->ins, "unable to find fleet: %s", ctx->fleet_name); + return -1; + } + if (ctx->fleet_id == NULL) { + return -1; + } return 0; } @@ -608,7 +614,10 @@ static int in_calyptia_fleet_collect(struct flb_input_instance *ins, } if (ctx->fleet_id == NULL) { - get_calyptia_fleet_id_by_name(ctx, u_conn, config); + if (get_calyptia_fleet_id_by_name(ctx, u_conn, config) == -1) { + flb_plg_error(ctx->ins, "unable to find fleet: %s", ctx->fleet_name); + goto conn_error; + } } if (ctx->fleet_url == NULL) { @@ -770,97 +779,6 @@ static void load_fleet_config(struct flb_in_calyptia_fleet_config *ctx) } } -static ssize_t parse_fleets_json(struct flb_in_calyptia_fleet_config *ctx, uint64_t ts, - char *payload, size_t size) -{ - int ret; - int out_size; - char *pack; - struct flb_pack_state pack_state; - size_t off = 0; - msgpack_unpacked result; - msgpack_object_kv *cur; - msgpack_object_str *key; - msgpack_object_map *fleet = NULL; - int i = 0; - - /* Initialize packer */ - flb_pack_state_init(&pack_state); - - /* Pack JSON as msgpack */ - ret = flb_pack_json_state(payload, size, - &pack, &out_size, &pack_state); - flb_pack_state_reset(&pack_state); - - /* Handle exceptions */ - if (ret == FLB_ERR_JSON_PART) { - flb_plg_warn(ctx->ins, "JSON data is incomplete, skipping"); - return -1; - } - else if (ret == FLB_ERR_JSON_INVAL) { - flb_plg_warn(ctx->ins, "invalid JSON message, skipping"); - return -1; - } - else if (ret == -1) { - return -1; - } - - msgpack_unpacked_init(&result); - while (msgpack_unpack_next(&result, payload, size, &off) == MSGPACK_UNPACK_SUCCESS) { - if (result.data.type == MSGPACK_OBJECT_MAP) { - for (i = 0; i < result.data.via.map.size; i++) { - cur = &result.data.via.map.ptr[i]; - key = &cur->key.via.str; - - if (strncmp(key->ptr, "items", key->size) == 0) { - if (cur->val.type != MSGPACK_OBJECT_ARRAY || cur->val.via.array.size != 1) { - flb_plg_error(ctx->ins, "unable to find fleet by name"); - msgpack_unpacked_destroy(&result); - return -1; - } - } - - if (cur->val.via.array.ptr[0].type != MSGPACK_OBJECT_MAP) { - flb_plg_error(ctx->ins, "invalid fleet response"); - msgpack_unpacked_destroy(&result); - return -1; - } - - fleet = &cur->val.via.array.ptr[0].via.map; - break; - } - break; - } - } - - if (fleet == NULL) { - flb_plg_error(ctx->ins, "unable to find fleet in API response"); - msgpack_unpacked_destroy(&result); - return -1; - } - - for (i = 0; i < fleet->size; i++) { - cur = &fleet->ptr[i]; - key = &cur->key.via.str; - - if (strncasecmp(key->ptr, "id", key->size) == 0) { - if (ctx->fleet_id != NULL) { - flb_sds_destroy(ctx->fleet_id); - } - ctx->fleet_id = flb_sds_create_len(cur->val.via.str.ptr, - cur->val.via.str.size); - } - } - - msgpack_unpacked_destroy(&result); - flb_free(pack); - - if (ctx->fleet_id == NULL) { - return -1; - } - return 0; -} - static int in_calyptia_fleet_init(struct flb_input_instance *in, struct flb_config *config, void *data) { From f187b04063e4877549d37bb6e3aaff077d40cb81 Mon Sep 17 00:00:00 2001 From: Phillip Whelan Date: Thu, 20 Jul 2023 17:34:49 -0400 Subject: [PATCH 141/315] custom_calyptia: do not register as agent before loading configuration. Avoid a possible colision with other agent instances by waiting until loading the fleet configuration to register the agent and any metrics. Signed-off-by: Phillip Whelan --- plugins/custom_calyptia/calyptia.c | 130 ++++++++++++++++------------- 1 file changed, 73 insertions(+), 57 deletions(-) diff --git a/plugins/custom_calyptia/calyptia.c b/plugins/custom_calyptia/calyptia.c index ecc1e4acad5..b1f8558cf28 100644 --- a/plugins/custom_calyptia/calyptia.c +++ b/plugins/custom_calyptia/calyptia.c @@ -221,60 +221,29 @@ flb_sds_t custom_calyptia_pipeline_config_get(struct flb_config *ctx) return buf; } -static int cb_calyptia_init(struct flb_custom_instance *ins, - struct flb_config *config, - void *data) +static struct flb_output_instance *setup_cloud_output(struct flb_config *config, struct calyptia *ctx) { int ret; - struct calyptia *ctx; + struct flb_output_instance *cloud; struct mk_list *head; - struct flb_config_map_val *mv; struct flb_slist_entry *k = NULL; struct flb_slist_entry *v = NULL; - (void) data; flb_sds_t kv; + struct flb_config_map_val *mv; - ctx = flb_calloc(1, sizeof(struct calyptia)); - if (!ctx) { - flb_errno(); - return -1; - } - ctx->ins = ins; - - /* Load the config map */ - ret = flb_custom_config_map_set(ins, (void *) ctx); - if (ret == -1) { - flb_free(ctx); - return -1; - } - - /* map instance and local context */ - flb_custom_set_context(ins, ctx); - - /* input collector */ - ctx->i = flb_input_new(config, "fluentbit_metrics", NULL, FLB_TRUE); - if (!ctx->i) { - flb_plg_error(ctx->ins, "could not load metrics collector"); - return -1; - } - flb_input_set_property(ctx->i, "tag", "_calyptia_cloud"); - flb_input_set_property(ctx->i, "scrape_on_start", "true"); - flb_input_set_property(ctx->i, "scrape_interval", "30"); - - /* output cloud connector */ - ctx->o = flb_output_new(config, "calyptia", ctx, FLB_FALSE); - if (!ctx->o) { + cloud = flb_output_new(config, "calyptia", ctx, FLB_FALSE); + if (!cloud) { flb_plg_error(ctx->ins, "could not load Calyptia Cloud connector"); flb_free(ctx); - return -1; + return NULL; } /* direct connect / routing */ - ret = flb_router_connect_direct(ctx->i, ctx->o); + ret = flb_router_connect_direct(ctx->i, cloud); if (ret != 0) { flb_plg_error(ctx->ins, "could not load Calyptia Cloud connector"); flb_free(ctx); - return -1; + return NULL; } if (ctx->add_labels && mk_list_size(ctx->add_labels) > 0) { @@ -285,46 +254,96 @@ static int cb_calyptia_init(struct flb_custom_instance *ins, kv = flb_sds_create_size(strlen(k->str) + strlen(v->str) + 1); if(!kv) { flb_free(ctx); - return -1; + return NULL; } flb_sds_printf(&kv, "%s %s", k->str, v->str); - flb_output_set_property(ctx->o, "add_label", kv); + flb_output_set_property(cloud, "add_label", kv); flb_sds_destroy(kv); } } - flb_output_set_property(ctx->o, "match", "_calyptia_cloud"); - flb_output_set_property(ctx->o, "api_key", ctx->api_key); + flb_output_set_property(cloud, "match", "_calyptia_cloud"); + flb_output_set_property(cloud, "api_key", ctx->api_key); if (ctx->store_path) { - flb_output_set_property(ctx->o, "store_path", ctx->store_path); + flb_output_set_property(cloud, "store_path", ctx->store_path); } if (ctx->machine_id) { - flb_output_set_property(ctx->o, "machine_id", ctx->machine_id); + flb_output_set_property(cloud, "machine_id", ctx->machine_id); } /* Override network details: development purposes only */ if (ctx->cloud_host) { - flb_output_set_property(ctx->o, "cloud_host", ctx->cloud_host); + flb_output_set_property(cloud, "cloud_host", ctx->cloud_host); } if (ctx->cloud_port) { - flb_output_set_property(ctx->o, "cloud_port", ctx->cloud_port); + flb_output_set_property(cloud, "cloud_port", ctx->cloud_port); } if (ctx->cloud_tls) { - flb_output_set_property(ctx->o, "tls", "true"); + flb_output_set_property(cloud, "tls", "true"); } else { - flb_output_set_property(ctx->o, "tls", "false"); + flb_output_set_property(cloud, "tls", "false"); } if (ctx->cloud_tls_verify) { - flb_output_set_property(ctx->o, "tls.verify", "true"); + flb_output_set_property(cloud, "tls.verify", "true"); } else { - flb_output_set_property(ctx->o, "tls.verify", "false"); + flb_output_set_property(cloud, "tls.verify", "false"); + } + +#ifdef FLB_HAVE_CHUNK_TRACE + flb_output_set_property(cloud, "pipeline_id", ctx->pipeline_id); +#endif /* FLB_HAVE_CHUNK_TRACE */ + + return cloud; +} + +static int cb_calyptia_init(struct flb_custom_instance *ins, + struct flb_config *config, + void *data) +{ + int ret; + struct calyptia *ctx; + (void) data; + + ctx = flb_calloc(1, sizeof(struct calyptia)); + if (!ctx) { + flb_errno(); + return -1; + } + ctx->ins = ins; + + /* Load the config map */ + ret = flb_custom_config_map_set(ins, (void *) ctx); + if (ret == -1) { + flb_free(ctx); + return -1; + } + + /* map instance and local context */ + flb_custom_set_context(ins, ctx); + + /* input collector */ + ctx->i = flb_input_new(config, "fluentbit_metrics", NULL, FLB_TRUE); + if (!ctx->i) { + flb_plg_error(ctx->ins, "could not load metrics collector"); + return -1; + } + flb_input_set_property(ctx->i, "tag", "_calyptia_cloud"); + flb_input_set_property(ctx->i, "scrape_on_start", "true"); + flb_input_set_property(ctx->i, "scrape_interval", "30"); + + /* output cloud connector */ + if (ctx->fleet_id != NULL) { + ctx->o = setup_cloud_output(config, ctx); + if (ctx->o == NULL) { + return -1; + } } if (ctx->fleet_id || ctx->fleet_name) { @@ -361,12 +380,9 @@ static int cb_calyptia_init(struct flb_custom_instance *ins, } } - -#ifdef FLB_HAVE_CHUNK_TRACE - flb_output_set_property(ctx->o, "pipeline_id", ctx->pipeline_id); -#endif /* FLB_HAVE_CHUNK_TRACE */ - - flb_router_connect(ctx->i, ctx->o); + if (ctx->o) { + flb_router_connect(ctx->i, ctx->o); + } flb_plg_info(ins, "custom initialized!"); return 0; } From 16605b78762e163e850ccc5c118006be00241939 Mon Sep 17 00:00:00 2001 From: Phillip Whelan Date: Thu, 20 Jul 2023 17:36:51 -0400 Subject: [PATCH 142/315] in_calyptia_fleet: fix use after free and non-null terminated string. Signed-off-by: Phillip Whelan --- plugins/in_calyptia_fleet/in_calyptia_fleet.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/plugins/in_calyptia_fleet/in_calyptia_fleet.c b/plugins/in_calyptia_fleet/in_calyptia_fleet.c index d1e229de890..37bf49e0b60 100644 --- a/plugins/in_calyptia_fleet/in_calyptia_fleet.c +++ b/plugins/in_calyptia_fleet/in_calyptia_fleet.c @@ -379,6 +379,7 @@ static flb_sds_t parse_api_key_json(struct flb_in_calyptia_fleet_config *ctx, msgpack_unpacked result; msgpack_object_kv *cur; msgpack_object_str *key; + flb_sds_t project_id; int i = 0; /* Initialize packer */ @@ -415,9 +416,11 @@ static flb_sds_t parse_api_key_json(struct flb_in_calyptia_fleet_config *ctx, msgpack_unpacked_destroy(&result); return NULL; } + project_id = flb_sds_create_len(cur->val.via.str.ptr, + cur->val.via.str.size); msgpack_unpacked_destroy(&result); flb_free(pack); - return flb_sds_create(cur->val.via.str.ptr); + return project_id; } } } From fcd1364fe75b8be334044e143de27b086e2084f2 Mon Sep 17 00:00:00 2001 From: Phillip Whelan Date: Thu, 20 Jul 2023 17:38:03 -0400 Subject: [PATCH 143/315] in_calyptia_fleet: maintain fleet_name parameter across reloads. Signed-off-by: Phillip Whelan --- plugins/in_calyptia_fleet/in_calyptia_fleet.c | 59 +++++++++++++------ 1 file changed, 41 insertions(+), 18 deletions(-) diff --git a/plugins/in_calyptia_fleet/in_calyptia_fleet.c b/plugins/in_calyptia_fleet/in_calyptia_fleet.c index 37bf49e0b60..42880b9c043 100644 --- a/plugins/in_calyptia_fleet/in_calyptia_fleet.c +++ b/plugins/in_calyptia_fleet/in_calyptia_fleet.c @@ -685,24 +685,47 @@ static int in_calyptia_fleet_collect(struct flb_input_instance *ins, goto http_error; } header = flb_sds_create_size(4096); - flb_sds_printf(&header, - "[CUSTOM]\n" - " Name calyptia\n" - " api_key %s\n" - " fleet_id %s\n" - " add_label fleet_id %s\n" - " Fleet.Config_Dir %s\n" - " calyptia_host %s\n" - " calyptia_port %d\n" - " calyptia_tls %s\n", - ctx->api_key, - ctx->fleet_id, - ctx->fleet_id, - ctx->config_dir, - ctx->ins->host.name, - ctx->ins->host.port, - tls_setting_string(ctx->ins->use_tls) - ); + if (ctx->fleet_name == NULL) { + flb_sds_printf(&header, + "[CUSTOM]\n" + " Name calyptia\n" + " api_key %s\n" + " fleet_id %s\n" + " add_label fleet_id %s\n" + " Fleet.Config_Dir %s\n" + " calyptia_host %s\n" + " calyptia_port %d\n" + " calyptia_tls %s\n", + ctx->api_key, + ctx->fleet_id, + ctx->fleet_id, + ctx->config_dir, + ctx->ins->host.name, + ctx->ins->host.port, + tls_setting_string(ctx->ins->use_tls) + ); + } else { + flb_sds_printf(&header, + "[CUSTOM]\n" + " Name calyptia\n" + " api_key %s\n" + " fleet_name %s\n" + " fleet_id %s\n" + " add_label fleet_id %s\n" + " Fleet.Config_Dir %s\n" + " calyptia_host %s\n" + " calyptia_port %d\n" + " calyptia_tls %s\n", + ctx->api_key, + ctx->fleet_name, + ctx->fleet_id, + ctx->fleet_id, + ctx->config_dir, + ctx->ins->host.name, + ctx->ins->host.port, + tls_setting_string(ctx->ins->use_tls) + ); + } fwrite(header, strlen(header), 1, cfgfp); flb_sds_destroy(header); fwrite(data, client->resp.payload_size, 1, cfgfp); From b6576c76270c1057c00f71a4fb9c30d73fd0ea1b Mon Sep 17 00:00:00 2001 From: Phillip Whelan Date: Thu, 20 Jul 2023 18:53:48 -0400 Subject: [PATCH 144/315] in_calyptia_fleet: keep casing consistent in the generated configuration file. Signed-off-by: Phillip Whelan --- plugins/in_calyptia_fleet/in_calyptia_fleet.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/in_calyptia_fleet/in_calyptia_fleet.c b/plugins/in_calyptia_fleet/in_calyptia_fleet.c index 42880b9c043..6452d49b174 100644 --- a/plugins/in_calyptia_fleet/in_calyptia_fleet.c +++ b/plugins/in_calyptia_fleet/in_calyptia_fleet.c @@ -692,7 +692,7 @@ static int in_calyptia_fleet_collect(struct flb_input_instance *ins, " api_key %s\n" " fleet_id %s\n" " add_label fleet_id %s\n" - " Fleet.Config_Dir %s\n" + " fleet.config_dir %s\n" " calyptia_host %s\n" " calyptia_port %d\n" " calyptia_tls %s\n", @@ -712,7 +712,7 @@ static int in_calyptia_fleet_collect(struct flb_input_instance *ins, " fleet_name %s\n" " fleet_id %s\n" " add_label fleet_id %s\n" - " Fleet.Config_Dir %s\n" + " fleet.config_dir %s\n" " calyptia_host %s\n" " calyptia_port %d\n" " calyptia_tls %s\n", From a6bff43d33c65d30cf95b4bc39ac3301f6187dbc Mon Sep 17 00:00:00 2001 From: Leonardo Alminana Date: Fri, 21 Jul 2023 02:25:07 +0200 Subject: [PATCH 145/315] core: introduced batch flush result processing Additionally, when shutting downflb_input_exit_all was moved to be the last step to prevent it from unmapping chunks that are still in use until flb_output_exit is executed. Signed-off-by: Leonardo Alminana --- include/fluent-bit/flb_engine.h | 2 + src/flb_engine.c | 66 ++++++++++++++++++++++++++------- 2 files changed, 54 insertions(+), 14 deletions(-) diff --git a/include/fluent-bit/flb_engine.h b/include/fluent-bit/flb_engine.h index e9e3f3d2c09..4c1cb076352 100644 --- a/include/fluent-bit/flb_engine.h +++ b/include/fluent-bit/flb_engine.h @@ -26,6 +26,8 @@ #include #include +#define FLB_ENGINE_OUTPUT_EVENT_BATCH_SIZE 1 + int flb_engine_start(struct flb_config *config); int flb_engine_failed(struct flb_config *config); int flb_engine_flush(struct flb_config *config, diff --git a/src/flb_engine.c b/src/flb_engine.c index b9b6626dd84..6bf0a03cd6d 100644 --- a/src/flb_engine.c +++ b/src/flb_engine.c @@ -17,6 +17,7 @@ * limitations under the License. */ +#include #include #include @@ -206,29 +207,22 @@ static inline int handle_input_event(flb_pipefd_t fd, uint64_t ts, return 0; } -static inline int handle_output_event(flb_pipefd_t fd, uint64_t ts, - struct flb_config *config) +static inline int handle_output_event(uint64_t ts, + struct flb_config *config, + uint64_t val) { int ret; - int bytes; int task_id; int out_id; int retries; int retry_seconds; uint32_t type; uint32_t key; - uint64_t val; char *name; struct flb_task *task; struct flb_task_retry *retry; struct flb_output_instance *ins; - bytes = flb_pipe_r(fd, &val, sizeof(val)); - if (bytes == -1) { - flb_errno(); - return -1; - } - /* Get type and key */ type = FLB_BITS_U64_HIGH(val); key = FLB_BITS_U64_LOW(val); @@ -441,6 +435,52 @@ static inline int handle_output_event(flb_pipefd_t fd, uint64_t ts, return 0; } +static inline int handle_output_events(flb_pipefd_t fd, + struct flb_config *config) +{ + uint64_t values[FLB_ENGINE_OUTPUT_EVENT_BATCH_SIZE]; + int result; + int bytes; + size_t limit; + size_t index; + uint64_t ts; + + memset(&values, 0, sizeof(values)); + + bytes = flb_pipe_r(fd, &values, sizeof(values)); + + if (bytes == -1) { + flb_errno(); + return -1; + } + + limit = floor(bytes / sizeof(uint64_t)); + + ts = cfl_time_now(); + + for (index = 0 ; + index < limit && + index < (sizeof(values) / sizeof(values[0])) ; + index++) { + if (values[index] == 0) { + break; + } + + result = handle_output_event(ts, config, values[index]); + } + + /* This is wrong, in one hand, if handle_output_event_ fails we should + * stop, on the other, we have already consumed the signals from the pipe + * so we have to do whatever we can with them. + * + * And a side effect is that since we have N results but we are not aborting + * as soon as we get an error there could be N results to this function which + * not only are we not ready to handle but is not even checked at the moment. + */ + + return result; +} + static inline int flb_engine_manager(flb_pipefd_t fd, struct flb_config *config) { int bytes; @@ -982,13 +1022,11 @@ int flb_engine_start(struct flb_config *config) } } else if (event->type == FLB_ENGINE_EV_OUTPUT) { - ts = cfl_time_now(); - /* * Event originated by an output plugin. likely a Task return * status. */ - handle_output_event(event->fd, ts, config); + handle_output_events(event->fd, config); } else if (event->type == FLB_ENGINE_EV_INPUT) { ts = cfl_time_now(); @@ -1042,10 +1080,10 @@ int flb_engine_shutdown(struct flb_config *config) flb_router_exit(config); /* cleanup plugins */ - flb_input_exit_all(config); flb_filter_exit(config); flb_output_exit(config); flb_custom_exit(config); + flb_input_exit_all(config); /* Destroy the storage context */ flb_storage_destroy(config); From b91df9b7e3f8d15d48db7dcfcbcd9c28741c80c0 Mon Sep 17 00:00:00 2001 From: Leonardo Alminana Date: Fri, 21 Jul 2023 02:27:05 +0200 Subject: [PATCH 146/315] core: changed the flush event priority This change was required to ensure that flush results are processed and any resources tied to those coroutines are released before we schedule new flushes. Signed-off-by: Leonardo Alminana --- include/fluent-bit/flb_engine_macros.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/fluent-bit/flb_engine_macros.h b/include/fluent-bit/flb_engine_macros.h index bdc862523aa..825febc0255 100644 --- a/include/fluent-bit/flb_engine_macros.h +++ b/include/fluent-bit/flb_engine_macros.h @@ -66,7 +66,7 @@ #define FLB_ENGINE_PRIORITY_CB_SCHED FLB_ENGINE_PRIORITY_TOP #define FLB_ENGINE_PRIORITY_CB_TIMER FLB_ENGINE_PRIORITY_TOP #define FLB_ENGINE_PRIORITY_SHUTDOWN FLB_ENGINE_PRIORITY_TOP -#define FLB_ENGINE_PRIORITY_FLUSH FLB_ENGINE_PRIORITY_TOP +#define FLB_ENGINE_PRIORITY_FLUSH (FLB_ENGINE_PRIORITY_NETWORK + 1) #define FLB_ENGINE_PRIORITY_DNS FLB_ENGINE_PRIORITY_NETWORK #define FLB_ENGINE_PRIORITY_CONNECT FLB_ENGINE_PRIORITY_NETWORK From 07b8ea16f710732d8ed034ac3195be960bfea1dd Mon Sep 17 00:00:00 2001 From: Leonardo Alminana Date: Fri, 21 Jul 2023 02:29:13 +0200 Subject: [PATCH 147/315] output: added a flush abortion mechanism This change introduces an additional check in output_pre_cb_flush to ensure that chunks can be dropped if they were scheduled to be flushed but the flush coroutine has not entered the plugins entry point yet. Signed-off-by: Leonardo Alminana --- include/fluent-bit/flb_output.h | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/include/fluent-bit/flb_output.h b/include/fluent-bit/flb_output.h index 5fe13f99c18..661054b7db4 100644 --- a/include/fluent-bit/flb_output.h +++ b/include/fluent-bit/flb_output.h @@ -498,6 +498,12 @@ struct flb_out_flush_params { extern FLB_TLS_DEFINE(struct flb_out_flush_params, out_flush_params); +#define FLB_OUTPUT_RETURN(x) \ + flb_output_return_do(x); \ + return + +static inline void flb_output_return_do(int x); + static FLB_INLINE void output_params_set(struct flb_output_flush *out_flush, struct flb_coro *coro, struct flb_task *task, @@ -537,6 +543,7 @@ static FLB_INLINE void output_params_set(struct flb_output_flush *out_flush, static FLB_INLINE void output_pre_cb_flush(void) { + int route_status; struct flb_coro *coro; struct flb_output_plugin *out_p; struct flb_out_flush_params *params; @@ -557,11 +564,29 @@ static FLB_INLINE void output_pre_cb_flush(void) */ coro = params->coro; persisted_params = *params; + co_switch(coro->caller); /* Continue, we will resume later */ out_p = persisted_params.out_plugin; + flb_task_acquire_lock(persisted_params.out_flush->task); + + route_status = flb_task_get_route_status( + persisted_params.out_flush->task, + persisted_params.out_flush->o_ins); + + if (route_status == FLB_TASK_ROUTE_DROPPED) { + flb_task_release_lock(persisted_params.out_flush->task); + + FLB_OUTPUT_RETURN(FLB_ERROR); + } + + flb_task_activate_route(persisted_params.out_flush->task, + persisted_params.out_flush->o_ins); + + flb_task_release_lock(persisted_params.out_flush->task); + out_p->cb_flush(persisted_params.event_chunk, persisted_params.out_flush, persisted_params.i_ins, @@ -909,6 +934,12 @@ static inline void flb_output_return(int ret, struct flb_coro *co) { o_ins = out_flush->o_ins; task = out_flush->task; + flb_task_acquire_lock(task); + + flb_task_deactivate_route(task, o_ins); + + flb_task_release_lock(task); + if (out_flush->processed_event_chunk) { if (task->event_chunk->data != out_flush->processed_event_chunk->data) { flb_free(out_flush->processed_event_chunk->data); From 78f8a1fd53164beab52f6c4ac9f400855c871f58 Mon Sep 17 00:00:00 2001 From: Leonardo Alminana Date: Fri, 21 Jul 2023 02:31:11 +0200 Subject: [PATCH 148/315] task: added locking and route dropping mechanisms A lock was added because it needs to be used when checking the route status from the main thread when trying to drop roll chunks over. Signed-off-by: Leonardo Alminana --- include/fluent-bit/flb_task.h | 98 +++++++++++++++++++++++++++++++++++ src/flb_task.c | 5 +- 2 files changed, 102 insertions(+), 1 deletion(-) diff --git a/include/fluent-bit/flb_task.h b/include/fluent-bit/flb_task.h index b8e95ff3e6a..1e8de515995 100644 --- a/include/fluent-bit/flb_task.h +++ b/include/fluent-bit/flb_task.h @@ -50,7 +50,13 @@ #define FLB_TASK_SET(ret, task_id, out_id) \ (uint32_t) ((ret << 28) | (task_id << 14) | out_id) +/* Route status */ +#define FLB_TASK_ROUTE_INACTIVE 0 +#define FLB_TASK_ROUTE_ACTIVE 1 +#define FLB_TASK_ROUTE_DROPPED 2 + struct flb_task_route { + int status; struct flb_output_instance *out; struct mk_list _head; }; @@ -86,6 +92,7 @@ struct flb_task { struct mk_list _head; /* link to input_instance */ struct flb_input_instance *i_ins; /* input instance */ struct flb_config *config; /* parent flb config */ + pthread_mutex_t lock; }; /* @@ -177,5 +184,96 @@ static inline void flb_task_users_dec(struct flb_task *task, int release_check) } } +static inline void flb_task_acquire_lock(struct flb_task *task) +{ + pthread_mutex_lock(&task->lock); +} + +static inline void flb_task_release_lock(struct flb_task *task) +{ + pthread_mutex_unlock(&task->lock); +} + +static FLB_INLINE int flb_task_get_active_route_count( + struct flb_task *task) +{ + struct mk_list *iterator; + int result; + struct flb_task_route *route; + + result = 0; + + mk_list_foreach(iterator, &task->routes) { + route = mk_list_entry(iterator, struct flb_task_route, _head); + + if (route->status == FLB_TASK_ROUTE_ACTIVE) { + result++; + } + } + + return result; +} + +static FLB_INLINE size_t flb_task_get_route_status( + struct flb_task *task, + struct flb_output_instance *o_ins) +{ + struct mk_list *iterator; + size_t result; + struct flb_task_route *route; + + result = FLB_TASK_ROUTE_INACTIVE; + + mk_list_foreach(iterator, &task->routes) { + route = mk_list_entry(iterator, struct flb_task_route, _head); + + if (route->out == o_ins) { + result = route->status; + break; + } + } + + return result; +} + +static FLB_INLINE void flb_task_set_route_status( + struct flb_task *task, + struct flb_output_instance *o_ins, + int new_status) +{ + struct mk_list *iterator; + struct flb_task_route *route; + + mk_list_foreach(iterator, &task->routes) { + route = mk_list_entry(iterator, struct flb_task_route, _head); + + if (route->out == o_ins) { + route->status = new_status; + break; + } + } +} + + +static FLB_INLINE void flb_task_activate_route( + struct flb_task *task, + struct flb_output_instance *o_ins) +{ + flb_task_set_route_status(task, o_ins, FLB_TASK_ROUTE_ACTIVE); +} + +static FLB_INLINE void flb_task_deactivate_route( + struct flb_task *task, + struct flb_output_instance *o_ins) +{ + flb_task_set_route_status(task, o_ins, FLB_TASK_ROUTE_INACTIVE); +} + +static FLB_INLINE void flb_task_drop_route( + struct flb_task *task, + struct flb_output_instance *o_ins) +{ + flb_task_set_route_status(task, o_ins, FLB_TASK_ROUTE_DROPPED); +} #endif diff --git a/src/flb_task.c b/src/flb_task.c index 9e6da583550..bc9ddc6344f 100644 --- a/src/flb_task.c +++ b/src/flb_task.c @@ -256,6 +256,8 @@ static struct flb_task *task_alloc(struct flb_config *config) mk_list_init(&task->routes); mk_list_init(&task->retries); + pthread_mutex_init(&task->lock, NULL); + return task; } @@ -420,12 +422,13 @@ struct flb_task *flb_task_create(uint64_t ref_id, } if (flb_routes_mask_get_bit(task_ic->routes_mask, o_ins->id) != 0) { - route = flb_malloc(sizeof(struct flb_task_route)); + route = flb_calloc(1, sizeof(struct flb_task_route)); if (!route) { flb_errno(); continue; } + route->status = FLB_TASK_ROUTE_INACTIVE; route->out = o_ins; mk_list_add(&route->_head, &task->routes); count++; From 2d0ac1b56b2ca74ee089feda96cd6f00d758fef1 Mon Sep 17 00:00:00 2001 From: Leonardo Alminana Date: Fri, 21 Jul 2023 02:34:11 +0200 Subject: [PATCH 149/315] storage_backlog: changed the release strategy The output queue release strategy was changed from a transaction based approach to a non transaction based approach in order to allow rollover to work properly. Additionally, the default behavior when chunks are mapped was changed to set them down in order to honor max_chunks_up. Signed-off-by: Leonardo Alminana --- plugins/in_storage_backlog/sb.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/plugins/in_storage_backlog/sb.c b/plugins/in_storage_backlog/sb.c index 75840a49169..1380caf8abb 100644 --- a/plugins/in_storage_backlog/sb.c +++ b/plugins/in_storage_backlog/sb.c @@ -91,7 +91,7 @@ static int sb_append_chunk_to_segregated_backlogs(struct cio_chunk *target_chun int sb_segregate_chunks(struct flb_config *config); int sb_release_output_queue_space(struct flb_output_instance *output_plugin, - size_t required_space); + ssize_t *required_space); ssize_t sb_get_releasable_output_queue_space(struct flb_output_instance *output_plugin, size_t required_space); @@ -441,9 +441,10 @@ ssize_t sb_get_releasable_output_queue_space(struct flb_output_instance *output_ } int sb_release_output_queue_space(struct flb_output_instance *output_plugin, - size_t required_space) + ssize_t *required_space) { struct mk_list *chunk_iterator_tmp; + struct cio_chunk *underlying_chunk; struct mk_list *chunk_iterator; size_t released_space; struct flb_sb *context; @@ -469,18 +470,17 @@ int sb_release_output_queue_space(struct flb_output_instance *output_plugin, chunk = mk_list_entry(chunk_iterator, struct sb_out_chunk, _head); released_space += chunk->size; + underlying_chunk = chunk->chunk; - cio_chunk_close(chunk->chunk, FLB_TRUE); - sb_remove_chunk_from_segregated_backlogs(chunk->chunk, context); + sb_remove_chunk_from_segregated_backlogs(underlying_chunk, context); + cio_chunk_close(underlying_chunk, FLB_TRUE); - if (released_space >= required_space) { + if (released_space >= *required_space) { break; } } - if (released_space < required_space) { - return -3; - } + *required_space -= released_space; return 0; } @@ -618,6 +618,7 @@ static int cb_queue_chunks(struct flb_input_instance *in, * queue but we need to leave it in the remainder queues. */ sb_remove_chunk_from_segregated_backlogs(chunk_instance->chunk, ctx); + cio_chunk_down(ch); /* check our limits */ total += size; From b69f6a66ec44311c26d84084a2b2ea6a2bf14886 Mon Sep 17 00:00:00 2001 From: Leonardo Alminana Date: Fri, 21 Jul 2023 02:34:57 +0200 Subject: [PATCH 150/315] input_chunk: changed the chunk release strategy The chunk release strategy was changed from a transaction based approach to a non transaction based approach in order to allow rollover to work properly. Signed-off-by: Leonardo Alminana --- src/flb_input_chunk.c | 355 +++++++++++------------------------------- 1 file changed, 88 insertions(+), 267 deletions(-) diff --git a/src/flb_input_chunk.c b/src/flb_input_chunk.c index 47713325f43..35bfde75ba7 100644 --- a/src/flb_input_chunk.c +++ b/src/flb_input_chunk.c @@ -65,7 +65,7 @@ extern ssize_t sb_get_releasable_output_queue_space(struct flb_output_instance * size_t required_space); extern int sb_release_output_queue_space(struct flb_output_instance *output_plugin, - size_t required_space); + ssize_t *required_space); #else @@ -77,7 +77,7 @@ ssize_t sb_get_releasable_output_queue_space(struct flb_output_instance *output_ } int sb_release_output_queue_space(struct flb_output_instance *output_plugin, - size_t required_space) + ssize_t *required_space) { return 0; } @@ -90,48 +90,17 @@ static int flb_input_chunk_safe_delete(struct flb_input_chunk *ic, static int flb_input_chunk_is_task_safe_delete(struct flb_task *task); -static ssize_t flb_input_chunk_get_real_size(struct flb_input_chunk *ic); - -static ssize_t flb_input_chunk_get_releasable_space( - struct flb_input_chunk *new_input_chunk, - struct flb_input_instance *input_plugin, - struct flb_output_instance *output_plugin, - size_t required_space) -{ - struct mk_list *input_chunk_iterator; - ssize_t releasable_space; - struct flb_input_chunk *old_input_chunk; - - releasable_space = 0; - - mk_list_foreach(input_chunk_iterator, &input_plugin->chunks) { - old_input_chunk = mk_list_entry(input_chunk_iterator, struct flb_input_chunk, _head); - - if (!flb_routes_mask_get_bit(old_input_chunk->routes_mask, output_plugin->id)) { - continue; - } - - if (flb_input_chunk_safe_delete(new_input_chunk, old_input_chunk, - output_plugin->id) == FLB_FALSE || - flb_input_chunk_is_task_safe_delete(old_input_chunk->task) == FLB_FALSE) { - continue; - } - - releasable_space += flb_input_chunk_get_real_size(old_input_chunk); - - if (releasable_space >= required_space) { - break; - } - } +static int flb_input_chunk_drop_task_route( + struct flb_task *task, + struct flb_output_instance *o_ins); - return releasable_space; -} +static ssize_t flb_input_chunk_get_real_size(struct flb_input_chunk *ic); static int flb_input_chunk_release_space( struct flb_input_chunk *new_input_chunk, struct flb_input_instance *input_plugin, struct flb_output_instance *output_plugin, - ssize_t required_space, + ssize_t *required_space, int release_scope) { struct mk_list *input_chunk_iterator_tmp; @@ -156,8 +125,12 @@ static int flb_input_chunk_release_space( if (flb_input_chunk_safe_delete(new_input_chunk, old_input_chunk, - output_plugin->id) == FLB_FALSE || - flb_input_chunk_is_task_safe_delete(old_input_chunk->task) == FLB_FALSE) { + output_plugin->id) == FLB_FALSE) { + continue; + } + + if (flb_input_chunk_drop_task_route(old_input_chunk->task, + output_plugin) == FLB_FALSE) { continue; } @@ -209,14 +182,12 @@ static int flb_input_chunk_release_space( released_space += chunk_size; } - if (released_space >= required_space) { + if (released_space >= *required_space) { break; } } - if (released_space < required_space) { - return -2; - } + *required_space -= released_space; return 0; } @@ -298,6 +269,43 @@ int flb_input_chunk_write_at(void *data, off_t offset, return ret; } +static int flb_input_chunk_drop_task_route( + struct flb_task *task, + struct flb_output_instance *output_plugin) +{ + int route_status; + int result; + + if (task == NULL) { + return FLB_TRUE; + } + + result = FLB_TRUE; + + if (task->users != 0) { + result = FLB_FALSE; + + if (output_plugin != NULL) { + flb_task_acquire_lock(task); + + route_status = flb_task_get_route_status(task, output_plugin); + + if (route_status == FLB_TASK_ROUTE_INACTIVE) { + flb_task_set_route_status(task, + output_plugin, + FLB_TASK_ROUTE_DROPPED); + + result = FLB_TRUE; + } + + flb_task_release_lock(task); + } + } + + return result; +} + + /* * For input_chunk referenced by an outgoing task, we need to check * whether the chunk is in the middle of output flush callback @@ -342,11 +350,10 @@ int flb_input_chunk_release_space_compound( size_t *local_release_requirement, int release_local_space) { - ssize_t segregated_backlog_releasable_space; - ssize_t active_backlog_releasable_space; - ssize_t active_plugin_releasable_space; ssize_t required_space_remainder; struct flb_input_instance *storage_backlog_instance; + struct flb_input_instance *input_plugin_instance; + struct mk_list *iterator; int result; storage_backlog_instance = output_plugin->config->storage_input_plugin; @@ -354,88 +361,46 @@ int flb_input_chunk_release_space_compound( *local_release_requirement = flb_input_chunk_get_real_size(new_input_chunk); required_space_remainder = (ssize_t) *local_release_requirement; - segregated_backlog_releasable_space = 0; - active_backlog_releasable_space = 0; - active_plugin_releasable_space = 0; - - active_backlog_releasable_space = flb_input_chunk_get_releasable_space( - new_input_chunk, - storage_backlog_instance, - output_plugin, - required_space_remainder); - - required_space_remainder -= active_backlog_releasable_space; - if (required_space_remainder > 0) { - segregated_backlog_releasable_space = sb_get_releasable_output_queue_space( - output_plugin, - required_space_remainder); - - required_space_remainder -= segregated_backlog_releasable_space; - } - - if (required_space_remainder > 0) { - active_plugin_releasable_space = flb_input_chunk_get_releasable_space( - new_input_chunk, - new_input_chunk->in, - output_plugin, - required_space_remainder); - - required_space_remainder -= active_plugin_releasable_space; - } - - /* When we get here required_space_remainder could be negative but it's not a problem - * this happens when the weight of the removed chunk is higher than the remainder of - * the required space and it's not something that can nor should be prevented. - */ - - if (required_space_remainder > 0) { - return -2; - } - - required_space_remainder = (ssize_t) *local_release_requirement; - - if (required_space_remainder > 0 && active_backlog_releasable_space > 0) { result = flb_input_chunk_release_space(new_input_chunk, storage_backlog_instance, output_plugin, - active_backlog_releasable_space, + &required_space_remainder, FLB_INPUT_CHUNK_RELEASE_SCOPE_GLOBAL); - - if (result) { - return -3; - } - - required_space_remainder -= active_backlog_releasable_space; } - if (required_space_remainder > 0 && segregated_backlog_releasable_space > 0) { - result = sb_release_output_queue_space( - output_plugin, - segregated_backlog_releasable_space); - - if (result) { - *local_release_requirement = (size_t) required_space_remainder; - - return -4; - } - - required_space_remainder -= segregated_backlog_releasable_space; + if (required_space_remainder > 0) { + result = sb_release_output_queue_space(output_plugin, + &required_space_remainder); } if (release_local_space) { - if (required_space_remainder > 0 && active_plugin_releasable_space > 0) { + if (required_space_remainder > 0) { result = flb_input_chunk_release_space(new_input_chunk, new_input_chunk->in, output_plugin, - active_plugin_releasable_space, + &required_space_remainder, FLB_INPUT_CHUNK_RELEASE_SCOPE_LOCAL); + } + } - if (result) { - return -5; + if (required_space_remainder > 0) { + mk_list_foreach(iterator, &output_plugin->config->inputs) { + input_plugin_instance = \ + mk_list_entry(iterator, struct flb_input_instance, _head); + + if (input_plugin_instance != new_input_chunk->in) { + result = flb_input_chunk_release_space( + new_input_chunk, + input_plugin_instance, + output_plugin, + &required_space_remainder, + FLB_INPUT_CHUNK_RELEASE_SCOPE_LOCAL); } - required_space_remainder -= active_plugin_releasable_space; + if (required_space_remainder <= 0) { + break; + } } } @@ -445,57 +410,9 @@ int flb_input_chunk_release_space_compound( *local_release_requirement = (size_t) required_space_remainder; - return 0; -} - -/* - * Returns how many chunks needs to be dropped in order to get enough space to - * buffer the incoming data (with size chunk_size) - */ -int flb_intput_chunk_count_dropped_chunks(struct flb_input_chunk *ic, - struct flb_output_instance *o_ins, - size_t chunk_size) -{ - int count = 0; - int enough_space = FLB_FALSE; - ssize_t bytes_remained; - struct mk_list *head; - struct flb_input_chunk *old_ic; - - FS_CHUNK_SIZE_DEBUG(o_ins); - bytes_remained = o_ins->total_limit_size - - o_ins->fs_chunks_size - - o_ins->fs_backlog_chunks_size; - - mk_list_foreach(head, &ic->in->chunks) { - old_ic = mk_list_entry(head, struct flb_input_chunk, _head); + (void) result; - if (flb_input_chunk_safe_delete(ic, old_ic, o_ins->id) == FLB_FALSE || - flb_input_chunk_is_task_safe_delete(old_ic->task) == FLB_FALSE) { - continue; - } - - bytes_remained += flb_input_chunk_get_real_size(old_ic); - count++; - if (bytes_remained >= (ssize_t) chunk_size) { - enough_space = FLB_TRUE; - break; - } - } - - /* - * flb_intput_chunk_count_dropped_chunks(3) will only be called if the chunk will - * be flushing to the output instance passed in and the instance will reach its - * limit after appending the new data. This function will try to count how many - * chunks need to be dropped in order to place the incoing chunk. - * - * Return '0' means that we cannot find a slot to ingest the incoming data. - */ - if (enough_space == FLB_FALSE) { - return 0; - } - - return count; + return 0; } /* @@ -507,13 +424,8 @@ int flb_input_chunk_find_space_new_data(struct flb_input_chunk *ic, { int count; int result; - ssize_t bytes; - ssize_t old_ic_bytes; - struct mk_list *tmp; struct mk_list *head; - struct mk_list *head_chunk; struct flb_output_instance *o_ins; - struct flb_input_chunk *old_ic; size_t local_release_requirement; /* @@ -522,8 +434,9 @@ int flb_input_chunk_find_space_new_data(struct flb_input_chunk *ic, * routes_mask to only route to the output plugin that have enough space after * deleting some chunks fome the queue. */ + count = 0; + mk_list_foreach(head, &ic->in->config->outputs) { - count = 0; o_ins = mk_list_entry(head, struct flb_output_instance, _head); if ((o_ins->total_limit_size == -1) || ((1 << o_ins->id) & overlimit) == 0 || @@ -536,112 +449,19 @@ int flb_input_chunk_find_space_new_data(struct flb_input_chunk *ic, result = flb_input_chunk_release_space_compound( ic, o_ins, &local_release_requirement, - FLB_FALSE); + FLB_TRUE); - if (!result && local_release_requirement == 0) { - /* If this function returned 0 it means the space requirement was - * satisfied solely by releasing chunks in either storage_backlog - * state (segregated or in queue) - */ - continue; - } - - /* flb_input_chunk_find_space_new_data_backlog may fail to meet the space - * requirements but it always sets local_release_requirement to the right amount - */ - - count = flb_intput_chunk_count_dropped_chunks(ic, o_ins, local_release_requirement); - - if (count == 0) { - /* - * The worst scenerio is that we cannot find a space by dropping some - * old chunks for the incoming chunk. We need to adjust the routes_mask - * of the incoming chunk to not flush to that output instance. - */ - flb_error("[input chunk] chunk %s would exceed total limit size in plugin %s", - flb_input_chunk_get_name(ic), o_ins->name); - - flb_routes_mask_clear_bit(ic->routes_mask, o_ins->id); - if (flb_routes_mask_is_empty(ic->routes_mask)) { - bytes = flb_input_chunk_get_size(ic); - if (bytes != 0) { - /* - * Skip newly created chunk as newly created chunk - * hasn't updated the fs_chunks_size yet. - */ - bytes = flb_input_chunk_get_real_size(ic); - FS_CHUNK_SIZE_DEBUG_MOD(o_ins, ic, -bytes); - o_ins->fs_chunks_size -= bytes; - flb_debug("[input chunk] chunk %s has no output route, " - "remove %ld bytes from fs_chunks_size", - flb_input_chunk_get_name(ic), bytes); - } - } - - continue; - } - - /* - * Here we need to drop some chunks from the beginning of chunks list. - * Since chunks are stored in a double linked list (mk_list), we are - * able to iterate the list from the beginning and check if the current - * chunk is able to be removed. - */ - mk_list_foreach_safe(head_chunk, tmp, &ic->in->chunks) { - old_ic = mk_list_entry(head_chunk, struct flb_input_chunk, _head); - - if (flb_input_chunk_safe_delete(ic, old_ic, o_ins->id) == FLB_FALSE || - flb_input_chunk_is_task_safe_delete(old_ic->task) == FLB_FALSE) { - continue; - } - - old_ic_bytes = flb_input_chunk_get_real_size(old_ic); - - /* drop chunk by adjusting the routes_mask */ - flb_routes_mask_clear_bit(old_ic->routes_mask, o_ins->id); - FS_CHUNK_SIZE_DEBUG_MOD(o_ins, old_ic, -old_ic_bytes); - o_ins->fs_chunks_size -= old_ic_bytes; - - flb_debug("[input chunk] consider route removal for chunk %s with size %zd bytes from input plugin %s to output plugin %s " - "to place the incoming data with size %zu bytes, total_limit_size=%zu", flb_input_chunk_get_name(old_ic), - old_ic_bytes, ic->in->name, o_ins->name, chunk_size, o_ins->total_limit_size); - - if (flb_routes_mask_is_empty(old_ic->routes_mask)) { - if (old_ic->task != NULL) { - /* - * If the chunk is referenced by a task and task has no active route, - * we need to destroy the task as well. - */ - if (old_ic->task->users == 0) { - flb_debug("[task] drop task_id %d with no active route from input plugin %s", - old_ic->task->id, ic->in->name); - /* end-user friendly message */ - flb_info("[input chunk] remove chunk %s with size %zd bytes from input plugin %s to output plugin %s " - "to place the incoming data with size %zu bytes, total_limit_size=%zu, task_id=%d", - flb_input_chunk_get_name(old_ic), old_ic_bytes, ic->in->name, o_ins->name, chunk_size, - o_ins->total_limit_size, old_ic->task->id); - flb_task_destroy(old_ic->task, FLB_TRUE); - } - } - else { - flb_info("[input chunk] remove chunk %s with size %zd bytes from input plugin %s to output plugin %s " - "to place the incoming data with size %zu bytes, total_limit_size=%zu", flb_input_chunk_get_name(old_ic), - old_ic_bytes, ic->in->name, o_ins->name, chunk_size, o_ins->total_limit_size); - flb_input_chunk_destroy(old_ic, FLB_TRUE); - } - } - - count--; - if (count == 0) { - /* we have dropped enough chunks to place the incoming chunks */ - break; - } + if (result != 0 || + local_release_requirement != 0) { + count++; } } if (count != 0) { flb_error("[input chunk] fail to drop enough chunks in order to place new data"); + exit(0); } + return 0; } @@ -1211,6 +1031,7 @@ static struct flb_input_chunk *input_chunk_get(struct flb_input_instance *in, int new_chunk = FLB_FALSE; size_t out_size; struct flb_input_chunk *ic = NULL; + size_t expected_chunk_size; if (tag_len > FLB_INPUT_CHUNK_TAG_MAX) { flb_plg_warn(in, From 55606281008956a72c06b5db577cb3ea2dd86e02 Mon Sep 17 00:00:00 2001 From: Thiago Padilha Date: Mon, 24 Jul 2023 20:00:09 -0300 Subject: [PATCH 151/315] config: allow up to 32MB length of line buffer in read_config (#7691) --------- Signed-off-by: Thiago Padilha Signed-off-by: Hiroshi Hatake Co-authored-by: Hiroshi Hatake --- include/fluent-bit/flb_config_format.h | 4 +- src/config_format/flb_cf_fluentbit.c | 41 +++++++++++----- tests/internal/config_format_fluentbit.c | 49 +++++++++++++++++++ .../config_format/classic/nolimitline.conf | 11 +++++ 4 files changed, 93 insertions(+), 12 deletions(-) create mode 100644 tests/internal/data/config_format/classic/nolimitline.conf diff --git a/include/fluent-bit/flb_config_format.h b/include/fluent-bit/flb_config_format.h index 72f6f31cddd..8205ebcc1cd 100644 --- a/include/fluent-bit/flb_config_format.h +++ b/include/fluent-bit/flb_config_format.h @@ -29,4 +29,6 @@ #include "config_format/flb_cf_yaml.h" #endif -#endif \ No newline at end of file +#define FLB_DEFAULT_CF_BUF_SIZE 4096 + +#endif diff --git a/src/config_format/flb_cf_fluentbit.c b/src/config_format/flb_cf_fluentbit.c index f973654ad35..ac72f9425e4 100644 --- a/src/config_format/flb_cf_fluentbit.c +++ b/src/config_format/flb_cf_fluentbit.c @@ -40,7 +40,6 @@ #define PATH_MAX MAX_PATH #endif -#define FLB_CF_BUF_SIZE 4096 #define FLB_CF_FILE_NUM_LIMIT 1000 /* indent checker return codes */ @@ -418,6 +417,8 @@ static int read_config(struct flb_cf *cf, struct local_ctx *ctx, char *val = NULL; int val_len; char *buf; + char *fgets_ptr; + size_t bufsize = FLB_DEFAULT_CF_BUF_SIZE; char tmp[PATH_MAX]; flb_sds_t section = NULL; flb_sds_t indent = NULL; @@ -427,6 +428,9 @@ static int read_config(struct flb_cf *cf, struct local_ctx *ctx, struct flb_cf_section *current_section = NULL; struct flb_cf_group *current_group = NULL; struct cfl_variant *var; + unsigned long line_hard_limit; + + line_hard_limit = 32 * 1024 * 1024; /* 32MiB */ FILE *f = NULL; @@ -479,14 +483,14 @@ static int read_config(struct flb_cf *cf, struct local_ctx *ctx, #ifndef FLB_HAVE_STATIC_CONF /* Open configuration file */ - if ((f = fopen(cfg_file, "r")) == NULL) { + if ((f = fopen(cfg_file, "rb")) == NULL) { flb_warn("[config] I cannot open %s file", cfg_file); return -1; } #endif /* Allocate temporal buffer to read file content */ - buf = flb_malloc(FLB_CF_BUF_SIZE); + buf = flb_malloc(bufsize); if (!buf) { flb_errno(); goto error; @@ -501,7 +505,9 @@ static int read_config(struct flb_cf *cf, struct local_ctx *ctx, while (static_fgets(buf, FLB_CF_BUF_SIZE, in_data, &off)) { #else /* normal mode, read lines into a buffer */ - while (fgets(buf, FLB_CF_BUF_SIZE, f)) { + /* note that we use "fgets_ptr" so we can continue reading after realloc */ + fgets_ptr = buf; + while (fgets(fgets_ptr, bufsize - (fgets_ptr - buf), f)) { #endif len = strlen(buf); if (len > 0 && buf[len - 1] == '\n') { @@ -509,18 +515,31 @@ static int read_config(struct flb_cf *cf, struct local_ctx *ctx, if (len && buf[len - 1] == '\r') { buf[--len] = 0; } + /* after a successful line read, restore "fgets_ptr" to point to the + * beginning of buffer */ + fgets_ptr = buf; + } else if (feof(f)) { + /* handle EOF without a newline(CRLF or LF) */ + fgets_ptr = buf; } #ifndef FLB_HAVE_STATIC_CONF else { - /* - * If we don't find a break line, validate if we got an EOF or not. No EOF - * means that the incoming string is not finished so we must raise an - * exception. - */ - if (!feof(f)) { - config_error(cfg_file, line, "length of content has exceeded limit"); + /* resize the line buffer */ + bufsize *= 2; + if (bufsize > line_hard_limit) { + flb_error("reading line is exceeded to the limit size of %lu. Current size is: %zu", + line_hard_limit, bufsize); goto error; } + buf = flb_realloc(buf, bufsize); + if (!buf) { + flb_error("failed to resize line buffer to %zu", bufsize); + flb_errno(); + goto error; + } + /* read more, starting at the buf + len position */ + fgets_ptr = buf + len; + continue; } #endif diff --git a/tests/internal/config_format_fluentbit.c b/tests/internal/config_format_fluentbit.c index 9244a481600..5104ae62032 100644 --- a/tests/internal/config_format_fluentbit.c +++ b/tests/internal/config_format_fluentbit.c @@ -17,6 +17,7 @@ #define FLB_002 FLB_TESTS_DATA_PATH "/data/config_format/classic/indent_level_error.conf" #define FLB_003 FLB_TESTS_DATA_PATH "/data/config_format/classic/recursion.conf" #define FLB_004 FLB_TESTS_DATA_PATH "/data/config_format/classic/issue6281.conf" +#define FLB_005 FLB_TESTS_DATA_PATH "/data/config_format/classic/nolimitline.conf" #define ERROR_LOG "fluentbit_conf_error.log" @@ -258,11 +259,59 @@ void not_current_dir_files() } } +/* data/config_format/nolimitline.conf */ +void test_nolimit_line() +{ + struct mk_list *head; + struct flb_cf *cf; + struct flb_cf_section *s; + struct cfl_list *p_head; + struct cfl_kvpair *kv; + + cf = flb_cf_fluentbit_create(NULL, FLB_005, NULL, 0); + TEST_CHECK(cf != NULL); + + /* Total number of sections */ + TEST_CHECK(mk_list_size(&cf->sections) == 3); + + /* SERVICE check */ + TEST_CHECK(cf->service == NULL); + + /* Meta commands */ + TEST_CHECK(mk_list_size(&cf->metas) == 0); + + /* Check number sections per list */ + TEST_CHECK(mk_list_size(&cf->inputs) == 1); + TEST_CHECK(mk_list_size(&cf->filters) == 1); + TEST_CHECK(mk_list_size(&cf->outputs) == 1); + + /* Check the previous line buffer limit */ + s = flb_cf_section_get_by_name(cf, "filter"); + TEST_CHECK(s != NULL); + TEST_CHECK(mk_list_size(&s->groups) == 0); + + if (cfl_list_size(&s->properties->list) > 0) { + TEST_CHECK(cfl_list_size(&s->properties->list) == 4); + cfl_list_foreach(p_head, &s->properties->list) { + kv = cfl_list_entry(p_head, struct cfl_kvpair, _head); + if (strcmp(kv->key, "code") == 0) { + TEST_CHECK(cfl_sds_len(kv->val->data.as_string) > FLB_DEFAULT_CF_BUF_SIZE); + } + } + } + + printf("\n"); + flb_cf_dump(cf); + + flb_cf_destroy(cf); +} + TEST_LIST = { { "basic" , test_basic}, { "missing_value_issue5880" , missing_value}, { "indent_level_error" , indent_level_error}, { "recursion" , recursion}, { "not_current_dir_files", not_current_dir_files}, + { "no_limit_line", test_nolimit_line}, { 0 } }; diff --git a/tests/internal/data/config_format/classic/nolimitline.conf b/tests/internal/data/config_format/classic/nolimitline.conf new file mode 100644 index 00000000000..e7fff842015 --- /dev/null +++ b/tests/internal/data/config_format/classic/nolimitline.conf @@ -0,0 +1,11 @@ +[INPUT] + name dummy + +[FILTER] + Name lua + Match * + code local str = 'abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd'; function cb_filter(tag, ts, record) record.str = str; return 1, ts, record end + call cb_filter + +[OUTPUT] + name stdout From 82c3ef14cfa4c37de01a8d5b273a93e12ca0bd90 Mon Sep 17 00:00:00 2001 From: Hiroshi Hatake Date: Tue, 25 Jul 2023 08:01:53 +0900 Subject: [PATCH 152/315] in_syslog: Provide appending source address parameter (#7651) * in_syslog: Append source_address into records if needed --- plugins/in_syslog/syslog.c | 5 + plugins/in_syslog/syslog.h | 1 + plugins/in_syslog/syslog_conn.c | 5 +- plugins/in_syslog/syslog_prot.c | 175 +++++++++++++++++++++----------- plugins/in_syslog/syslog_prot.h | 7 +- tests/runtime/in_syslog.c | 146 ++++++++++++++++++++++++++ 6 files changed, 276 insertions(+), 63 deletions(-) diff --git a/plugins/in_syslog/syslog.c b/plugins/in_syslog/syslog.c index c9e2150bbc7..d478dfc3fb1 100644 --- a/plugins/in_syslog/syslog.c +++ b/plugins/in_syslog/syslog.c @@ -239,6 +239,11 @@ static struct flb_config_map config_map[] = { 0, FLB_TRUE, offsetof(struct flb_syslog, raw_message_key), "Key where the raw message will be preserved" }, + { + FLB_CONFIG_MAP_STR, "source_address_key", (char *) NULL, + 0, FLB_TRUE, offsetof(struct flb_syslog, source_address_key), + "Key where the source address will be injected" + }, /* EOF */ diff --git a/plugins/in_syslog/syslog.h b/plugins/in_syslog/syslog.h index 13b3a3f78d2..6da2fbd8322 100644 --- a/plugins/in_syslog/syslog.h +++ b/plugins/in_syslog/syslog.h @@ -65,6 +65,7 @@ struct flb_syslog { flb_sds_t parser_name; struct flb_parser *parser; flb_sds_t raw_message_key; + flb_sds_t source_address_key; int dgram_mode_flag; int collector_id; diff --git a/plugins/in_syslog/syslog_conn.c b/plugins/in_syslog/syslog_conn.c index ec3908fd3e8..8785c1e869b 100644 --- a/plugins/in_syslog/syslog_conn.c +++ b/plugins/in_syslog/syslog_conn.c @@ -128,14 +128,11 @@ int syslog_dgram_conn_event(void *data) struct flb_connection *connection; int bytes; struct syslog_conn *conn; - struct flb_syslog *ctx; connection = (struct flb_connection *) data; conn = connection->user_data; - ctx = conn->ctx; - bytes = flb_io_net_read(connection, (void *) &conn->buf_data[conn->buf_len], conn->buf_size - 1); @@ -144,7 +141,7 @@ int syslog_dgram_conn_event(void *data) conn->buf_data[bytes] = '\0'; conn->buf_len = bytes; - syslog_prot_process_udp(conn->buf_data, conn->buf_len, ctx); + syslog_prot_process_udp(conn); } else { flb_errno(); diff --git a/plugins/in_syslog/syslog_prot.c b/plugins/in_syslog/syslog_prot.c index 01c0e085a5a..1ec2c97cd59 100644 --- a/plugins/in_syslog/syslog_prot.c +++ b/plugins/in_syslog/syslog_prot.c @@ -20,9 +20,11 @@ #include #include #include +#include #include "syslog.h" #include "syslog_conn.h" +#include "syslog_prot.h" #include @@ -31,88 +33,127 @@ static inline void consume_bytes(char *buf, int bytes, int length) memmove(buf, buf + bytes, length - bytes); } -static int append_raw_message_to_record_data(char **result_buffer, - size_t *result_size, - flb_sds_t raw_message_key_name, - char *base_object_buffer, - size_t base_object_size, - char *raw_message_buffer, - size_t raw_message_size) +static int append_message_to_record_data(char **result_buffer, + size_t *result_size, + flb_sds_t message_key_name, + char *base_object_buffer, + size_t base_object_size, + char *message_buffer, + size_t message_size, + int message_type) { - int i; - int result; - size_t unpacker_offset; - msgpack_sbuffer mp_sbuf; - msgpack_packer mp_pck; - msgpack_unpacked unpacked_buffer; + int result = FLB_MAP_NOT_MODIFIED; + char *modified_data_buffer; + int modified_data_size; + msgpack_object_kv *new_map_entries[1]; + msgpack_object_kv message_entry; *result_buffer = NULL; *result_size = 0; + modified_data_buffer = NULL; - unpacker_offset = 0; - msgpack_unpacked_init(&unpacked_buffer); - result = msgpack_unpack_next(&unpacked_buffer, - base_object_buffer, - base_object_size, - &unpacker_offset); + if (message_key_name != NULL) { + new_map_entries[0] = &message_entry; - if (result != MSGPACK_UNPACK_SUCCESS) { - return -1; - } + message_entry.key.type = MSGPACK_OBJECT_STR; + message_entry.key.via.str.size = flb_sds_len(message_key_name); + message_entry.key.via.str.ptr = message_key_name; - if (unpacker_offset != base_object_size) { - msgpack_unpacked_destroy(&unpacked_buffer); - return -2; - } + if (message_type == MSGPACK_OBJECT_BIN) { + message_entry.val.type = MSGPACK_OBJECT_BIN; + message_entry.val.via.bin.size = message_size; + message_entry.val.via.bin.ptr = message_buffer; + } + else if (message_type == MSGPACK_OBJECT_STR) { + message_entry.val.type = MSGPACK_OBJECT_STR; + message_entry.val.via.str.size = message_size; + message_entry.val.via.str.ptr = message_buffer; + } + else { + result = FLB_MAP_EXPANSION_INVALID_VALUE_TYPE; + } - if (unpacked_buffer.data.type != MSGPACK_OBJECT_MAP) { - msgpack_unpacked_destroy(&unpacked_buffer); - return -3; + if (result == FLB_MAP_NOT_MODIFIED) { + result = flb_msgpack_expand_map(base_object_buffer, + base_object_size, + new_map_entries, 1, + &modified_data_buffer, + &modified_data_size); + if (result == 0) { + result = FLB_MAP_EXPAND_SUCCESS; + } + else { + result = FLB_MAP_EXPANSION_ERROR; + } + } } - msgpack_sbuffer_init(&mp_sbuf); - msgpack_packer_init(&mp_pck, &mp_sbuf, msgpack_sbuffer_write); - - msgpack_pack_map(&mp_pck, unpacked_buffer.data.via.map.size + 1); - - for (i = 0; i < unpacked_buffer.data.via.map.size; i++) { - msgpack_pack_object(&mp_pck, unpacked_buffer.data.via.map.ptr[i].key); - msgpack_pack_object(&mp_pck, unpacked_buffer.data.via.map.ptr[i].val); + if (result == FLB_MAP_EXPAND_SUCCESS) { + *result_buffer = modified_data_buffer; + *result_size = modified_data_size; } - msgpack_pack_str(&mp_pck, flb_sds_len(raw_message_key_name)); - msgpack_pack_str_body(&mp_pck, raw_message_key_name, flb_sds_len(raw_message_key_name)); - msgpack_pack_str(&mp_pck, raw_message_size); - msgpack_pack_str_body(&mp_pck, raw_message_buffer, raw_message_size); - - *result_buffer = mp_sbuf.data; - *result_size = mp_sbuf.size; - - msgpack_unpacked_destroy(&unpacked_buffer); return result; } static inline int pack_line(struct flb_syslog *ctx, struct flb_time *time, + struct flb_connection *connection, char *data, size_t data_size, char *raw_data, size_t raw_data_size) { char *modified_data_buffer; size_t modified_data_size; + char *appended_address_buffer; + size_t appended_address_size; int result; + char *source_address; + source_address = NULL; modified_data_buffer = NULL; + appended_address_buffer = NULL; if (ctx->raw_message_key != NULL) { - result = append_raw_message_to_record_data(&modified_data_buffer, - &modified_data_size, - ctx->raw_message_key, - data, - data_size, - raw_data, - raw_data_size); - - if (result != 0) { - flb_plg_debug(ctx->ins, "error appending raw message : %d", result); + result = append_message_to_record_data(&modified_data_buffer, + &modified_data_size, + ctx->raw_message_key, + data, + data_size, + raw_data, + raw_data_size, + MSGPACK_OBJECT_BIN); + + if (result == FLB_MAP_EXPANSION_ERROR) { + flb_plg_debug(ctx->ins, "error expanding raw message : %d", result); + } + } + + if (ctx->source_address_key != NULL) { + source_address = flb_connection_get_remote_address(connection); + if (source_address != NULL) { + if (modified_data_buffer != NULL) { + result = append_message_to_record_data(&appended_address_buffer, + &appended_address_size, + ctx->source_address_key, + modified_data_buffer, + modified_data_size, + source_address, + strlen(source_address), + MSGPACK_OBJECT_STR); + } + else { + result = append_message_to_record_data(&appended_address_buffer, + &appended_address_size, + ctx->source_address_key, + data, + data_size, + source_address, + strlen(source_address), + MSGPACK_OBJECT_STR); + } + + if (result == FLB_MAP_EXPANSION_ERROR) { + flb_plg_debug(ctx->ins, "error expanding source_address : %d", result); + } } } @@ -123,7 +164,11 @@ static inline int pack_line(struct flb_syslog *ctx, } if (result == FLB_EVENT_ENCODER_SUCCESS) { - if (modified_data_buffer != NULL) { + if (appended_address_buffer != NULL) { + result = flb_log_event_encoder_set_body_from_raw_msgpack( + ctx->log_encoder, appended_address_buffer, appended_address_size); + } + else if (modified_data_buffer != NULL) { result = flb_log_event_encoder_set_body_from_raw_msgpack( ctx->log_encoder, modified_data_buffer, modified_data_size); } @@ -154,6 +199,9 @@ static inline int pack_line(struct flb_syslog *ctx, if (modified_data_buffer != NULL) { flb_free(modified_data_buffer); } + if (appended_address_buffer != NULL) { + flb_free(appended_address_buffer); + } return result; } @@ -210,6 +258,7 @@ int syslog_prot_process(struct syslog_conn *conn) flb_time_get(&out_time); } pack_line(ctx, &out_time, + conn->connection, out_buf, out_size, p, len); flb_free(out_buf); @@ -235,12 +284,21 @@ int syslog_prot_process(struct syslog_conn *conn) return 0; } -int syslog_prot_process_udp(char *buf, size_t size, struct flb_syslog *ctx) +int syslog_prot_process_udp(struct syslog_conn *conn) { int ret; void *out_buf; size_t out_size; struct flb_time out_time = {0}; + char *buf; + size_t size; + struct flb_syslog *ctx; + struct flb_connection *connection; + + buf = conn->buf_data; + size = conn->buf_len; + ctx = conn->ctx; + connection = conn->connection; ret = flb_parser_do(ctx->parser, buf, size, &out_buf, &out_size, &out_time); @@ -249,6 +307,7 @@ int syslog_prot_process_udp(char *buf, size_t size, struct flb_syslog *ctx) flb_time_get(&out_time); } pack_line(ctx, &out_time, + connection, out_buf, out_size, buf, size); flb_free(out_buf); diff --git a/plugins/in_syslog/syslog_prot.h b/plugins/in_syslog/syslog_prot.h index 8ad4b20651d..cb5976b7bcf 100644 --- a/plugins/in_syslog/syslog_prot.h +++ b/plugins/in_syslog/syslog_prot.h @@ -24,7 +24,12 @@ #include "syslog.h" +#define FLB_MAP_EXPAND_SUCCESS 0 +#define FLB_MAP_NOT_MODIFIED -1 +#define FLB_MAP_EXPANSION_ERROR -2 +#define FLB_MAP_EXPANSION_INVALID_VALUE_TYPE -3 + int syslog_prot_process(struct syslog_conn *conn); -int syslog_prot_process_udp(char *buf, size_t size, struct flb_syslog *ctx); +int syslog_prot_process_udp(struct syslog_conn *conn); #endif diff --git a/tests/runtime/in_syslog.c b/tests/runtime/in_syslog.c index cf4da64cbe5..6935c7a3bd9 100644 --- a/tests/runtime/in_syslog.c +++ b/tests/runtime/in_syslog.c @@ -43,6 +43,18 @@ char *RFC5424_EXPECTED_STRS_1[] = {"\"pri\":\"34\"", "\"message\":\"'su root' fa "\"ident\":\"su\"" }; +char *RFC5424_EXPECTED_STRS_TCP[] = {"\"pri\":\"34\"", "\"message\":\"'su root' failed for lonvick on /dev/pts/8\"", + "\"host\":\"mymachine.example.com\"", "\"msgid\":\"ID47\"","\"time\":\"2003-10-11T22:14:15.003Z\"", + "\"ident\":\"su\"", + "\"source_host\":\"tcp://" +}; + +char *RFC5424_EXPECTED_STRS_UDP[] = {"\"pri\":\"34\"", "\"message\":\"'su root' failed for lonvick on /dev/pts/8\"", + "\"host\":\"mymachine.example.com\"", "\"msgid\":\"ID47\"","\"time\":\"2003-10-11T22:14:15.003Z\"", + "\"ident\":\"su\"", + "\"source_host\":\"udp://" +}; + char *RFC3164_EXPECTED_STRS_1[] = {"\"pri\":\"34\"", "\"message\":\"'su root' failed for lonvick on /dev/pts/8\"", "\"host\":\"mymachine\"", "\"time\":\"Oct 11 22:14:15\"", "\"ident\":\"su\"" }; @@ -425,6 +437,71 @@ void flb_test_syslog_tcp_port() test_ctx_destroy(ctx); } +void flb_test_syslog_tcp_source_address() +{ + struct flb_lib_out_cb cb_data; + struct test_ctx *ctx; + flb_sockfd_t fd; + int ret; + int num; + ssize_t w_size; + + struct str_list expected = { + .size = sizeof(RFC5424_EXPECTED_STRS_TCP)/sizeof(char*), + .lists = &RFC5424_EXPECTED_STRS_TCP[0], + }; + + char *buf = RFC5424_EXAMPLE_1; + size_t size = strlen(buf); + + clear_output_num(); + + cb_data.cb = cb_check_json_str_list; + cb_data.data = &expected; + + ctx = test_ctx_create(&cb_data); + if (!TEST_CHECK(ctx != NULL)) { + TEST_MSG("test_ctx_create failed"); + exit(EXIT_FAILURE); + } + + ret = flb_input_set(ctx->flb, ctx->i_ffd, + "mode", "tcp", + "source_address_key", "source_host", + "parser", PARSER_NAME_RFC5424, + NULL); + TEST_CHECK(ret == 0); + + /* Start the engine */ + ret = flb_start(ctx->flb); + TEST_CHECK(ret == 0); + + /* use default host/port */ + fd = connect_tcp(NULL, -1); + if (!TEST_CHECK(fd >= 0)) { + test_ctx_destroy(ctx); + exit(EXIT_FAILURE); + } + + w_size = send(fd, buf, size, 0); + if (!TEST_CHECK(w_size == size)) { + TEST_MSG("failed to send, errno=%d", errno); + flb_socket_close(fd); + test_ctx_destroy(ctx); + exit(EXIT_FAILURE); + } + + /* waiting to flush */ + flb_time_msleep(500); + + num = get_output_num(); + if (!TEST_CHECK(num > 0)) { + TEST_MSG("no outputs"); + } + + flb_socket_close(fd); + test_ctx_destroy(ctx); +} void flb_test_syslog_unknown_mode() { @@ -655,6 +732,73 @@ void flb_test_syslog_udp_port() test_ctx_destroy(ctx); } +void flb_test_syslog_udp_source_address() +{ + struct flb_lib_out_cb cb_data; + struct test_ctx *ctx; + struct sockaddr_in addr; + flb_sockfd_t fd; + int ret; + int num; + ssize_t w_size; + + struct str_list expected = { + .size = sizeof(RFC5424_EXPECTED_STRS_UDP)/sizeof(char*), + .lists = &RFC5424_EXPECTED_STRS_UDP[0], + }; + + char *buf = RFC5424_EXAMPLE_1; + size_t size = strlen(buf); + + clear_output_num(); + + cb_data.cb = cb_check_json_str_list; + cb_data.data = &expected; + + ctx = test_ctx_create(&cb_data); + if (!TEST_CHECK(ctx != NULL)) { + TEST_MSG("test_ctx_create failed"); + exit(EXIT_FAILURE); + } + + ret = flb_input_set(ctx->flb, ctx->i_ffd, + "mode", "udp", + "source_address_key", "source_host", + "parser", PARSER_NAME_RFC5424, + NULL); + TEST_CHECK(ret == 0); + + /* Start the engine */ + ret = flb_start(ctx->flb); + TEST_CHECK(ret == 0); + + /* use default host/port */ + fd = init_udp(NULL, -1, &addr); + if (!TEST_CHECK(fd >= 0)) { + test_ctx_destroy(ctx); + exit(EXIT_FAILURE); + } + + w_size = sendto(fd, buf, size, 0, (const struct sockaddr *)&addr, sizeof(addr)); + if (!TEST_CHECK(w_size == size)) { + TEST_MSG("failed to send, errno=%d", errno); + flb_socket_close(fd); + test_ctx_destroy(ctx); + exit(EXIT_FAILURE); + } + + /* waiting to flush */ + flb_time_msleep(500); + + num = get_output_num(); + if (!TEST_CHECK(num > 0)) { + TEST_MSG("no outputs"); + } + + flb_socket_close(fd); + test_ctx_destroy(ctx); +} + #ifdef FLB_HAVE_UNIX_SOCKET void flb_test_syslog_tcp_unix() { @@ -860,7 +1004,9 @@ TEST_LIST = { {"syslog_tcp", flb_test_syslog_tcp}, {"syslog_udp", flb_test_syslog_udp}, {"syslog_tcp_port", flb_test_syslog_tcp_port}, + {"syslog_tcp_source_address", flb_test_syslog_tcp_source_address}, {"syslog_udp_port", flb_test_syslog_udp_port}, + {"syslog_udp_source_address", flb_test_syslog_udp_source_address}, {"syslog_unknown_mode", flb_test_syslog_unknown_mode}, #ifdef FLB_HAVE_UNIX_SOCKET {"syslog_unix_perm", flb_test_syslog_unix_perm}, From 04cf2f2ca5f6223d3ce99e4c04010e5632a6d052 Mon Sep 17 00:00:00 2001 From: Takahiro Yamashita Date: Tue, 25 Jul 2023 10:44:40 +0900 Subject: [PATCH 153/315] bin: remove cleanup code from flb_signal_exit (#7735) - remove cleanup code from flb_signal_exit - release trace_props Signed-off-by: Takahiro Yamashita --- src/fluent-bit.c | 25 ++++--------------------- 1 file changed, 4 insertions(+), 21 deletions(-) diff --git a/src/fluent-bit.c b/src/fluent-bit.c index c44ccd1bdd7..774001f985a 100644 --- a/src/fluent-bit.c +++ b/src/fluent-bit.c @@ -524,8 +524,6 @@ static void flb_signal_exit(int signal) char s[] = "[engine] caught signal ("; time_t now; struct tm *cur; - flb_ctx_t *ctx = flb_context_get(); - struct flb_cf *cf_opts = flb_cf_context_get(); now = time(NULL); cur = localtime(&now); @@ -550,25 +548,6 @@ static void flb_signal_exit(int signal) flb_print_signal(SIGTERM); flb_print_signal(SIGSEGV); }; - - /* Signal handlers */ - /* SIGSEGV is not handled here to preserve stacktrace */ - switch (signal) { - case SIGINT: - case SIGTERM: -#ifndef FLB_SYSTEM_WINDOWS - case SIGQUIT: - case SIGHUP: -#endif - if (cf_opts != NULL) { - flb_cf_destroy(cf_opts); - } - flb_stop(ctx); - flb_destroy(ctx); - _exit(EXIT_SUCCESS); - default: - break; - } } static void flb_signal_handler(int signal) @@ -1359,6 +1338,10 @@ int flb_main(int argc, char **argv) if (trace_output) { flb_free(trace_output); } + if (trace_props != NULL) { + flb_kv_release(trace_props); + flb_free(trace_props); + } #endif flb_stop(ctx); From d8916aadeabedf25218ad1535888befb6f24423c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 26 Jul 2023 10:56:34 +0100 Subject: [PATCH 154/315] release: update to 2.1.9 (#7753) Signed-off-by: GitHub Co-authored-by: patrick-stephens --- CMakeLists.txt | 2 +- dockerfiles/Dockerfile | 2 +- fluent-bit-2.1.8.bb => fluent-bit-2.1.9.bb | 2 +- snap/snapcraft.yaml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) rename fluent-bit-2.1.8.bb => fluent-bit-2.1.9.bb (99%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 90f489c64b5..8d723fc0da5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,7 @@ set(CMAKE_POLICY_DEFAULT_CMP0069 NEW) # Fluent Bit Version set(FLB_VERSION_MAJOR 2) set(FLB_VERSION_MINOR 1) -set(FLB_VERSION_PATCH 8) +set(FLB_VERSION_PATCH 9) set(FLB_VERSION_STR "${FLB_VERSION_MAJOR}.${FLB_VERSION_MINOR}.${FLB_VERSION_PATCH}") set(CMAKE_POSITION_INDEPENDENT_CODE ON) diff --git a/dockerfiles/Dockerfile b/dockerfiles/Dockerfile index 8d583901296..64f3adac364 100644 --- a/dockerfiles/Dockerfile +++ b/dockerfiles/Dockerfile @@ -11,7 +11,7 @@ # docker buildx build --platform "linux/amd64,linux/arm64,linux/arm/v7" -f ./dockerfiles/Dockerfile.multiarch --build-arg FLB_TARBALL=https://github.com/fluent/fluent-bit/archive/v1.8.11.tar.gz ./dockerfiles/ # Set this to the current release version: it gets done so as part of the release. -ARG RELEASE_VERSION=2.1.8 +ARG RELEASE_VERSION=2.1.9 # For multi-arch builds - assumption is running on an AMD64 host FROM multiarch/qemu-user-static:x86_64-arm as qemu-arm32 diff --git a/fluent-bit-2.1.8.bb b/fluent-bit-2.1.9.bb similarity index 99% rename from fluent-bit-2.1.8.bb rename to fluent-bit-2.1.9.bb index 9096e336753..5b9f999f52c 100644 --- a/fluent-bit-2.1.8.bb +++ b/fluent-bit-2.1.9.bb @@ -16,7 +16,7 @@ LIC_FILES_CHKSUM = "file://LICENSE;md5=2ee41112a44fe7014dce33e26468ba93" SECTION = "net" PR = "r0" -PV = "2.1.8" +PV = "2.1.9" SRCREV = "v${PV}" SRC_URI = "git://github.com/fluent/fluent-bit.git;nobranch=1" diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 891d71e33f1..46d477a12c8 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -1,6 +1,6 @@ name: fluent-bit base: core18 -version: '2.1.8' +version: '2.1.9' summary: High performance logs and stream processor description: | Fluent Bit is a high performance log processor and stream processor for Linux. From 4b5f38eef2770a52bdc891919bd35ef889de6365 Mon Sep 17 00:00:00 2001 From: Pat Date: Fri, 28 Jul 2023 13:42:21 +0100 Subject: [PATCH 155/315] workflows: disable provenance for legacy format images (#7766) * workflows: disable provenance for legacy format images Signed-off-by: Patrick Stephens * workflows: disable provenance for legacy format images Signed-off-by: Patrick Stephens --------- Signed-off-by: Patrick Stephens --- .github/workflows/build-legacy-branch.yaml | 2 ++ .github/workflows/call-build-images.yaml | 8 ++++++-- .github/workflows/call-integration-image-build.yaml | 2 ++ .github/workflows/pr-compile-check.yaml | 1 + .github/workflows/pr-image-tests.yaml | 10 ++++++---- 5 files changed, 17 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build-legacy-branch.yaml b/.github/workflows/build-legacy-branch.yaml index 163752ce1b8..df1832f0859 100644 --- a/.github/workflows/build-legacy-branch.yaml +++ b/.github/workflows/build-legacy-branch.yaml @@ -86,6 +86,7 @@ jobs: context: . tags: ${{ steps.debug-meta.outputs.tags }} labels: ${{ steps.debug-meta.outputs.labels }} + provenance: false platforms: linux/amd64 push: true load: false @@ -108,6 +109,7 @@ jobs: tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} platforms: linux/${{ matrix.arch }} + provenance: false push: true load: false build-args: | diff --git a/.github/workflows/call-build-images.yaml b/.github/workflows/call-build-images.yaml index d72ff98c435..d231283e86b 100644 --- a/.github/workflows/call-build-images.yaml +++ b/.github/workflows/call-build-images.yaml @@ -122,6 +122,8 @@ jobs: labels: ${{ steps.meta.outputs.labels }} platforms: linux/amd64, linux/arm64, linux/arm/v7 target: production + # Must be disabled to provide legacy format images from the registry + provenance: false push: true load: false build-args: | @@ -146,6 +148,8 @@ jobs: tags: ${{ steps.debug-meta.outputs.tags }} labels: ${{ steps.debug-meta.outputs.labels }} platforms: linux/amd64, linux/arm64, linux/arm/v7 + # Must be disabled to provide legacy format images from the registry + provenance: false target: debug push: true load: false @@ -285,7 +289,7 @@ jobs: strategy: fail-fast: true matrix: - windows-base-version: + windows-base-version: - '2019' - '2022' permissions: @@ -308,7 +312,7 @@ jobs: run: | docker build -t ${{ inputs.registry }}/${{ inputs.image }}:windows-${{ matrix.windows-base-version }}-${{ inputs.version }} --build-arg FLB_NIGHTLY_BUILD=${{ inputs.unstable }} --build-arg WINDOWS_VERSION=ltsc${{ matrix.windows-base-version }} -f ./dockerfiles/Dockerfile.windows . docker push ${{ inputs.registry }}/${{ inputs.image }}:windows-${{ matrix.windows-base-version }}-${{ inputs.version }} - + # We cannot use this action as it requires privileged mode # uses: docker/build-push-action@v4 # with: diff --git a/.github/workflows/call-integration-image-build.yaml b/.github/workflows/call-integration-image-build.yaml index f109b31d2dc..c312f1919df 100644 --- a/.github/workflows/call-integration-image-build.yaml +++ b/.github/workflows/call-integration-image-build.yaml @@ -70,6 +70,7 @@ jobs: labels: ${{ steps.meta.outputs.labels }} platforms: linux/amd64 target: production + provenance: false push: true load: false @@ -103,6 +104,7 @@ jobs: context: . tags: ${{ steps.meta-debug.outputs.tags }} labels: ${{ steps.meta-debug.outputs.labels }} + provenance: false target: debug platforms: linux/amd64 push: true diff --git a/.github/workflows/pr-compile-check.yaml b/.github/workflows/pr-compile-check.yaml index b1b5dead0f3..b7ff250aef8 100644 --- a/.github/workflows/pr-compile-check.yaml +++ b/.github/workflows/pr-compile-check.yaml @@ -29,3 +29,4 @@ jobs: # No need to use after this so discard completely push: false load: false + provenance: false diff --git a/.github/workflows/pr-image-tests.yaml b/.github/workflows/pr-image-tests.yaml index b15f8e02cea..e3c869168fa 100644 --- a/.github/workflows/pr-image-tests.yaml +++ b/.github/workflows/pr-image-tests.yaml @@ -33,7 +33,7 @@ jobs: images: ${{ github.repository }}/pr-${{ github.event.pull_request.number }} tags: | type=sha - + - name: Build the multi-arch images id: build uses: docker/build-push-action@v4 @@ -42,6 +42,7 @@ jobs: context: . platforms: linux/amd64 target: production + provenance: false push: false load: true tags: ${{ steps.meta.outputs.tags }} @@ -52,7 +53,7 @@ jobs: run: | docker run --rm -t ${{ steps.meta.outputs.tags }} --help shell: bash - + - name: Build the debug multi-arch images uses: docker/build-push-action@v4 with: @@ -60,6 +61,7 @@ jobs: context: . platforms: linux/amd64 target: debug + provenance: false push: false load: false @@ -86,7 +88,7 @@ jobs: strategy: fail-fast: true matrix: - windows-base-version: + windows-base-version: # https://github.com/fluent/fluent-bit/blob/1d366594a889624ec3003819fe18588aac3f17cd/dockerfiles/Dockerfile.windows#L3 - '2019' - '2022' @@ -105,7 +107,7 @@ jobs: type=sha flavor: | suffix=-windows-${{ matrix.windows-base-version }} - + - name: Build the windows images id: build run: | From 16dbffe8066af93e84489b56fe0cdece8266ebba Mon Sep 17 00:00:00 2001 From: Pat Date: Fri, 28 Jul 2023 14:08:27 +0100 Subject: [PATCH 156/315] workflows: add extra push of arch-specfic images (#7767) Signed-off-by: Patrick Stephens --- .github/workflows/staging-release.yaml | 102 ++++++++++++++++++++----- 1 file changed, 85 insertions(+), 17 deletions(-) diff --git a/.github/workflows/staging-release.yaml b/.github/workflows/staging-release.yaml index 6cf33a68518..0eb0936561e 100644 --- a/.github/workflows/staging-release.yaml +++ b/.github/workflows/staging-release.yaml @@ -66,7 +66,7 @@ jobs: - name: Checkout repository uses: actions/checkout@v3 - + # Check we can download the AppVeyor build which confirms it matches the version to release as well as being a successful build - name: Get Appveyor binaries run: | @@ -90,13 +90,13 @@ jobs: sudo apt-get update sudo apt-get install -y jq shell: bash - + # Cope with 1.9 as well as 2.0 - uses: ./.github/actions/generate-package-build-matrix id: get-matrix with: ref: v${{ inputs.version }} - + # Now annotate with whether it is Yum or Apt based # 1. Take packages from the staging bucket @@ -109,7 +109,7 @@ jobs: name: S3 - update YUM packages bucket runs-on: ubuntu-22.04 # no createrepo on Ubuntu 20.04 environment: release - needs: + needs: - staging-release-version-check - staging-release-generate-package-matrix permissions: @@ -182,7 +182,7 @@ jobs: name: S3 - update APT packages bucket runs-on: ubuntu-latest environment: release - needs: + needs: - staging-release-version-check - staging-release-generate-package-matrix permissions: @@ -215,7 +215,7 @@ jobs: shell: bash env: DISTRO: ${{ matrix.distro }} - + - name: Import GPG key for signing id: import_gpg uses: crazy-max/ghaction-import-gpg@v5 @@ -260,7 +260,7 @@ jobs: name: Update Windows and macOS packages runs-on: ubuntu-22.04 environment: release - needs: + needs: - staging-release-version-check permissions: contents: none @@ -297,7 +297,7 @@ jobs: name: Update top-level bucket info runs-on: ubuntu-22.04 environment: release - needs: + needs: - staging-release-apt-packages - staging-release-yum-packages permissions: @@ -337,7 +337,7 @@ jobs: name: S3 - update source bucket runs-on: ubuntu-latest environment: release - needs: + needs: - staging-release-version-check permissions: contents: read @@ -352,7 +352,7 @@ jobs: - name: Sync packages from buckets on S3 run: | - mkdir -p release staging + mkdir -p release staging aws s3 sync "s3://${{ secrets.AWS_S3_BUCKET_RELEASE_SOURCES }}" release/ --no-progress aws s3 sync "s3://${{ secrets.AWS_S3_BUCKET_STAGING }}/source/" staging/ --no-progress env: @@ -382,7 +382,7 @@ jobs: VERSION: ${{ github.event.inputs.version }} MAJOR_VERSION: ${{ needs.staging-release-version-check.outputs.major-version }} shell: bash - + - name: Sync to bucket on S3 run: | aws s3 sync release/ "s3://${{ secrets.AWS_S3_BUCKET_RELEASE_SOURCES }}" --delete --follow-symlinks --no-progress @@ -476,9 +476,77 @@ jobs: TAG: ${{ matrix.tag }} shell: bash + # Part of resolution for: https://github.com/fluent/fluent-bit/issues/7748 + # More recent build-push-actions may mean legacy format is not preserved so we provide arch-specific tags just in case + staging-release-images-arch-specific-legacy-tags: + # TODO: remove next release once we are happy this all works, for now though do not block a release + continue-on-error: true + # + name: Release ${{ matrix.arch }} legacy format Linux container images + runs-on: ubuntu-latest + needs: + - staging-release-images + environment: release + strategy: + fail-fast: false + matrix: + arch: + - amd64 + - arm64 + - arm/v7 + permissions: + packages: write + env: + RELEASE_IMAGE_NAME: ${{ github.event.inputs.docker-image || secrets.DOCKERHUB_ORGANIZATION }} + RELEASE_TAG: ${{ github.event.inputs.version }} + steps: + + - name: Login to Docker Hub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Login to GitHub Container Registry + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Convert arch to tag + id: get-tag + run: | + TAG="${RELEASE_TAG}-${{ matrix.arch }}" + echo "Input value: $TAG" + TAG=${TAG/\//-} + echo "Using tag: $TAG" + echo "tag=$TAG" >> $GITHUB_OUTPUT + shell: bash + + - name: Pull release image + run: docker pull --platform='linux/${{ matrix.arch }}' "$RELEASE_IMAGE_NAME:$RELEASE_TAG" + shell: bash + + - name: Tag and push legacy format image to DockerHub + run: | + docker tag "$RELEASE_IMAGE_NAME:$RELEASE_TAG" docker.io/"$RELEASE_IMAGE_NAME:$TAG" + docker push docker.io/"$RELEASE_IMAGE_NAME:$TAG" + shell: bash + env: + TAG: ${{ steps.get-tag.outputs.tag }} + + - name: Tag and push legacy format image to Github Container Registry + run: | + docker tag "$RELEASE_IMAGE_NAME:$RELEASE_TAG" ghcr.io/"$RELEASE_IMAGE_NAME:$TAG" + docker push ghcr.io/"$RELEASE_IMAGE_NAME:$TAG" + shell: bash + env: + TAG: ${{ steps.get-tag.outputs.tag }} + staging-release-images-latest-tags: # Only update latest tags for 2.1 releases - if: startsWith(github.event.inputs.version, '2.1') + if: startsWith(github.event.inputs.version, '2.1') name: Release latest Linux container images runs-on: ubuntu-latest needs: @@ -599,7 +667,7 @@ jobs: permissions: write-all runs-on: ubuntu-latest environment: release - needs: + needs: - staging-release-images env: DH_RELEASE_IMAGE_NAME: docker.io/${{ github.event.inputs.docker-image || secrets.DOCKERHUB_ORGANIZATION }} @@ -634,7 +702,7 @@ jobs: "$GHCR_RELEASE_IMAGE_NAME:${{ github.event.inputs.version }}" \ "$GHCR_RELEASE_IMAGE_NAME:${{ github.event.inputs.version }}-debug" \ "$DH_RELEASE_IMAGE_NAME:${{ github.event.inputs.version }}" \ - "$DH_RELEASE_IMAGE_NAME:${{ github.event.inputs.version }}-debug" + "$DH_RELEASE_IMAGE_NAME:${{ github.event.inputs.version }}-debug" rm -f /tmp/my_cosign.key shell: bash env: @@ -670,7 +738,7 @@ jobs: steps: - name: Install cosign uses: sigstore/cosign-installer@v2 - + - name: Get public key and add to S3 bucket # Only run if we have a key defined if: ${{ env.COSIGN_PRIVATE_KEY }} @@ -765,7 +833,7 @@ jobs: staging-release-create-docs-pr: name: Create docs updates for new release - needs: + needs: - staging-release-images - staging-release-source-s3 permissions: @@ -832,7 +900,7 @@ jobs: staging-release-create-version-update-pr: name: Create version update PR for new release - needs: + needs: - staging-release-create-release permissions: contents: write From 6df51da55f2f96a3efc9fd5dd3bed525729fc699 Mon Sep 17 00:00:00 2001 From: Hiroshi Hatake Date: Fri, 28 Jul 2023 22:27:17 +0900 Subject: [PATCH 157/315] workflows: windows: Use vcpkg to install dependencies (#7764) Signed-off-by: Hiroshi Hatake --- .github/workflows/call-build-windows.yaml | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/.github/workflows/call-build-windows.yaml b/.github/workflows/call-build-windows.yaml index d15af8c9a4f..cc32eadf2e2 100644 --- a/.github/workflows/call-build-windows.yaml +++ b/.github/workflows/call-build-windows.yaml @@ -73,19 +73,16 @@ jobs: - name: "Windows 32bit" arch: x86 openssl_dir: C:\vcpkg\packages\openssl_x86-windows-static - chocolatey_opt: --x86 cmake_additional_opt: "" vcpkg_triplet: x86-windows-static - name: "Windows 64bit" arch: x64 - openssl_dir: C:\Program Files\OpenSSL-Win64 - chocolatey_opt: --x64 + openssl_dir: C:\vcpkg\packages\openssl_x64-windows-static cmake_additional_opt: "" vcpkg_triplet: x64-windows-static - name: "Windows 64bit (Arm64)" arch: amd64_arm64 openssl_dir: C:\vcpkg\packages\openssl_arm64-windows-static - chocolatey_opt: "" cmake_additional_opt: "-DCMAKE_SYSTEM_NAME=Windows -DCMAKE_SYSTEM_VERSION=10.0 -DCMAKE_SYSTEM_PROCESSOR=ARM64" vcpkg_triplet: arm64-windows-static permissions: @@ -110,19 +107,12 @@ jobs: WINFLEXBISON: https://github.com/lexxmark/winflexbison/releases/download/v2.5.22/win_flex_bison-2.5.22.zip shell: pwsh - - name: Get dependencies w/ chocolatey - if: ${{ matrix.config.arch == 'x64' }} - uses: crazy-max/ghaction-chocolatey@v2 - with: - args: install ${{ matrix.config.chocolatey_opt }} openssl -y - - name: Set up with Developer Command Prompt for Microsoft Visual C++ uses: ilammy/msvc-dev-cmd@v1 with: arch: ${{ matrix.config.arch }} - name: Build openssl with vcpkg - if: ${{ matrix.config.arch != 'x64' }} run: | C:\vcpkg\vcpkg install --recurse openssl --triplet ${{ matrix.config.vcpkg_triplet }} shell: cmd From ac136a9279f90bd2998262a18bd4e87e851e452a Mon Sep 17 00:00:00 2001 From: Hiroshi Hatake Date: Wed, 2 Aug 2023 04:30:02 +0900 Subject: [PATCH 158/315] workflows: windows: Implement cache mechanism for source packages of vcpkg (#7773) * workflows: windows: Introduce cache/restore mechanism for vcpkg sources Signed-off-by: Hiroshi Hatake * workflows: windows: Use OS specific caches Signed-off-by: Hiroshi Hatake * workflows: windows: Install gzip command to make caches Signed-off-by: Hiroshi Hatake * workflows: windows: Use date based caches Signed-off-by: Hiroshi Hatake --------- Signed-off-by: Hiroshi Hatake --- .github/workflows/call-build-windows.yaml | 30 +++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/.github/workflows/call-build-windows.yaml b/.github/workflows/call-build-windows.yaml index cc32eadf2e2..62ad4b81941 100644 --- a/.github/workflows/call-build-windows.yaml +++ b/.github/workflows/call-build-windows.yaml @@ -112,6 +112,27 @@ jobs: with: arch: ${{ matrix.config.arch }} + - name: Get gzip command w/ chocolatey + uses: crazy-max/ghaction-chocolatey@v2 + with: + args: install gzip -y + + # http://man7.org/linux/man-pages/man1/date.1.html + - name: Get Date + id: get-date + run: | + echo "date=$(/bin/date -u "+%Y%m%d")" >> $GITHUB_OUTPUT + shell: bash + + - name: Restore cached packages of vcpkg + id: cache-vcpkg-sources + uses: actions/cache/restore@v3 + with: + path: | + C:\vcpkg\packages + key: ${{ runner.os }}-${{ matrix.config.arch }}-vcpkg + enableCrossOsArchive: false + - name: Build openssl with vcpkg run: | C:\vcpkg\vcpkg install --recurse openssl --triplet ${{ matrix.config.vcpkg_triplet }} @@ -122,6 +143,15 @@ jobs: C:\vcpkg\vcpkg install --recurse libyaml --triplet ${{ matrix.config.vcpkg_triplet }} shell: cmd + - name: Save packages of vcpkg + id: save-vcpkg-sources + uses: actions/cache/save@v3 + with: + path: | + C:\vcpkg\packages + key: ${{ steps.cache-vcpkg-sources.outputs.cache-primary-key }}-${{ steps.get-date.outputs.date }} + enableCrossOsArchive: false + - name: Build Fluent Bit packages # If we are using 2.0.* or earlier we need to exclude the ARM64 build as the dependencies fail to compile. # Trying to do via an exclude for the job triggers linting errors. From c247be6752af4dd5ae72fe3e5286f4ced982d4b7 Mon Sep 17 00:00:00 2001 From: Hiroshi Hatake Date: Wed, 2 Aug 2023 18:23:18 +0900 Subject: [PATCH 159/315] workflow: windows: Make more rigid handling for caches (#7780) * workflows: windows: Use restore-keys element for surely restoring Signed-off-by: Hiroshi Hatake * workflows: windows: Use the cache primary key as-is Thie is because it has been already used Windows-$arch-vcpkg-%Y%m%d style. No needed to append additional %Y%m%d suffix. Signed-off-by: Hiroshi Hatake --------- Signed-off-by: Hiroshi Hatake --- .github/workflows/call-build-windows.yaml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/call-build-windows.yaml b/.github/workflows/call-build-windows.yaml index 62ad4b81941..3acb055feff 100644 --- a/.github/workflows/call-build-windows.yaml +++ b/.github/workflows/call-build-windows.yaml @@ -130,7 +130,9 @@ jobs: with: path: | C:\vcpkg\packages - key: ${{ runner.os }}-${{ matrix.config.arch }}-vcpkg + key: ${{ runner.os }}-${{ matrix.config.arch }}-vcpkg-${{ steps.get-date.outputs.date }} + restore-keys: | + ${{ runner.os }}-${{ matrix.config.arch }}-vcpkg- enableCrossOsArchive: false - name: Build openssl with vcpkg @@ -149,7 +151,7 @@ jobs: with: path: | C:\vcpkg\packages - key: ${{ steps.cache-vcpkg-sources.outputs.cache-primary-key }}-${{ steps.get-date.outputs.date }} + key: ${{ steps.cache-vcpkg-sources.outputs.cache-primary-key }} enableCrossOsArchive: false - name: Build Fluent Bit packages From 3b8f07955f109baa15f28fb36a14a4b70348f67e Mon Sep 17 00:00:00 2001 From: Chico Venancio Date: Tue, 1 Aug 2023 20:04:50 -0300 Subject: [PATCH 160/315] out_stackdriver: change default workers to 1 Fixes #7552 Signed-off-by: Chico Venancio --- plugins/out_stackdriver/stackdriver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/out_stackdriver/stackdriver.c b/plugins/out_stackdriver/stackdriver.c index f375417a81e..5c48a338b81 100644 --- a/plugins/out_stackdriver/stackdriver.c +++ b/plugins/out_stackdriver/stackdriver.c @@ -2856,7 +2856,7 @@ struct flb_output_plugin out_stackdriver_plugin = { .cb_init = cb_stackdriver_init, .cb_flush = cb_stackdriver_flush, .cb_exit = cb_stackdriver_exit, - .workers = 2, + .workers = 1, .config_map = config_map, /* Test */ From bf6b127737b58b77cc1ef91111a0c41256bd8cfd Mon Sep 17 00:00:00 2001 From: Celalettin Calis Date: Thu, 3 Aug 2023 17:11:55 +0300 Subject: [PATCH 161/315] ci: remove azure resources and tests (#7787) Signed-off-by: --get --- .../workflows/call-run-integration-test.yaml | 51 ------------------- .../workflows/master-integration-test.yaml | 4 -- .github/workflows/pr-integration-test.yaml | 4 -- .github/workflows/staging-test.yaml | 4 -- 4 files changed, 63 deletions(-) diff --git a/.github/workflows/call-run-integration-test.yaml b/.github/workflows/call-run-integration-test.yaml index 96a7317d61a..c65b000ef89 100644 --- a/.github/workflows/call-run-integration-test.yaml +++ b/.github/workflows/call-run-integration-test.yaml @@ -18,18 +18,6 @@ on: gcp-service-account-key: description: The GCP service account key to use. required: true - azure-client-id: - description: The Azure client ID to use. - required: true - azure-client-secret: - description: The Azure client secret to use. - required: true - azure-subscription-id: - description: The Azure subscription to use. - required: true - azure-tenant-id: - description: The Azure tenant ID to use. - required: true inputs: image_name: description: The image repository and name to use. @@ -53,19 +41,10 @@ jobs: permissions: packages: read outputs: - aks-cluster-name: ${{ steps.aks-cluster-name.outputs.stdout }} - aks-cluster-resource-group: ${{ steps.aks-cluster-resource-group.outputs.stdout }} aws-opensearch-endpoint: ${{ steps.aws-opensearch-endpoint.outputs.stdout }} gke-cluster-name: ${{ steps.gke-cluster-name.outputs.stdout }} gke-cluster-region: ${{ steps.gke-cluster-region.outputs.stdout }} gke-cluster-zone: ${{ steps.gke-cluster-zone.outputs.stdout }} - env: - # https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/guides/service_principal_client_secret - # Note these have to be set in the Terraform Cloud workspace as well - ARM_CLIENT_ID: ${{ secrets.azure-client-id }} - ARM_CLIENT_SECRET: ${{ secrets.azure-client-secret }} - ARM_SUBSCRIPTION_ID: ${{ secrets.azure-subscription-id }} - ARM_TENANT_ID: ${{ secrets.azure-tenant-id }} steps: - uses: actions/checkout@v3 with: @@ -91,11 +70,6 @@ jobs: sed -i -e "s|\$OPENSEARCH_AWS_SECRET_KEY|${{ secrets.opensearch_aws_secret_key }}|g" default.auto.tfvars sed -i -e "s|\$OPENSEARCH_ADMIN_PASSWORD|${{ secrets.opensearch_admin_password }}|g" default.auto.tfvars - sed -i -e "s|\$AZURE_CLIENT_ID|${{ secrets.azure-client-id }}|g" default.auto.tfvars - sed -i -e "s|\$AZURE_CLIENT_SECRET|${{ secrets.azure-client-secret }}|g" default.auto.tfvars - sed -i -e "s|\$AZURE_SUBSCRIPTION_ID|${{ secrets.azure-subscription-id }}|g" default.auto.tfvars - sed -i -e "s|\$AZURE_TENANT_ID|${{ secrets.azure-tenant-id }}|g" default.auto.tfvars - cat <> default.auto.tfvars gcp_sa_key = <<-EOF ${{ secrets.gcp-service-account-key }} @@ -184,16 +158,6 @@ jobs: working-directory: terraform shell: bash - - id: aks-cluster-name - run: terraform output -no-color -raw aks_cluster_name - working-directory: terraform - shell: bash - - - id: aks-cluster-resource-group - run: terraform output -no-color -raw aks_resource_group - working-directory: terraform - shell: bash - call-run-integration-kind: name: Run integration tests on KIND needs: @@ -266,7 +230,6 @@ jobs: fail-fast: false matrix: cloud: - - aks - gke env: USE_GKE_GCLOUD_AUTH_PLUGIN: true @@ -306,20 +269,6 @@ jobs: cluster_name: ${{ needs.call-run-terraform-setup.outputs.gke-cluster-name }} location: ${{ needs.call-run-terraform-setup.outputs.gke-cluster-zone }} - - name: Get the AKS Kubeconfig - if: matrix.cloud == 'aks' - run: | - az login --username="$ARM_CLIENT_ID" --password="$ARM_CLIENT_SECRET" --tenant="$ARM_TENANT_ID" --service-principal - az aks get-credentials --name "$AKS_CLUSTER_NAME" --resource-group "$AKS_CLUSTER_RG" --admin - shell: bash - env: - AKS_CLUSTER_NAME: ${{ needs.call-run-terraform-setup.outputs.aks-cluster-name }} - AKS_CLUSTER_RG: ${{ needs.call-run-terraform-setup.outputs.aks-cluster-resource-group }} - ARM_CLIENT_ID: ${{ secrets.azure-client-id }} - ARM_CLIENT_SECRET: ${{ secrets.azure-client-secret }} - ARM_SUBSCRIPTION_ID: ${{ secrets.azure-subscription-id }} - ARM_TENANT_ID: ${{ secrets.azure-tenant-id }} - - name: Check Kubeconfig set up run: | kubectl cluster-info diff --git a/.github/workflows/master-integration-test.yaml b/.github/workflows/master-integration-test.yaml index a879c451e1b..85c321b8250 100644 --- a/.github/workflows/master-integration-test.yaml +++ b/.github/workflows/master-integration-test.yaml @@ -30,8 +30,4 @@ jobs: opensearch_aws_secret_key: ${{ secrets.OPENSEARCH_AWS_SECRET_KEY }} opensearch_admin_password: ${{ secrets.OPENSEARCH_ADMIN_PASSWORD }} terraform_api_token: ${{ secrets.TF_API_TOKEN }} - azure-client-id: ${{ secrets.AZURE_CLIENT_ID }} - azure-client-secret: ${{ secrets.AZURE_CLIENT_SECRET }} - azure-subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} - azure-tenant-id: ${{ secrets.AZURE_TENANT_ID }} gcp-service-account-key: ${{ secrets.GCP_SA_KEY }} diff --git a/.github/workflows/pr-integration-test.yaml b/.github/workflows/pr-integration-test.yaml index d98fd7d781e..2b18b1c67b1 100644 --- a/.github/workflows/pr-integration-test.yaml +++ b/.github/workflows/pr-integration-test.yaml @@ -52,10 +52,6 @@ jobs: opensearch_aws_secret_key: ${{ secrets.OPENSEARCH_AWS_SECRET_KEY }} opensearch_admin_password: ${{ secrets.OPENSEARCH_ADMIN_PASSWORD }} terraform_api_token: ${{ secrets.TF_API_TOKEN }} - azure-client-id: ${{ secrets.AZURE_CLIENT_ID }} - azure-client-secret: ${{ secrets.AZURE_CLIENT_SECRET }} - azure-subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} - azure-tenant-id: ${{ secrets.AZURE_TENANT_ID }} gcp-service-account-key: ${{ secrets.GCP_SA_KEY }} pr-integration-test-run-integration-post-label: diff --git a/.github/workflows/staging-test.yaml b/.github/workflows/staging-test.yaml index e78936e662f..e7a2d3caa1c 100644 --- a/.github/workflows/staging-test.yaml +++ b/.github/workflows/staging-test.yaml @@ -42,10 +42,6 @@ jobs: opensearch_aws_secret_key: ${{ secrets.OPENSEARCH_AWS_SECRET_KEY }} opensearch_admin_password: ${{ secrets.OPENSEARCH_ADMIN_PASSWORD }} terraform_api_token: ${{ secrets.TF_API_TOKEN }} - azure-client-id: ${{ secrets.AZURE_CLIENT_ID }} - azure-client-secret: ${{ secrets.AZURE_CLIENT_SECRET }} - azure-subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} - azure-tenant-id: ${{ secrets.AZURE_TENANT_ID }} gcp-service-account-key: ${{ secrets.GCP_SA_KEY }} staging-test-packages: From 0674883055f50044f416aaa756d7b184d0ba2b48 Mon Sep 17 00:00:00 2001 From: Celalettin Calis Date: Fri, 4 Aug 2023 16:24:25 +0300 Subject: [PATCH 162/315] ci: add codeowner celalettin1286 (#7794) Signed-off-by: Celalettin Calis --- CODEOWNERS | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index 469ffcc7e11..98504a4f78c 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -13,17 +13,17 @@ # Build System & Portability # -------------------------- -/CMakeLists.txt @fujimotos @niedbalski @patrick-stephens -/cmake/ @fujimotos @niedbalski @patrick-stephens +/CMakeLists.txt @fujimotos @niedbalski @patrick-stephens @celalettin1286 +/cmake/ @fujimotos @niedbalski @patrick-stephens @celalettin1286 # CI # ------------------------- -/.github/ @niedbalski @patrick-stephens -/appveyor.yml @niedbalski @patrick-stephens -/dockerfiles/ @niedbalski @patrick-stephens -/packaging/ @niedbalski @patrick-stephens -/codebase-structure.svg @niedbalski @patrick-stephens -/install.sh @niedbalski @patrick-stephens +/.github/ @niedbalski @patrick-stephens @celalettin1286 +/appveyor.yml @niedbalski @patrick-stephens @celalettin1286 +/dockerfiles/ @niedbalski @patrick-stephens @celalettin1286 +/packaging/ @niedbalski @patrick-stephens @celalettin1286 +/codebase-structure.svg @niedbalski @patrick-stephens @celalettin1286 +/install.sh @niedbalski @patrick-stephens @celalettin1286 # Core: Signv4 # ------------ From 6a9f9ccd6ad7488305f500216040834c7197ddbe Mon Sep 17 00:00:00 2001 From: leonardo-albertovich Date: Fri, 4 Aug 2023 16:18:36 +0200 Subject: [PATCH 163/315] in_prometheus_scrape: added authorization support (#7785) Signed-off-by: Leonardo Alminana --- plugins/in_prometheus_scrape/prom_scrape.c | 25 ++++++++++++++++++++++ plugins/in_prometheus_scrape/prom_scrape.h | 7 ++++++ 2 files changed, 32 insertions(+) diff --git a/plugins/in_prometheus_scrape/prom_scrape.c b/plugins/in_prometheus_scrape/prom_scrape.c index 21b8eb5b40c..68d4540bca9 100644 --- a/plugins/in_prometheus_scrape/prom_scrape.c +++ b/plugins/in_prometheus_scrape/prom_scrape.c @@ -100,6 +100,13 @@ static int collect_metrics(struct prom_scrape *ctx) flb_http_buffer_size(c, ctx->buffer_max_size); + /* Auth headers */ + if (ctx->http_user && ctx->http_passwd) { /* Basic */ + flb_http_basic_auth(c, ctx->http_user, ctx->http_passwd); + } else if (ctx->bearer_token) { /* Bearer token */ + flb_http_bearer_auth(c, ctx->bearer_token); + } + ret = flb_http_do(c, &b_sent); if (ret != 0) { flb_plg_error(ctx->ins, "http do error"); @@ -218,6 +225,24 @@ static struct flb_config_map config_map[] = { "Set the metrics URI endpoint, it must start with a forward slash." }, + { + FLB_CONFIG_MAP_STR, "http_user", NULL, + 0, FLB_TRUE, offsetof(struct prom_scrape, http_user), + "Set HTTP auth user" + }, + + { + FLB_CONFIG_MAP_STR, "http_passwd", "", + 0, FLB_TRUE, offsetof(struct prom_scrape, http_passwd), + "Set HTTP auth password" + }, + + { + FLB_CONFIG_MAP_STR, "bearer_token", NULL, + 0, FLB_TRUE, offsetof(struct prom_scrape, bearer_token), + "Set bearer token auth" + }, + /* EOF */ {0} }; diff --git a/plugins/in_prometheus_scrape/prom_scrape.h b/plugins/in_prometheus_scrape/prom_scrape.h index 86161b5d040..9510abfef5d 100644 --- a/plugins/in_prometheus_scrape/prom_scrape.h +++ b/plugins/in_prometheus_scrape/prom_scrape.h @@ -33,6 +33,13 @@ struct prom_scrape struct flb_upstream *upstream; struct flb_input_instance *ins; /* input plugin instance */ size_t buffer_max_size; /* Maximum buffer size */ + + /* HTTP Auth */ + flb_sds_t http_user; + flb_sds_t http_passwd; + + /* Bearer Token Auth */ + flb_sds_t bearer_token; }; #endif From 7c981b5bafc1c73976f39dd87c4ba74273d0a01b Mon Sep 17 00:00:00 2001 From: DavidKorczynski Date: Tue, 8 Aug 2023 20:41:40 +0100 Subject: [PATCH 164/315] config_format: fix possible heap overflow (#7768) The return value of `strchr` is not checked for failure. If it's failure then `tmp` will be `0` in the `(tmp-p)` calculation, causing `xlen` to be `p`. `xlen` is later used for copying memory by way of `memcpy` in string creation using `flb_sds_create_len`. This fixes it. Signed-off-by: David Korczynski --- src/config_format/flb_config_format.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/config_format/flb_config_format.c b/src/config_format/flb_config_format.c index a62bda96ab7..af4f56b9d27 100644 --- a/src/config_format/flb_config_format.c +++ b/src/config_format/flb_config_format.c @@ -420,6 +420,9 @@ struct flb_kv *flb_cf_meta_property_add(struct flb_cf *cf, char *meta, int len) p = meta; tmp = strchr(p, ' '); + if (tmp == NULL) { + return NULL; + } xlen = (tmp - p); /* create k/v pair */ From 01cdaddf341b8747d70b7ebc817c781ce6507ea7 Mon Sep 17 00:00:00 2001 From: David Korczynski Date: Mon, 24 Jul 2023 07:12:33 -0700 Subject: [PATCH 165/315] tests: fuzzers: utils_fuzzer: extend Extnd the `utils_fuzzer` with an additional string split operation. Signed-off-by: David Korczynski --- tests/internal/fuzzers/utils_fuzzer.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/internal/fuzzers/utils_fuzzer.c b/tests/internal/fuzzers/utils_fuzzer.c index 420a4074404..2352adf3e43 100644 --- a/tests/internal/fuzzers/utils_fuzzer.c +++ b/tests/internal/fuzzers/utils_fuzzer.c @@ -70,6 +70,10 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) if (list != NULL) { flb_utils_split_free(list); } + struct mk_list *list2 = flb_utils_split_quoted(null_terminated, 'A', 3); + if (list2 != NULL) { + flb_utils_split_free(list2); + } if (flb_utils_url_split(null_terminated, &prot, &host, &port, &uri) == 0) { flb_free(prot); From 6f54e3d7d64bd6a03b5affea609bd285e3d7c1c2 Mon Sep 17 00:00:00 2001 From: David Korczynski Date: Mon, 24 Jul 2023 07:16:51 -0700 Subject: [PATCH 166/315] tests: internal: fuzzers: cmetrics_fuzzer: extend Extend cmetrics_fuzzer so it reaches prometheus decoding logic as well. Signed-off-by: David Korczynski --- tests/internal/fuzzers/cmetrics_decode_fuzz.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/tests/internal/fuzzers/cmetrics_decode_fuzz.c b/tests/internal/fuzzers/cmetrics_decode_fuzz.c index 7ddd1ab2197..1d1098c0f19 100644 --- a/tests/internal/fuzzers/cmetrics_decode_fuzz.c +++ b/tests/internal/fuzzers/cmetrics_decode_fuzz.c @@ -18,6 +18,7 @@ */ #include +#include int @@ -34,7 +35,7 @@ LLVMFuzzerTestOneInput(const uint8_t * data, size_t size) return 0; } - decider = data[0] % 2; + decider = data[0] % 3; /* Adjust data pointer since the first byte is used */ data += 1; @@ -54,5 +55,15 @@ LLVMFuzzerTestOneInput(const uint8_t * data, size_t size) cmt_destroy(cmt); } } + else if (decider == 2) { + if (size == 0) { + return 0; + } + struct cmt_decode_prometheus_parse_opts opts; + result = cmt_decode_prometheus_create(&cmt, data, size, &opts); + if (result == CMT_DECODE_PROMETHEUS_SUCCESS) { + cmt_decode_prometheus_destroy(cmt); + } + } return 0; } From 197ff40c942ac95835dfb774e7fd38a487ef6b33 Mon Sep 17 00:00:00 2001 From: David Korczynski Date: Mon, 24 Jul 2023 07:58:53 -0700 Subject: [PATCH 167/315] tests: internal: fuzzers: add input fuzzer Add fuzzer dedicated to input chunk fuzzing. Although much of the logic is covered already, it would be nice to have something more dedicated. Signed-off-by: David Korczynski --- tests/internal/fuzzers/CMakeLists.txt | 1 + tests/internal/fuzzers/input_fuzzer.c | 164 ++++++++++++++++++++++++++ 2 files changed, 165 insertions(+) create mode 100644 tests/internal/fuzzers/input_fuzzer.c diff --git a/tests/internal/fuzzers/CMakeLists.txt b/tests/internal/fuzzers/CMakeLists.txt index 0ace2db9898..e61ff698277 100644 --- a/tests/internal/fuzzers/CMakeLists.txt +++ b/tests/internal/fuzzers/CMakeLists.txt @@ -7,6 +7,7 @@ set(UNIT_TESTS_FILES config_fuzzer.c config_random_fuzzer.c ctrace_fuzzer.c + input_fuzzer.c signv4_fuzzer.c flb_json_fuzzer.c filter_stdout_fuzzer.c diff --git a/tests/internal/fuzzers/input_fuzzer.c b/tests/internal/fuzzers/input_fuzzer.c new file mode 100644 index 00000000000..57458d36f78 --- /dev/null +++ b/tests/internal/fuzzers/input_fuzzer.c @@ -0,0 +1,164 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "chunkio/chunkio.h" +#include "flb_fuzz_header.h" + + +const char *input_chunk_property_keywords[] = { + "log_suppress_interval", + "routable", + "alias", + "mem_buf_limit", + "listen", + "log_level", + "host", + "port", + "ipv6", + "net.", + "tls", + "tls.verify", + "tls.debug", + "tls.ca_path", + "tls.key_file", + "tls.vhost", + "tls.ca_file", + "tls.crt_file", + "tls.key_passwd", + "threaded", + "storage.type", +}; + +int LLVMFuzzerTestOneInput(const uint8_t *data3, size_t size3) +{ + int i; + int ret; + int in_ffd; + int out_ffd; + + flb_ctx_t *ctx; + size_t total_bytes; + struct flb_input_instance *i_ins; + struct mk_list *tmp; + struct mk_list *head; + struct flb_input_chunk *ic; + struct flb_task *task; + + if (size3 < 60) { + return 0; + } + /* Set fuzzer-malloc chance of failure */ + flb_malloc_p = 0; + flb_malloc_mod = 25000; + char *input_buffer1 = get_null_terminated(30, &data3, &size3); + if (input_buffer1 == NULL) { + return 0; + } + size_t input_buffer1_len = strlen(input_buffer1); + + char *input_buffer2 = get_null_terminated(10, &data3, &size3); + if (input_buffer2 == NULL) { + return 0; + } + size_t input_buffer_len2 = strlen(input_buffer2); + + char *input_buffer3 = get_null_terminated(10, &data3, &size3); + if (input_buffer3 == NULL) { + return 0; + } + size_t input_buffer_len3 = strlen(input_buffer3); + /* Create context, flush every second (some checks omitted here) */ + ctx = flb_create(); + + /* create chunks in /tmp folder */ + ret = flb_service_set(ctx, + "flush", "2", "grace", "1", + "storage.path", "/tmp/input-chunk-test/", + "Log_Level", "error", + NULL); + if (ret != 0) { + flb_free(input_buffer1); + flb_free(input_buffer2); + flb_free(input_buffer3); + return 0; + } + + /* Lib input mode */ + in_ffd = flb_input(ctx, (char *) "lib", NULL); + ret = flb_input_set(ctx, in_ffd, + "tag", "test", + "storage.type", "filesystem", + NULL); + if (ret != 0) { + flb_free(input_buffer1); + flb_free(input_buffer2); + flb_free(input_buffer3); + return 0; + } + + /* an invalid output destination */ + out_ffd = flb_output(ctx, (char *) "http", NULL); + flb_output_set(ctx, out_ffd, + "match", "test", + "Host", "127.0.0.1", + "Port", "1", + "storage.total_limit_size", "1K", + NULL); + + /* Start */ + ret = flb_start(ctx); + if (ret != 0) { + flb_free(input_buffer1); + flb_free(input_buffer2); + flb_free(input_buffer3); + return 0; + } + + i_ins = mk_list_entry_first(&ctx->config->inputs, + struct flb_input_instance, + _head); + + /* main fuzzing logic */ + flb_input_set_property(i_ins, input_buffer2, input_buffer3); + for (int i = 0; i < sizeof(input_chunk_property_keywords)/sizeof(char*); i++) { + flb_input_set_property(i_ins, + input_chunk_property_keywords[i], + input_buffer3); + } + + /* Ingest fuzz data sample */ + for (i = 0; i < 2; ++i) { + flb_lib_push(ctx, in_ffd, (char *) input_buffer1, input_buffer1_len); + sleep(1); + total_bytes = flb_input_chunk_total_size(i_ins); + ret = total_bytes > 1000 ? -1 : 0; + } + + /* FORCE clean up test tasks */ + mk_list_foreach_safe(head, tmp, &i_ins->tasks) { + task = mk_list_entry(head, struct flb_task, _head); + flb_info("[task] cleanup test task"); + flb_task_destroy(task, FLB_TRUE); + } + + /* clean up test chunks */ + mk_list_foreach_safe(head, tmp, &i_ins->chunks) { + ic = mk_list_entry(head, struct flb_input_chunk, _head); + flb_input_chunk_destroy(ic, FLB_TRUE); + } + flb_free(input_buffer1); + flb_free(input_buffer2); + flb_free(input_buffer3); + + flb_time_msleep(200); + flb_stop(ctx); + flb_destroy(ctx); +} From cc81df28b640e3471b6d1aa671bf9cb39ac3ebf8 Mon Sep 17 00:00:00 2001 From: Phillip Whelan Date: Thu, 10 Aug 2023 19:48:42 -0400 Subject: [PATCH 168/315] utils: check existence of machine-id files before reading them. (#7806) Signed-off-by: Phillip Whelan --- src/flb_utils.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/flb_utils.c b/src/flb_utils.c index 93e04556390..ac876175a56 100644 --- a/src/flb_utils.c +++ b/src/flb_utils.c @@ -1356,19 +1356,23 @@ int flb_utils_get_machine_id(char **out_id, size_t *out_size) char *dbus_etc = "/etc/machine-id"; /* dbus */ - ret = machine_id_read_and_sanitize(dbus_var, &id, &bytes); - if (ret == 0) { - *out_id = id; - *out_size = bytes; - return 0; + if (access(dbus_var, F_OK) == 0) { /* check if the file exists first */ + ret = machine_id_read_and_sanitize(dbus_var, &id, &bytes); + if (ret == 0) { + *out_id = id; + *out_size = bytes; + return 0; + } } /* etc */ - ret = machine_id_read_and_sanitize(dbus_etc, &id, &bytes); - if (ret == 0) { - *out_id = id; - *out_size = bytes; - return 0; + if (access(dbus_etc, F_OK) == 0) { /* check if the file exists first */ + ret = machine_id_read_and_sanitize(dbus_etc, &id, &bytes); + if (ret == 0) { + *out_id = id; + *out_size = bytes; + return 0; + } } #elif defined(__FreeBSD__) || defined(__NetBSD__) || \ defined(__OpenBSD__) || defined(__DragonFly__) From 757e03271c40741a680c59345ade4c5e36416e2f Mon Sep 17 00:00:00 2001 From: Hiroshi Hatake Date: Mon, 31 Jul 2023 17:46:38 +0900 Subject: [PATCH 169/315] aws: Allocate S3_KEY_SIZE +1 instead of S3_KEY_SIZE for allocating buffer for s3 key This is because macOS's strlen complains buffer overflow due to exceeding length of allocated buffers. To prevent this issue, we need to allocate an adittional +1 length of char type of buffer. Signed-off-by: Hiroshi Hatake --- src/aws/flb_aws_util.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/aws/flb_aws_util.c b/src/aws/flb_aws_util.c index 75efe1b0df1..533bba7eb4d 100644 --- a/src/aws/flb_aws_util.c +++ b/src/aws/flb_aws_util.c @@ -908,8 +908,8 @@ flb_sds_t flb_get_s3_key(const char *format, time_t time, const char *tag, flb_sds_destroy(tmp); tmp = NULL; - /* A string no longer than S3_KEY_SIZE is created to store the formatted timestamp. */ - key = flb_calloc(1, S3_KEY_SIZE * sizeof(char)); + /* A string no longer than S3_KEY_SIZE + 1 is created to store the formatted timestamp. */ + key = flb_calloc(1, (S3_KEY_SIZE + 1) * sizeof(char)); if (!key) { goto error; } From a88708cd5e56eaf7327909ee3f9c163c09948300 Mon Sep 17 00:00:00 2001 From: Takahiro Yamashita Date: Sat, 5 Aug 2023 11:45:56 +0900 Subject: [PATCH 170/315] out_kinesis_firefose: fix typo Signed-off-by: Takahiro Yamashita --- plugins/out_kinesis_firehose/firehose_api.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/out_kinesis_firehose/firehose_api.c b/plugins/out_kinesis_firehose/firehose_api.c index 9e3c1152c76..5c2f0c2f9b0 100644 --- a/plugins/out_kinesis_firehose/firehose_api.c +++ b/plugins/out_kinesis_firehose/firehose_api.c @@ -741,7 +741,7 @@ static int process_api_response(struct flb_firehose *ctx, (strncmp(response_val.via.str.ptr, ERR_CODE_SERVICE_UNAVAILABLE, 27) == 0)) { throughput_exceeded = FLB_TRUE; - flb_plg_error(ctx->ins, "Thoughput limits may have been exceeded, %s", + flb_plg_error(ctx->ins, "Throughput limits may have been exceeded, %s", ctx->delivery_stream); } flb_plg_debug(ctx->ins, "Record %i failed with err_code=%.*s", From 8f4300f79aef0b2454247995795abb76fa9cdf18 Mon Sep 17 00:00:00 2001 From: Takahiro Yamashita Date: Sat, 5 Aug 2023 11:46:09 +0900 Subject: [PATCH 171/315] out_kinesis_streams: fix typo Signed-off-by: Takahiro Yamashita --- plugins/out_kinesis_streams/kinesis_api.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/out_kinesis_streams/kinesis_api.c b/plugins/out_kinesis_streams/kinesis_api.c index 95c500b5b68..664e4fe4dad 100644 --- a/plugins/out_kinesis_streams/kinesis_api.c +++ b/plugins/out_kinesis_streams/kinesis_api.c @@ -771,7 +771,7 @@ static int process_api_response(struct flb_kinesis *ctx, (strncmp(response_val.via.str.ptr, ERR_CODE_EXCEEDED_THROUGHPUT, 38) == 0)) { throughput_exceeded = FLB_TRUE; - flb_plg_error(ctx->ins, "Thoughput limits may have been exceeded, %s", + flb_plg_error(ctx->ins, "Throughput limits may have been exceeded, %s", ctx->stream_name); } flb_plg_debug(ctx->ins, "Record %i failed with err_code=%.*s", From 59ed0dca0cb7bbcca3516da01bc42813ec88ccdb Mon Sep 17 00:00:00 2001 From: Daniel Lenar Date: Wed, 9 Aug 2023 00:52:12 -0500 Subject: [PATCH 172/315] input: send resume signal to the input thread event loop if plugin is threaded Signed-off-by: Daniel Lenar --- include/fluent-bit/flb_input_thread.h | 1 + src/flb_input.c | 8 ++++++- src/flb_input_chunk.c | 4 ++-- src/flb_input_thread.c | 30 +++++++++++++++++++++++++++ 4 files changed, 40 insertions(+), 3 deletions(-) diff --git a/include/fluent-bit/flb_input_thread.h b/include/fluent-bit/flb_input_thread.h index ffce7bcc4b6..abc16123106 100644 --- a/include/fluent-bit/flb_input_thread.h +++ b/include/fluent-bit/flb_input_thread.h @@ -93,6 +93,7 @@ int flb_input_thread_instance_init(struct flb_config *config, int flb_input_thread_instance_pre_run(struct flb_config *config, struct flb_input_instance *ins); int flb_input_thread_instance_pause(struct flb_input_instance *ins); +int flb_input_thread_instance_resume(struct flb_input_instance *ins); int flb_input_thread_instance_exit(struct flb_input_instance *ins); int flb_input_thread_collectors_signal_start(struct flb_input_instance *ins); diff --git a/src/flb_input.c b/src/flb_input.c index 94aa52cbc43..1c4faad4d3f 100644 --- a/src/flb_input.c +++ b/src/flb_input.c @@ -1695,7 +1695,13 @@ int flb_input_pause(struct flb_input_instance *ins) int flb_input_resume(struct flb_input_instance *ins) { if (ins->p->cb_resume) { - ins->p->cb_resume(ins->context, ins->config); + if (flb_input_is_threaded(ins)) { + /* signal the thread event loop about the 'resume' operation */ + flb_input_thread_instance_resume(ins); + } + else { + ins->p->cb_resume(ins->context, ins->config); + } } return 0; diff --git a/src/flb_input_chunk.c b/src/flb_input_chunk.c index 35bfde75ba7..284a7f708e1 100644 --- a/src/flb_input_chunk.c +++ b/src/flb_input_chunk.c @@ -1185,7 +1185,7 @@ size_t flb_input_chunk_set_limits(struct flb_input_instance *in) in->mem_buf_status == FLB_INPUT_PAUSED) { in->mem_buf_status = FLB_INPUT_RUNNING; if (in->p->cb_resume) { - in->p->cb_resume(in->context, in->config); + flb_input_resume(in); flb_info("[input] %s resume (mem buf overlimit)", in->name); } @@ -1196,7 +1196,7 @@ size_t flb_input_chunk_set_limits(struct flb_input_instance *in) in->storage_buf_status == FLB_INPUT_PAUSED) { in->storage_buf_status = FLB_INPUT_RUNNING; if (in->p->cb_resume) { - in->p->cb_resume(in->context, in->config); + flb_input_resume(in); flb_info("[input] %s resume (storage buf overlimit %zu/%zu)", in->name, ((struct flb_storage_input *)in->storage)->cio->total_chunks_up, diff --git a/src/flb_input_thread.c b/src/flb_input_thread.c index bb0f3016517..bf073296de2 100644 --- a/src/flb_input_thread.c +++ b/src/flb_input_thread.c @@ -78,6 +78,11 @@ static inline int handle_input_event(flb_pipefd_t fd, struct flb_input_instance ins->p->cb_pause(ins->context, ins->config); } } + else if (operation == FLB_INPUT_THREAD_RESUME) { + if (ins->p->cb_resume) { + ins->p->cb_resume(ins->context, ins->config); + } + } else if (operation == FLB_INPUT_THREAD_EXIT) { return FLB_INPUT_THREAD_EXIT; } @@ -482,6 +487,31 @@ int flb_input_thread_instance_pause(struct flb_input_instance *ins) return 0; } +/* + * Signal the thread event loop to resume the running plugin instance. This function + * must be called only from the main thread/pipeline. + */ +int flb_input_thread_instance_resume(struct flb_input_instance *ins) +{ + int ret; + uint64_t val; + struct flb_input_thread_instance *thi = ins->thi; + + flb_plg_debug(ins, "thread resume instance"); + + /* compose message to resume the thread */ + val = FLB_BITS_U64_SET(FLB_INPUT_THREAD_TO_THREAD, + FLB_INPUT_THREAD_RESUME); + + ret = flb_pipe_w(thi->ch_parent_events[1], &val, sizeof(val)); + if (ret <= 0) { + flb_errno(); + return -1; + } + + return 0; +} + int flb_input_thread_instance_exit(struct flb_input_instance *ins) { int ret; From b2900a4ae2bfc940511fbb38501a5e80fa8988ec Mon Sep 17 00:00:00 2001 From: Phillip Whelan Date: Wed, 2 Aug 2023 15:46:59 -0400 Subject: [PATCH 173/315] config: throw an error if a configuration property is not applied. Signed-off-by: Phillip Whelan --- src/flb_config.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/flb_config.c b/src/flb_config.c index 0b9cc578ba6..8cc02e62bc5 100644 --- a/src/flb_config.c +++ b/src/flb_config.c @@ -781,6 +781,9 @@ static int configure_plugins_type(struct flb_config *config, struct flb_cf *cf, continue; } + // mark as error by default. + ret = -1; + if (type == FLB_CF_CUSTOM) { if (kv->val->type == CFL_VARIANT_STRING) { ret = flb_custom_set_property(ins, kv->key, kv->val->data.as_string); From 5a24487d7f3a13523804a41ec9c412ee68db8c1d Mon Sep 17 00:00:00 2001 From: Phillip Whelan Date: Wed, 9 Aug 2023 10:13:57 -0400 Subject: [PATCH 174/315] config: update comment about setting ret to -1. Signed-off-by: Phillip Whelan --- src/flb_config.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/flb_config.c b/src/flb_config.c index 8cc02e62bc5..459ff8197dd 100644 --- a/src/flb_config.c +++ b/src/flb_config.c @@ -781,7 +781,9 @@ static int configure_plugins_type(struct flb_config *config, struct flb_cf *cf, continue; } - // mark as error by default. + /* set ret to -1 to ensure that we treat any unhandled plugin or + * value types as errors. + */ ret = -1; if (type == FLB_CF_CUSTOM) { From 8dc84d2e120a451c322ade21d80e7e696b252d6f Mon Sep 17 00:00:00 2001 From: Hiroshi Hatake Date: Sun, 20 Aug 2023 01:58:53 +0900 Subject: [PATCH 175/315] in_windows_exporter_metrics: Implement WMI based memory and paging_file metrics (#7817) --------- Signed-off-by: Hiroshi Hatake --- .../CMakeLists.txt | 2 + plugins/in_windows_exporter_metrics/we.c | 124 ++++ plugins/in_windows_exporter_metrics/we.h | 51 ++ .../we_wmi_memory.c | 557 ++++++++++++++++++ .../we_wmi_memory.h | 29 + .../we_wmi_paging_file.c | 156 +++++ .../we_wmi_paging_file.h | 29 + 7 files changed, 948 insertions(+) create mode 100644 plugins/in_windows_exporter_metrics/we_wmi_memory.c create mode 100644 plugins/in_windows_exporter_metrics/we_wmi_memory.h create mode 100644 plugins/in_windows_exporter_metrics/we_wmi_paging_file.c create mode 100644 plugins/in_windows_exporter_metrics/we_wmi_paging_file.h diff --git a/plugins/in_windows_exporter_metrics/CMakeLists.txt b/plugins/in_windows_exporter_metrics/CMakeLists.txt index 8b20fa9bd55..4474e1ce166 100644 --- a/plugins/in_windows_exporter_metrics/CMakeLists.txt +++ b/plugins/in_windows_exporter_metrics/CMakeLists.txt @@ -15,6 +15,8 @@ set(src we_wmi_logon.c we_wmi_system.c we_wmi_service.c + we_wmi_memory.c + we_wmi_paging_file.c ) set(libs diff --git a/plugins/in_windows_exporter_metrics/we.c b/plugins/in_windows_exporter_metrics/we.c index b0af3ecccff..5dd3631ec95 100644 --- a/plugins/in_windows_exporter_metrics/we.c +++ b/plugins/in_windows_exporter_metrics/we.c @@ -41,6 +41,8 @@ #include "we_wmi_system.h" #include "we_wmi_thermalzone.h" #include "we_wmi_service.h" +#include "we_wmi_memory.h" +#include "we_wmi_paging_file.h" static int we_timer_cpu_metrics_cb(struct flb_input_instance *ins, struct flb_config *config, void *in_context) @@ -142,6 +144,26 @@ static int we_timer_wmi_service_metrics_cb(struct flb_input_instance *ins, return 0; } +static int we_timer_wmi_memory_metrics_cb(struct flb_input_instance *ins, + struct flb_config *config, void *in_context) +{ + struct flb_ne *ctx = in_context; + + we_wmi_memory_update(ctx); + + return 0; +} + +static int we_timer_wmi_paging_file_metrics_cb(struct flb_input_instance *ins, + struct flb_config *config, void *in_context) +{ + struct flb_ne *ctx = in_context; + + we_wmi_paging_file_update(ctx); + + return 0; +} + struct flb_we_callback { char *name; void (*func)(char *, void *, void *); @@ -264,6 +286,20 @@ static void we_wmi_service_update_cb(char *name, void *p1, void *p2) we_wmi_service_update(ctx); } +static void we_wmi_memory_update_cb(char *name, void *p1, void *p2) +{ + struct flb_we *ctx = p1; + + we_wmi_memory_update(ctx); +} + +static void we_wmi_paging_file_update_cb(char *name, void *p1, void *p2) +{ + struct flb_we *ctx = p1; + + we_wmi_paging_file_update(ctx); +} + static int we_update_cb(struct flb_we *ctx, char *name) { int ret; @@ -287,6 +323,8 @@ struct flb_we_callback ne_callbacks[] = { { "logon", we_wmi_logon_update_cb }, { "system", we_wmi_system_update_cb }, { "service", we_wmi_service_update_cb }, + { "memory", we_wmi_memory_update_cb }, + { "paging_file", we_wmi_paging_file_update_cb }, { 0 } }; @@ -321,6 +359,8 @@ static int in_we_init(struct flb_input_instance *in, ctx->coll_wmi_logon_fd = -1; ctx->coll_wmi_system_fd = -1; ctx->coll_wmi_service_fd = -1; + ctx->coll_wmi_memory_fd = -1; + ctx->coll_wmi_paging_file_fd = -1; ctx->callback = flb_callback_create(in->name); if (!ctx->callback) { @@ -625,6 +665,54 @@ static int in_we_init(struct flb_input_instance *in, return -1; } } + else if (strncmp(entry->str, "memory", 6) == 0) { + if (ctx->wmi_memory_scrape_interval == 0) { + flb_plg_debug(ctx->ins, "enabled metrics %s", entry->str); + metric_idx = 10; + } else { + /* Create the memory collector */ + ret = flb_input_set_collector_time(in, + we_timer_wmi_memory_metrics_cb, + ctx->wmi_memory_scrape_interval, 0, + config); + if (ret == -1) { + flb_plg_error(ctx->ins, + "could not set memory collector for Windows Exporter Metrics plugin"); + return -1; + } + ctx->coll_wmi_memory_fd = ret; + } + + /* Initialize memory metric collectors */ + ret = we_wmi_memory_init(ctx); + if (ret) { + return -1; + } + } + else if (strncmp(entry->str, "paging_file", 11) == 0) { + if (ctx->wmi_paging_file_scrape_interval == 0) { + flb_plg_debug(ctx->ins, "enabled metrics %s", entry->str); + metric_idx = 11; + } else { + /* Create the paging_file collector */ + ret = flb_input_set_collector_time(in, + we_timer_wmi_paging_file_metrics_cb, + ctx->wmi_paging_file_scrape_interval, 0, + config); + if (ret == -1) { + flb_plg_error(ctx->ins, + "could not set paging_file collector for Windows Exporter Metrics plugin"); + return -1; + } + ctx->coll_wmi_paging_file_fd = ret; + } + + /* Initialize paging_file metric collectors */ + ret = we_wmi_paging_file_init(ctx); + if (ret) { + return -1; + } + } else { flb_plg_warn(ctx->ins, "Unknown metrics: %s", entry->str); metric_idx = -1; @@ -698,6 +786,12 @@ static int in_we_exit(void *data, struct flb_config *config) else if (strncmp(entry->str, "service", 7) == 0) { we_wmi_service_exit(ctx); } + else if (strncmp(entry->str, "memory", 6) == 0) { + we_wmi_memory_exit(ctx); + } + else if (strncmp(entry->str, "paging_file", 11) == 0) { + we_wmi_paging_file_exit(ctx); + } else { flb_plg_warn(ctx->ins, "Unknown metrics: %s", entry->str); } @@ -738,6 +832,12 @@ static int in_we_exit(void *data, struct flb_config *config) if (ctx->coll_wmi_service_fd != -1) { we_wmi_service_exit(ctx); } + if (ctx->coll_wmi_memory_fd != -1) { + we_wmi_memory_exit(ctx); + } + if (ctx->coll_wmi_paging_file_fd != -1) { + we_wmi_paging_file_exit(ctx); + } flb_we_config_destroy(ctx); @@ -781,6 +881,12 @@ static void in_we_pause(void *data, struct flb_config *config) if (ctx->coll_wmi_service_fd != -1) { flb_input_collector_pause(ctx->coll_wmi_service_fd, ctx->ins); } + if (ctx->coll_wmi_memory_fd != -1) { + flb_input_collector_pause(ctx->coll_wmi_memory_fd, ctx->ins); + } + if (ctx->coll_wmi_paging_file_fd != -1) { + flb_input_collector_pause(ctx->coll_wmi_paging_file_fd, ctx->ins); + } } static void in_we_resume(void *data, struct flb_config *config) @@ -820,6 +926,12 @@ static void in_we_resume(void *data, struct flb_config *config) if (ctx->coll_wmi_service_fd != -1) { flb_input_collector_resume(ctx->coll_wmi_service_fd, ctx->ins); } + if (ctx->coll_wmi_memory_fd != -1) { + flb_input_collector_resume(ctx->coll_wmi_memory_fd, ctx->ins); + } + if (ctx->coll_wmi_paging_file_fd != -1) { + flb_input_collector_resume(ctx->coll_wmi_paging_file_fd, ctx->ins); + } } /* Configuration properties map */ @@ -890,6 +1002,18 @@ static struct flb_config_map config_map[] = { 0, FLB_TRUE, offsetof(struct flb_we, wmi_service_scrape_interval), "scrape interval to collect service metrics from the node." }, + + { + FLB_CONFIG_MAP_TIME, "collector.memory.scrape_interval", "0", + 0, FLB_TRUE, offsetof(struct flb_we, wmi_memory_scrape_interval), + "scrape interval to collect memory metrics from the node." + }, + { + FLB_CONFIG_MAP_TIME, "collector.paging_file.scrape_interval", "0", + 0, FLB_TRUE, offsetof(struct flb_we, wmi_paging_file_scrape_interval), + "scrape interval to collect paging_file metrics from the node." + }, + { FLB_CONFIG_MAP_CLIST, "metrics", "cpu,cpu_info,os,net,logical_disk,cs,thermalzone,logon,system,service", diff --git a/plugins/in_windows_exporter_metrics/we.h b/plugins/in_windows_exporter_metrics/we.h index e74305e0967..08d14f9a580 100644 --- a/plugins/in_windows_exporter_metrics/we.h +++ b/plugins/in_windows_exporter_metrics/we.h @@ -154,6 +154,51 @@ struct we_wmi_service_counters { int operational; }; +struct we_wmi_memory_counters { + struct wmi_query_spec *info; + struct cmt_gauge *available_bytes; + struct cmt_gauge *cache_bytes; + struct cmt_gauge *cache_bytes_peak; + struct cmt_gauge *cache_faults_total; + struct cmt_gauge *commit_limit; + struct cmt_gauge *committed_bytes; + struct cmt_gauge *demand_zero_faults_total; + struct cmt_gauge *free_and_zero_page_list_bytes; + struct cmt_gauge *free_system_page_table_entries; + struct cmt_gauge *modified_page_list_bytes; + struct cmt_gauge *page_faults_total; + struct cmt_gauge *swap_page_reads_total; + struct cmt_gauge *swap_pages_read_total; + struct cmt_gauge *swap_pages_written_total; + struct cmt_gauge *swap_page_operations_total; + struct cmt_gauge *swap_page_writes_total; + struct cmt_gauge *pool_nonpaged_allocs_total; + struct cmt_gauge *pool_nonpaged_bytes; + struct cmt_gauge *pool_paged_allocs_total; + struct cmt_gauge *pool_paged_bytes; + struct cmt_gauge *pool_paged_resident_bytes; + struct cmt_gauge *standby_cache_core_bytes; + struct cmt_gauge *standby_cache_normal_priority_bytes; + struct cmt_gauge *standby_cache_reserve_bytes; + struct cmt_gauge *system_cache_resident_bytes; + struct cmt_gauge *system_code_resident_bytes; + struct cmt_gauge *system_code_total_bytes; + struct cmt_gauge *system_driver_resident_bytes; + struct cmt_gauge *system_driver_total_bytes; + struct cmt_gauge *transition_faults_total; + struct cmt_gauge *transition_pages_repurposed_total; + struct cmt_gauge *write_copies_total; + int operational; +}; + +struct we_wmi_paging_file_counters { + struct wmi_query_spec *info; + struct cmt_gauge *allocated_base_size_megabytes; + struct cmt_gauge *current_usage_megabytes; + struct cmt_gauge *peak_usage_megabytes; + int operational; +}; + struct we_os_counters { struct cmt_gauge *info; struct cmt_gauge *users; @@ -220,6 +265,8 @@ struct flb_we { int wmi_logon_scrape_interval; int wmi_system_scrape_interval; int wmi_service_scrape_interval; + int wmi_memory_scrape_interval; + int wmi_paging_file_scrape_interval; int coll_cpu_fd; /* collector fd (cpu) */ int coll_net_fd; /* collector fd (net) */ @@ -231,6 +278,8 @@ struct flb_we { int coll_wmi_logon_fd; /* collector fd (wmi_logon) */ int coll_wmi_system_fd; /* collector fd (wmi_system) */ int coll_wmi_service_fd; /* collector fd (wmi_service) */ + int coll_wmi_memory_fd; /* collector fd (wmi_memory) */ + int coll_wmi_paging_file_fd; /* collector fd (wmi_paging_file) */ /* * Metrics Contexts @@ -247,6 +296,8 @@ struct flb_we { struct we_wmi_logon_counters *wmi_logon; struct we_wmi_system_counters *wmi_system; struct we_wmi_service_counters *wmi_service; + struct we_wmi_memory_counters *wmi_memory; + struct we_wmi_paging_file_counters *wmi_paging_file; }; typedef int (*collector_cb)(struct flb_we *); diff --git a/plugins/in_windows_exporter_metrics/we_wmi_memory.c b/plugins/in_windows_exporter_metrics/we_wmi_memory.c new file mode 100644 index 00000000000..ec1a13e9667 --- /dev/null +++ b/plugins/in_windows_exporter_metrics/we_wmi_memory.c @@ -0,0 +1,557 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Fluent Bit + * ========== + * Copyright (C) 2022 The Fluent Bit Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include + +#include "we.h" +#include "we_wmi.h" +#include "we_wmi_memory.h" +#include "we_util.h" +#include "we_metric.h" + +static double nop_adjust(double value) +{ + return value; +} + +int we_wmi_memory_init(struct flb_we *ctx) +{ + struct cmt_gauge *g; + + ctx->wmi_memory = flb_calloc(1, sizeof(struct we_wmi_memory_counters)); + if (!ctx->wmi_memory) { + flb_errno(); + return -1; + } + ctx->wmi_memory->operational = FLB_FALSE; + + g = cmt_gauge_create(ctx->cmt, "windows", "memory", "available_bytes", + "The amount of physical memory, in bytes, immediately available " \ + "for allocation to a process or for system use. (AvailableBytes)", + 0, NULL); + + if (!g) { + return -1; + } + ctx->wmi_memory->available_bytes = g; + + g = cmt_gauge_create(ctx->cmt, "windows", "memory", "cache_bytes", + "The size, in bytes, of the portion of the system file cache " \ + "which is currently resident and active in physical memory "\ + "(CacheBytes)", + 0, NULL); + + if (!g) { + return -1; + } + ctx->wmi_memory->cache_bytes = g; + + g = cmt_gauge_create(ctx->cmt, "windows", "memory", "cache_bytes_peak", + "the maximum number of bytes used by the system file cache " \ + "since the system was last restarted (CacheBytesPeak)", + 0, NULL); + + if (!g) { + return -1; + } + ctx->wmi_memory->cache_bytes_peak = g; + + g = cmt_gauge_create(ctx->cmt, "windows", "memory", "cache_faults_total", + "The rate at which faults occur when a page sought in " \ + "the file system cache is not found and must be retrieved " \ + "from elsewhere in memory (a soft fault) or from disk (a hard fault)" \ + "(CacheFaultsPersec)", + 0, NULL); + + if (!g) { + return -1; + } + ctx->wmi_memory->cache_faults_total = g; + + g = cmt_gauge_create(ctx->cmt, "windows", "memory", "commit_limit", + "The amount of virtual memory that can be committed " \ + "without having to extend the paging file(s) " \ + "(CommitLimit)", + 0, NULL); + + if (!g) { + return -1; + } + ctx->wmi_memory->commit_limit = g; + + g = cmt_gauge_create(ctx->cmt, "windows", "memory", "committed_bytes", + "The amount of committed virtual memory, in bytes " \ + "(CommittedBytes)", + 0, NULL); + + if (!g) { + return -1; + } + ctx->wmi_memory->committed_bytes = g; + + g = cmt_gauge_create(ctx->cmt, "windows", "memory", "demand_zero_faults_total", + "The rate at which a zeroed page is required to satisfy the fault " \ + "(DemandZeroFaultsPersec)", + 0, NULL); + + if (!g) { + return -1; + } + ctx->wmi_memory->demand_zero_faults_total = g; + + g = cmt_gauge_create(ctx->cmt, "windows", "memory", "free_and_zero_page_list_bytes", + "the amount of physical memory, in bytes, that is assigned to " \ + "the free and zero page lists " \ + "(FreeAndZeroPageListBytes)", + 0, NULL); + + if (!g) { + return -1; + } + ctx->wmi_memory->free_and_zero_page_list_bytes = g; + + g = cmt_gauge_create(ctx->cmt, "windows", "memory", "free_system_page_table_entries", + "The number of page table entries not currently in used by the system " \ + "(FreeSystemPageTableEntries)", + 0, NULL); + + if (!g) { + return -1; + } + ctx->wmi_memory->free_system_page_table_entries = g; + + g = cmt_gauge_create(ctx->cmt, "windows", "memory", "modified_page_list_bytes", + "The amount of physical memory, in bytes, that is assigned to " \ + "the modified page list " \ + "(ModifiedPageListBytes)", + 0, NULL); + + if (!g) { + return -1; + } + ctx->wmi_memory->modified_page_list_bytes = g; + + g = cmt_gauge_create(ctx->cmt, "windows", "memory", "page_faults_total", + "The average number of pages faulted per second. " \ + "It is measured in number of pages faulted per second " \ + "because only one page is faulted in each fault operation, " \ + "hence this is also equal to the number of page fault operations " \ + "(PageFaultsPersec)", + 0, NULL); + + if (!g) { + return -1; + } + ctx->wmi_memory->page_faults_total = g; + + g = cmt_gauge_create(ctx->cmt, "windows", "memory", "swap_page_reads_total", + "The rate at which the disk was read to resolve hard page faults " \ + "(PageReadsPersec)", + 0, NULL); + + if (!g) { + return -1; + } + ctx->wmi_memory->swap_page_reads_total = g; + + g = cmt_gauge_create(ctx->cmt, "windows", "memory", "swap_pages_read_total", + "The rate at which pages are read from disk to resolve hard page faults " \ + "(PagesInputPersec)", + 0, NULL); + + if (!g) { + return -1; + } + ctx->wmi_memory->swap_pages_read_total = g; + + g = cmt_gauge_create(ctx->cmt, "windows", "memory", "swap_pages_written_total", + "the rate at which pages are written to disk to free up space "\ + "in physical memory (PagesOutputPersec)", + 0, NULL); + + if (!g) { + return -1; + } + ctx->wmi_memory->swap_pages_written_total = g; + + g = cmt_gauge_create(ctx->cmt, "windows", "memory", "swap_page_operations_total", + "the rate at which pages are read from or written " \ + "to disk to resolve hard page faults (PagesPersec)", + 0, NULL); + + if (!g) { + return -1; + } + ctx->wmi_memory->swap_page_operations_total = g; + + g = cmt_gauge_create(ctx->cmt, "windows", "memory", "swap_page_writes_total", + "the rate at which pages are written to disk to free up space " \ + "in physical memory (PageWritesPersec)", + 0, NULL); + + if (!g) { + return -1; + } + ctx->wmi_memory->swap_page_writes_total = g; + + g = cmt_gauge_create(ctx->cmt, "windows", "memory", "pool_nonpaged_allocs_total", + "Number of calls to allocate space in the nonpaged pool (PoolNonpagedAllocs)", + 0, NULL); + + if (!g) { + return -1; + } + ctx->wmi_memory->pool_nonpaged_allocs_total = g; + + g = cmt_gauge_create(ctx->cmt, "windows", "memory", "pool_nonpaged_bytes", + "the size, in bytes, of the nonpaged pool, an area of " \ + "the system virtual memory that is used for objects " \ + "that cannot be written to disk, but must remain " \ + "in physical memory as long as they are allocated " \ + "(PoolNonpagedBytes)", + 0, NULL); + + if (!g) { + return -1; + } + ctx->wmi_memory->pool_nonpaged_bytes = g; + + g = cmt_gauge_create(ctx->cmt, "windows", "memory", "pool_nonpaged_allocs_total", + "Number of bytes of allocated space in paged pool (PoolPagedAllocs)", + 0, NULL); + + if (!g) { + return -1; + } + ctx->wmi_memory->pool_paged_allocs_total = g; + + g = cmt_gauge_create(ctx->cmt, "windows", "memory", "pool_paged_bytes", + "the size, in bytes, of the paged pool, an area of the system " \ + "virtual memory that is used for objects that can be written " \ + "to disk when they are not being used (PoolPagedBytes)", + 0, NULL); + + if (!g) { + return -1; + } + ctx->wmi_memory->pool_paged_bytes = g; + + g = cmt_gauge_create(ctx->cmt, "windows", "memory", "pool_paged_resident_bytes", + "the size, in bytes, of the portion of the paged pool " \ + "that is currently resident and active in physical memory " \ + "(PoolPagedResidentBytes)", + 0, NULL); + + if (!g) { + return -1; + } + ctx->wmi_memory->pool_paged_resident_bytes = g; + + g = cmt_gauge_create(ctx->cmt, "windows", "memory", "standby_cache_core_bytes", + "The amount of physical memory, in bytes, that is assigned " \ + "to the core standby cache page lists (StandbyCacheCoreBytes)", + 0, NULL); + + if (!g) { + return -1; + } + ctx->wmi_memory->standby_cache_core_bytes = g; + + g = cmt_gauge_create(ctx->cmt, "windows", "memory", "standby_cache_normal_priority_bytes", + " the amount of physical memory, in bytes, that is assigned " \ + "to the normal priority standby cache page lists " \ + "(StandbyCacheNormalPriorityBytes)", + 0, NULL); + + if (!g) { + return -1; + } + ctx->wmi_memory->standby_cache_normal_priority_bytes = g; + + g = cmt_gauge_create(ctx->cmt, "windows", "memory", "standby_cache_reserve_bytes", + "Number of physical memory size(bytes) which is assigned to " \ + "the reserve standby cache page lists (StandbyCacheReserveBytes)", + 0, NULL); + + if (!g) { + return -1; + } + ctx->wmi_memory->standby_cache_reserve_bytes = g; + + g = cmt_gauge_create(ctx->cmt, "windows", "memory", "system_cache_resident_bytes", + "Number of physical memory size(bytes) of the portion of " \ + "the system file cache which is currently resident and active " \ + "(SystemCacheResidentBytes)", + 0, NULL); + + if (!g) { + return -1; + } + ctx->wmi_memory->system_cache_resident_bytes = g; + + g = cmt_gauge_create(ctx->cmt, "windows", "memory", "system_code_resident_bytes", + "Number of physical memory size(bytes) of the pageable operating system code "\ + "which is currently resident and active (SystemCodeResidentBytes)", + 0, NULL); + + if (!g) { + return -1; + } + ctx->wmi_memory->system_code_resident_bytes = g; + + g = cmt_gauge_create(ctx->cmt, "windows", "memory", "system_code_total_bytes", + "Number of virtual memory size(bytes) of the pageable operating system code " \ + "which is mapped into virtual address (SystemCodeTotalBytes)", + 0, NULL); + + if (!g) { + return -1; + } + ctx->wmi_memory->system_code_total_bytes = g; + + g = cmt_gauge_create(ctx->cmt, "windows", "memory", "system_driver_resident_bytes", + "Number of pagable physical memory size(bytes) by used device drivers "\ + "(SystemDriverResidentBytes)", + 0, NULL); + + if (!g) { + return -1; + } + ctx->wmi_memory->system_driver_resident_bytes = g; + + g = cmt_gauge_create(ctx->cmt, "windows", "memory", "system_driver_total_bytes", + "Number of virtual memory size(bytes) by used device drivers " \ + "(SystemDriverTotalBytes)", + 0, NULL); + + if (!g) { + return -1; + } + ctx->wmi_memory->system_driver_total_bytes = g; + + g = cmt_gauge_create(ctx->cmt, "windows", "memory", "transition_faults_total", + "Number of the rate at which page faults are resolved by recovering pages " \ + "that were being used by another process sharing the page, " \ + "or were on the modified page list or the standby list, " \ + "or were being written to disk at the time of the page fault " \ + "(TransitionFaultsPersec)", + 0, NULL); + + if (!g) { + return -1; + } + ctx->wmi_memory->transition_faults_total = g; + + g = cmt_gauge_create(ctx->cmt, "windows", "memory", "transition_pages_repurposed_total", + "Number of the rate at which the number of transition cache " \ + "pages were reused for a different purpose " \ + "(TransitionPagesRePurposedPersec)", + 0, NULL); + + if (!g) { + return -1; + } + ctx->wmi_memory->transition_pages_repurposed_total = g; + + g = cmt_gauge_create(ctx->cmt, "windows", "memory", "write_copies_total", + "Number of the rate at which page faults are caused by "\ + "attempts to write that have been satisfied by coping " \ + "of the page from elsewhere in physical memory " \ + "(WriteCopiesPersec)", + 0, NULL); + + if (!g) { + return -1; + } + ctx->wmi_memory->write_copies_total = g; + + ctx->wmi_memory->info = flb_calloc(1, sizeof(struct wmi_query_spec)); + if (!ctx->wmi_memory->info) { + flb_errno(); + return -1; + } + ctx->wmi_memory->info->metric_instance = (void *)g; + ctx->wmi_memory->info->type = CMT_GAUGE; + ctx->wmi_memory->info->value_adjuster = nop_adjust; + ctx->wmi_memory->info->wmi_counter = "Win32_PerfRawData_PerfOS_Memory"; + ctx->wmi_memory->info->wmi_property = ""; + ctx->wmi_memory->info->label_property_count = 0; + ctx->wmi_memory->info->label_property_keys = NULL; + ctx->wmi_memory->info->where_clause = NULL; + + ctx->wmi_memory->operational = FLB_TRUE; + + return 0; +} + +int we_wmi_memory_exit(struct flb_we *ctx) +{ + ctx->wmi_memory->operational = FLB_FALSE; + + flb_free(ctx->wmi_memory->info); + flb_free(ctx->wmi_memory); + + return 0; +} + +int we_wmi_memory_update(struct flb_we *ctx) +{ + uint64_t timestamp = 0; + IEnumWbemClassObject* enumerator = NULL; + HRESULT hr; + + IWbemClassObject *class_obj = NULL; + ULONG ret = 0; + double val = 0; + + if (!ctx->wmi_memory->operational) { + flb_plg_error(ctx->ins, "memory collector not yet in operational state"); + + return -1; + } + + if (FAILED(we_wmi_coinitialize(ctx))) { + return -1; + } + + timestamp = cfl_time_now(); + + if (FAILED(we_wmi_execute_query(ctx, ctx->wmi_memory->info, &enumerator))) { + return -1; + } + + while(enumerator) { + hr = enumerator->lpVtbl->Next(enumerator, WBEM_INFINITE, 1, &class_obj, &ret); + + if(ret == 0) { + break; + } + + val = we_wmi_get_property_value(ctx, "AvailableBytes", class_obj); + cmt_gauge_set(ctx->wmi_memory->available_bytes, timestamp, val, 0, NULL); + + val = we_wmi_get_property_value(ctx, "CacheBytes", class_obj); + cmt_gauge_set(ctx->wmi_memory->cache_bytes, timestamp, val, 0, NULL); + + val = we_wmi_get_property_value(ctx, "CacheBytesPeak", class_obj); + cmt_gauge_set(ctx->wmi_memory->cache_bytes_peak, timestamp, val, 0, NULL); + + val = we_wmi_get_property_value(ctx, "CacheFaultsPersec", class_obj); + cmt_gauge_set(ctx->wmi_memory->cache_faults_total, timestamp, val, 0, NULL); + + val = we_wmi_get_property_value(ctx, "CommitLimit", class_obj); + cmt_gauge_set(ctx->wmi_memory->commit_limit, timestamp, val, 0, NULL); + + val = we_wmi_get_property_value(ctx, "CommittedBytes", class_obj); + cmt_gauge_set(ctx->wmi_memory->committed_bytes, timestamp, val, 0, NULL); + + val = we_wmi_get_property_value(ctx, "DemandZeroFaultsPersec", class_obj); + cmt_gauge_set(ctx->wmi_memory->demand_zero_faults_total, timestamp, val, 0, NULL); + + val = we_wmi_get_property_value(ctx, "FreeAndZeroPageListBytes", class_obj); + cmt_gauge_set(ctx->wmi_memory->free_and_zero_page_list_bytes, timestamp, val, 0, NULL); + + val = we_wmi_get_property_value(ctx, "FreeSystemPageTableEntries", class_obj); + cmt_gauge_set(ctx->wmi_memory->free_system_page_table_entries, timestamp, val, 0, NULL); + + val = we_wmi_get_property_value(ctx, "ModifiedPageListBytes", class_obj); + cmt_gauge_set(ctx->wmi_memory->modified_page_list_bytes, timestamp, val, 0, NULL); + + val = we_wmi_get_property_value(ctx, "PageFaultsPersec", class_obj); + cmt_gauge_set(ctx->wmi_memory->page_faults_total, timestamp, val, 0, NULL); + + val = we_wmi_get_property_value(ctx, "PageReadsPersec", class_obj); + cmt_gauge_set(ctx->wmi_memory->swap_page_reads_total, timestamp, val, 0, NULL); + + val = we_wmi_get_property_value(ctx, "PagesInputPersec", class_obj); + cmt_gauge_set(ctx->wmi_memory->swap_pages_read_total, timestamp, val, 0, NULL); + + val = we_wmi_get_property_value(ctx, "PagesOutputPersec", class_obj); + cmt_gauge_set(ctx->wmi_memory->swap_pages_written_total, timestamp, val, 0, NULL); + + val = we_wmi_get_property_value(ctx, "PagesPersec", class_obj); + cmt_gauge_set(ctx->wmi_memory->swap_page_operations_total, timestamp, val, 0, NULL); + + val = we_wmi_get_property_value(ctx, "PageWritesPersec", class_obj); + cmt_gauge_set(ctx->wmi_memory->swap_page_writes_total, timestamp, val, 0, NULL); + + val = we_wmi_get_property_value(ctx, "PoolNonpagedAllocs", class_obj); + cmt_gauge_set(ctx->wmi_memory->pool_nonpaged_allocs_total, timestamp, val, 0, NULL); + + val = we_wmi_get_property_value(ctx, "PoolNonpagedBytes", class_obj); + cmt_gauge_set(ctx->wmi_memory->pool_nonpaged_bytes, timestamp, val, 0, NULL); + + val = we_wmi_get_property_value(ctx, "PoolPagedAllocs", class_obj); + cmt_gauge_set(ctx->wmi_memory->pool_paged_allocs_total, timestamp, val, 0, NULL); + + val = we_wmi_get_property_value(ctx, "PoolPagedBytes", class_obj); + cmt_gauge_set(ctx->wmi_memory->pool_paged_bytes, timestamp, val, 0, NULL); + + val = we_wmi_get_property_value(ctx, "PoolPagedResidentBytes", class_obj); + cmt_gauge_set(ctx->wmi_memory->pool_paged_resident_bytes, timestamp, val, 0, NULL); + + val = we_wmi_get_property_value(ctx, "StandbyCacheCoreBytes", class_obj); + cmt_gauge_set(ctx->wmi_memory->standby_cache_core_bytes, timestamp, val, 0, NULL); + + val = we_wmi_get_property_value(ctx, "StandbyCacheNormalPriorityBytes", class_obj); + cmt_gauge_set(ctx->wmi_memory->standby_cache_normal_priority_bytes, timestamp, val, 0, NULL); + + val = we_wmi_get_property_value(ctx, "StandbyCacheReserveBytes", class_obj); + cmt_gauge_set(ctx->wmi_memory->standby_cache_reserve_bytes, timestamp, val, 0, NULL); + + val = we_wmi_get_property_value(ctx, "SystemCacheResidentBytes", class_obj); + cmt_gauge_set(ctx->wmi_memory->system_cache_resident_bytes, timestamp, val, 0, NULL); + + val = we_wmi_get_property_value(ctx, "SystemCacheResidentBytes", class_obj); + cmt_gauge_set(ctx->wmi_memory->system_cache_resident_bytes, timestamp, val, 0, NULL); + + val = we_wmi_get_property_value(ctx, "SystemCodeResidentBytes", class_obj); + cmt_gauge_set(ctx->wmi_memory->system_code_resident_bytes, timestamp, val, 0, NULL); + + val = we_wmi_get_property_value(ctx, "SystemCodeTotalBytes", class_obj); + cmt_gauge_set(ctx->wmi_memory->system_code_total_bytes, timestamp, val, 0, NULL); + + val = we_wmi_get_property_value(ctx, "SystemDriverResidentBytes", class_obj); + cmt_gauge_set(ctx->wmi_memory->system_driver_resident_bytes, timestamp, val, 0, NULL); + + val = we_wmi_get_property_value(ctx, "SystemDriverTotalBytes", class_obj); + cmt_gauge_set(ctx->wmi_memory->system_driver_total_bytes, timestamp, val, 0, NULL); + + val = we_wmi_get_property_value(ctx, "TransitionFaultsPersec", class_obj); + cmt_gauge_set(ctx->wmi_memory->transition_faults_total, timestamp, val, 0, NULL); + + val = we_wmi_get_property_value(ctx, "TransitionPagesRePurposedPersec", class_obj); + cmt_gauge_set(ctx->wmi_memory->transition_pages_repurposed_total, timestamp, val, 0, NULL); + + val = we_wmi_get_property_value(ctx, "WriteCopiesPersec", class_obj); + cmt_gauge_set(ctx->wmi_memory->write_copies_total, timestamp, val, 0, NULL); + + class_obj->lpVtbl->Release(class_obj); + } + + enumerator->lpVtbl->Release(enumerator); + + we_wmi_cleanup(ctx); + + return 0; +} diff --git a/plugins/in_windows_exporter_metrics/we_wmi_memory.h b/plugins/in_windows_exporter_metrics/we_wmi_memory.h new file mode 100644 index 00000000000..fd6f08d548a --- /dev/null +++ b/plugins/in_windows_exporter_metrics/we_wmi_memory.h @@ -0,0 +1,29 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Fluent Bit + * ========== + * Copyright (C) 2023 The Fluent Bit Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLB_WE_WMI_MEMORY_H +#define FLB_WE_WMI_MEMORY_H + +#include "we.h" + +int we_wmi_memory_init(struct flb_we *ctx); +int we_wmi_memory_exit(struct flb_we *ctx); +int we_wmi_memory_update(struct flb_we *ctx); + +#endif diff --git a/plugins/in_windows_exporter_metrics/we_wmi_paging_file.c b/plugins/in_windows_exporter_metrics/we_wmi_paging_file.c new file mode 100644 index 00000000000..ed585381142 --- /dev/null +++ b/plugins/in_windows_exporter_metrics/we_wmi_paging_file.c @@ -0,0 +1,156 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Fluent Bit + * ========== + * Copyright (C) 2022 The Fluent Bit Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include + +#include "we.h" +#include "we_wmi.h" +#include "we_wmi_paging_file.h" +#include "we_util.h" +#include "we_metric.h" + +static double nop_adjust(double value) +{ + return value; +} + +int we_wmi_paging_file_init(struct flb_we *ctx) +{ + struct cmt_gauge *g; + + ctx->wmi_paging_file = flb_calloc(1, sizeof(struct we_wmi_paging_file_counters)); + if (!ctx->wmi_paging_file) { + flb_errno(); + return -1; + } + ctx->wmi_paging_file->operational = FLB_FALSE; + + g = cmt_gauge_create(ctx->cmt, "windows", "paging_file", "allocated_base_size_megabytes", + "The value indicates the actual amount of disk space allocated "\ + "for use with this page file (AllocatedBaseSize)", + 0, NULL); + + if (!g) { + return -1; + } + ctx->wmi_paging_file->allocated_base_size_megabytes = g; + + g = cmt_gauge_create(ctx->cmt, "windows", "paging_file", "current_usage_megabytes", + "The value indicates how much of the total reserved page file " \ + "is currently in use (CurrentUsage)", + 0, NULL); + + if (!g) { + return -1; + } + ctx->wmi_paging_file->current_usage_megabytes = g; + + g = cmt_gauge_create(ctx->cmt, "windows", "paging_file", "peak_usage_megabytes", + "The value indicates the highest use page file (PeakUsage)", + 0, NULL); + + if (!g) { + return -1; + } + ctx->wmi_paging_file->peak_usage_megabytes = g; + + ctx->wmi_paging_file->info = flb_calloc(1, sizeof(struct wmi_query_spec)); + if (!ctx->wmi_paging_file->info) { + flb_errno(); + return -1; + } + ctx->wmi_paging_file->info->metric_instance = (void *)g; + ctx->wmi_paging_file->info->type = CMT_GAUGE; + ctx->wmi_paging_file->info->value_adjuster = nop_adjust; + ctx->wmi_paging_file->info->wmi_counter = "Win32_PageFileUsage"; + ctx->wmi_paging_file->info->wmi_property = ""; + ctx->wmi_paging_file->info->label_property_count = 0; + ctx->wmi_paging_file->info->label_property_keys = NULL; + ctx->wmi_paging_file->info->where_clause = NULL; + + ctx->wmi_paging_file->operational = FLB_TRUE; + + return 0; +} + +int we_wmi_paging_file_exit(struct flb_we *ctx) +{ + ctx->wmi_paging_file->operational = FLB_FALSE; + + flb_free(ctx->wmi_paging_file->info); + flb_free(ctx->wmi_paging_file); + + return 0; +} + +int we_wmi_paging_file_update(struct flb_we *ctx) +{ + uint64_t timestamp = 0; + IEnumWbemClassObject* enumerator = NULL; + HRESULT hr; + + IWbemClassObject *class_obj = NULL; + ULONG ret = 0; + double val = 0; + + if (!ctx->wmi_paging_file->operational) { + flb_plg_error(ctx->ins, "paging_file collector not yet in operational state"); + + return -1; + } + + if (FAILED(we_wmi_coinitialize(ctx))) { + return -1; + } + + timestamp = cfl_time_now(); + + if (FAILED(we_wmi_execute_query(ctx, ctx->wmi_paging_file->info, &enumerator))) { + return -1; + } + + while(enumerator) { + hr = enumerator->lpVtbl->Next(enumerator, WBEM_INFINITE, 1, &class_obj, &ret); + + if(ret == 0) { + break; + } + + val = we_wmi_get_property_value(ctx, "AllocatedBaseSize", class_obj); + cmt_gauge_set(ctx->wmi_paging_file->allocated_base_size_megabytes, timestamp, val, 0, NULL); + + val = we_wmi_get_property_value(ctx, "CurrentUsage", class_obj); + cmt_gauge_set(ctx->wmi_paging_file->current_usage_megabytes, timestamp, val, 0, NULL); + + val = we_wmi_get_property_value(ctx, "PeakUsage", class_obj); + cmt_gauge_set(ctx->wmi_paging_file->peak_usage_megabytes, timestamp, val, 0, NULL); + + class_obj->lpVtbl->Release(class_obj); + } + + enumerator->lpVtbl->Release(enumerator); + + we_wmi_cleanup(ctx); + + return 0; +} diff --git a/plugins/in_windows_exporter_metrics/we_wmi_paging_file.h b/plugins/in_windows_exporter_metrics/we_wmi_paging_file.h new file mode 100644 index 00000000000..5ed74d292a7 --- /dev/null +++ b/plugins/in_windows_exporter_metrics/we_wmi_paging_file.h @@ -0,0 +1,29 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Fluent Bit + * ========== + * Copyright (C) 2023 The Fluent Bit Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLB_WE_WMI_PAGING_FILE_H +#define FLB_WE_WMI_PAGING_FILE_H + +#include "we.h" + +int we_wmi_paging_file_init(struct flb_we *ctx); +int we_wmi_paging_file_exit(struct flb_we *ctx); +int we_wmi_paging_file_update(struct flb_we *ctx); + +#endif From c2eb12ba7aee23913297e6f4d05f8eda8a62d907 Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Sun, 20 Aug 2023 22:16:14 -0600 Subject: [PATCH 176/315] lib: c-ares: upgrade to v1.19.1 Signed-off-by: Eduardo Silva --- cmake/libraries.cmake | 2 +- lib/c-ares-1.19.0/RELEASE-NOTES | 91 -- .../m4/ax_cxx_compile_stdcxx_11.m4 | 166 --- lib/c-ares-1.19.0/m4/ax_pthread.m4 | 332 ----- lib/{c-ares-1.19.0 => c-ares-1.19.1}/AUTHORS | 0 lib/{c-ares-1.19.0 => c-ares-1.19.1}/CHANGES | 300 +++-- .../CMakeLists.txt | 14 +- .../CONTRIBUTING.md | 0 .../INSTALL.md | 0 .../LICENSE.md | 0 .../Makefile.Watcom | 50 +- .../Makefile.am | 0 .../Makefile.dj | 0 .../Makefile.in | 1 + .../Makefile.m32 | 0 .../Makefile.msvc | 0 .../Makefile.netware | 0 lib/{c-ares-1.19.0 => c-ares-1.19.1}/NEWS | 0 .../README.cares | 0 .../README.md | 0 .../README.msvc | 0 lib/c-ares-1.19.1/RELEASE-NOTES | 57 + .../SECURITY.md | 0 lib/{c-ares-1.19.0 => c-ares-1.19.1}/TODO | 0 .../acinclude.m4 | 0 .../aclocal.m4 | 1 + .../aminclude_static.am | 2 +- .../buildconf | 0 .../buildconf.bat | 0 .../c-ares-config.cmake.in | 0 lib/{c-ares-1.19.0 => c-ares-1.19.1}/compile | 0 .../config.guess | 0 .../config.sub | 0 .../configure | 600 ++++++--- .../configure.ac | 17 +- lib/{c-ares-1.19.0 => c-ares-1.19.1}/depcomp | 0 .../docs/CMakeLists.txt | 0 .../docs/Makefile.am | 0 .../docs/Makefile.in | 1 + .../docs/Makefile.inc | 0 .../docs/acountry.1 | 0 .../docs/adig.1 | 0 .../docs/ahost.1 | 0 .../docs/ares_cancel.3 | 0 .../docs/ares_create_query.3 | 0 .../docs/ares_destroy.3 | 0 .../docs/ares_destroy_options.3 | 0 .../docs/ares_dup.3 | 0 .../docs/ares_expand_name.3 | 0 .../docs/ares_expand_string.3 | 0 .../docs/ares_fds.3 | 0 .../docs/ares_free_data.3 | 0 .../docs/ares_free_hostent.3 | 0 .../docs/ares_free_string.3 | 0 .../docs/ares_freeaddrinfo.3 | 0 .../docs/ares_get_servers.3 | 0 .../docs/ares_get_servers_ports.3 | 0 .../docs/ares_getaddrinfo.3 | 0 .../docs/ares_gethostbyaddr.3 | 0 .../docs/ares_gethostbyname.3 | 0 .../docs/ares_gethostbyname_file.3 | 0 .../docs/ares_getnameinfo.3 | 0 .../docs/ares_getsock.3 | 0 .../docs/ares_inet_ntop.3 | 0 .../docs/ares_inet_pton.3 | 0 .../docs/ares_init.3 | 0 .../docs/ares_init_options.3 | 2 +- .../docs/ares_library_cleanup.3 | 0 .../docs/ares_library_init.3 | 0 .../docs/ares_library_init_android.3 | 0 .../docs/ares_library_initialized.3 | 0 .../docs/ares_mkquery.3 | 0 .../docs/ares_parse_a_reply.3 | 0 .../docs/ares_parse_aaaa_reply.3 | 0 .../docs/ares_parse_caa_reply.3 | 0 .../docs/ares_parse_mx_reply.3 | 0 .../docs/ares_parse_naptr_reply.3 | 0 .../docs/ares_parse_ns_reply.3 | 0 .../docs/ares_parse_ptr_reply.3 | 0 .../docs/ares_parse_soa_reply.3 | 0 .../docs/ares_parse_srv_reply.3 | 0 .../docs/ares_parse_txt_reply.3 | 0 .../docs/ares_parse_uri_reply.3 | 0 .../docs/ares_process.3 | 0 .../docs/ares_query.3 | 0 .../docs/ares_save_options.3 | 0 .../docs/ares_search.3 | 0 .../docs/ares_send.3 | 0 .../docs/ares_set_local_dev.3 | 0 .../docs/ares_set_local_ip4.3 | 0 .../docs/ares_set_local_ip6.3 | 0 .../docs/ares_set_servers.3 | 0 .../docs/ares_set_servers_csv.3 | 0 .../docs/ares_set_servers_ports.3 | 0 .../docs/ares_set_servers_ports_csv.3 | 0 .../docs/ares_set_socket_callback.3 | 0 .../docs/ares_set_socket_configure_callback.3 | 0 .../docs/ares_set_socket_functions.3 | 0 .../docs/ares_set_sortlist.3 | 0 .../docs/ares_strerror.3 | 0 .../docs/ares_timeout.3 | 0 .../docs/ares_version.3 | 0 .../get_ver.awk | 0 .../include/CMakeLists.txt | 0 .../include/Makefile.am | 0 .../include/Makefile.in | 1 + .../include/ares.h | 0 .../include/ares_build.h | 0 .../include/ares_build.h.cmake | 0 .../include/ares_build.h.in | 0 .../include/ares_dns.h | 0 .../include/ares_nameser.h | 0 .../include/ares_rules.h | 0 .../include/ares_version.h | 4 +- .../install-sh | 0 .../libcares.pc.cmake | 0 .../libcares.pc.in | 0 .../ltmain.sh | 0 .../m4/ax_ac_append_to_file.m4 | 0 .../m4/ax_ac_print_to_file.m4 | 0 .../m4/ax_add_am_macro_static.m4 | 0 .../m4/ax_am_macros_static.m4 | 0 .../m4/ax_check_gnu_make.m4 | 0 .../m4/ax_check_user_namespace.m4 | 0 .../m4/ax_check_uts_namespace.m4 | 0 .../m4/ax_code_coverage.m4 | 0 lib/c-ares-1.19.1/m4/ax_cxx_compile_stdcxx.m4 | 1009 +++++++++++++++ .../m4/ax_cxx_compile_stdcxx_11.m4 | 39 + .../m4/ax_file_escapes.m4 | 0 lib/c-ares-1.19.1/m4/ax_pthread.m4 | 522 ++++++++ .../m4/ax_require_defined.m4 | 0 .../m4/cares-compilers.m4 | 0 .../m4/cares-confopts.m4 | 0 .../m4/cares-functions.m4 | 85 ++ .../m4/cares-reentrant.m4 | 0 .../m4/libtool.m4 | 0 .../m4/ltoptions.m4 | 0 .../m4/ltsugar.m4 | 0 .../m4/ltversion.m4 | 0 .../m4/lt~obsolete.m4 | 0 .../m4/xc-am-iface.m4 | 0 .../m4/xc-cc-check.m4 | 0 .../m4/xc-lt-iface.m4 | 0 .../m4/xc-translit.m4 | 0 .../m4/xc-val-flgs.m4 | 0 .../m4/zz40-xc-ovr.m4 | 0 lib/{c-ares-1.19.0 => c-ares-1.19.1}/maketgz | 0 lib/{c-ares-1.19.0 => c-ares-1.19.1}/missing | 0 .../msvc_ver.inc | 0 .../src/CMakeLists.txt | 0 .../src/Makefile.am | 0 .../src/Makefile.in | 1 + .../src/lib/CMakeLists.txt | 0 .../src/lib/Makefile.am | 0 .../src/lib/Makefile.in | 30 +- .../src/lib/Makefile.inc | 3 +- .../src/lib/ares__addrinfo2hostent.c | 0 .../src/lib/ares__addrinfo_localhost.c | 2 +- .../src/lib/ares__close_sockets.c | 0 .../src/lib/ares__get_hostent.c | 0 .../src/lib/ares__parse_into_addrinfo.c | 0 .../src/lib/ares__read_line.c | 0 .../src/lib/ares__readaddrinfo.c | 0 .../src/lib/ares__sortaddrinfo.c | 0 .../src/lib/ares__timeval.c | 0 .../src/lib/ares_android.c | 0 .../src/lib/ares_android.h | 0 .../src/lib/ares_cancel.c | 0 .../src/lib/ares_config.h.cmake | 3 + .../src/lib/ares_config.h.in | 3 + .../src/lib/ares_create_query.c | 0 .../src/lib/ares_data.c | 0 .../src/lib/ares_data.h | 2 +- .../src/lib/ares_destroy.c | 3 + .../src/lib/ares_expand_name.c | 6 +- .../src/lib/ares_expand_string.c | 0 .../src/lib/ares_fds.c | 0 .../src/lib/ares_free_hostent.c | 0 .../src/lib/ares_free_string.c | 0 .../src/lib/ares_freeaddrinfo.c | 0 .../src/lib/ares_getaddrinfo.c | 31 +- .../src/lib/ares_getenv.c | 0 .../src/lib/ares_getenv.h | 0 .../src/lib/ares_gethostbyaddr.c | 0 .../src/lib/ares_gethostbyname.c | 0 .../src/lib/ares_getnameinfo.c | 0 .../src/lib/ares_getsock.c | 0 .../src/lib/ares_inet_net_pton.h | 0 .../src/lib/ares_init.c | 101 +- .../src/lib/ares_iphlpapi.h | 0 .../src/lib/ares_ipv6.h | 0 .../src/lib/ares_library_init.c | 0 .../src/lib/ares_llist.c | 0 .../src/lib/ares_llist.h | 0 .../src/lib/ares_mkquery.c | 0 .../src/lib/ares_nowarn.c | 0 .../src/lib/ares_nowarn.h | 0 .../src/lib/ares_options.c | 0 .../src/lib/ares_parse_a_reply.c | 0 .../src/lib/ares_parse_aaaa_reply.c | 0 .../src/lib/ares_parse_caa_reply.c | 0 .../src/lib/ares_parse_mx_reply.c | 0 .../src/lib/ares_parse_naptr_reply.c | 0 .../src/lib/ares_parse_ns_reply.c | 0 .../src/lib/ares_parse_ptr_reply.c | 0 .../src/lib/ares_parse_soa_reply.c | 0 .../src/lib/ares_parse_srv_reply.c | 0 .../src/lib/ares_parse_txt_reply.c | 0 .../src/lib/ares_parse_uri_reply.c | 0 .../src/lib/ares_platform.c | 0 .../src/lib/ares_platform.h | 0 .../src/lib/ares_private.h | 19 +- .../src/lib/ares_process.c | 58 +- .../src/lib/ares_query.c | 36 +- lib/c-ares-1.19.1/src/lib/ares_rand.c | 279 ++++ .../src/lib/ares_search.c | 0 .../src/lib/ares_send.c | 12 +- .../src/lib/ares_setup.h | 0 .../src/lib/ares_strcasecmp.c | 0 .../src/lib/ares_strcasecmp.h | 0 .../src/lib/ares_strdup.c | 0 .../src/lib/ares_strdup.h | 0 .../src/lib/ares_strerror.c | 0 .../src/lib/ares_strsplit.c | 8 +- .../src/lib/ares_strsplit.h | 0 .../src/lib/ares_timeout.c | 0 .../src/lib/ares_version.c | 0 .../src/lib/ares_writev.c | 0 .../src/lib/ares_writev.h | 0 .../src/lib/bitncmp.c | 0 .../src/lib/bitncmp.h | 0 .../src/lib/cares.rc | 0 .../src/lib/config-dos.h | 0 .../src/lib/config-win32.h | 0 .../src/lib/inet_net_pton.c | 194 ++- .../src/lib/inet_ntop.c | 0 .../src/lib/setup_once.h | 0 .../src/lib/windows_port.c | 0 .../src/tools/CMakeLists.txt | 0 .../src/tools/Makefile.am | 0 .../src/tools/Makefile.in | 1 + .../src/tools/Makefile.inc | 0 .../src/tools/acountry.c | 0 .../src/tools/adig.c | 0 .../src/tools/ahost.c | 0 .../src/tools/ares_getopt.c | 0 .../src/tools/ares_getopt.h | 0 .../test/CMakeLists.txt | 0 .../test/Makefile.am | 0 .../test/Makefile.in | 5 +- .../test/Makefile.inc | 0 .../test/Makefile.m32 | 0 .../test/Makefile.msvc | 0 .../test/README.md | 0 .../test/aclocal.m4 | 1 + .../test}/aminclude_static.am | 2 +- .../test/ares-fuzz.c | 0 .../test/ares-test-ai.h | 0 .../test/ares-test-fuzz-name.c | 0 .../test/ares-test-fuzz.c | 0 .../test/ares-test-init.cc | 0 .../test/ares-test-internal.cc | 7 +- .../test/ares-test-live.cc | 0 .../test/ares-test-main.cc | 0 .../test/ares-test-misc.cc | 2 +- .../test/ares-test-mock-ai.cc | 0 .../test/ares-test-mock.cc | 0 .../test/ares-test-ns.cc | 0 .../test/ares-test-parse-a.cc | 0 .../test/ares-test-parse-aaaa.cc | 0 .../test/ares-test-parse-caa.cc | 0 .../test/ares-test-parse-mx.cc | 0 .../test/ares-test-parse-naptr.cc | 0 .../test/ares-test-parse-ns.cc | 0 .../test/ares-test-parse-ptr.cc | 0 .../test/ares-test-parse-soa-any.cc | 0 .../test/ares-test-parse-soa.cc | 0 .../test/ares-test-parse-srv.cc | 0 .../test/ares-test-parse-txt.cc | 0 .../test/ares-test-parse-uri.cc | 0 .../test/ares-test-parse.cc | 0 .../test/ares-test.cc | 0 .../test/ares-test.h | 0 .../test/buildconf | 0 .../test/compile | 0 .../test/config.guess | 0 .../test/config.h.in | 0 .../test/config.sub | 0 .../test/configure | 1131 +++++++++++++---- .../test/configure.ac | 0 .../test/depcomp | 0 .../test/dns-dump.cc | 0 .../test/dns-proto-test.cc | 0 .../test/dns-proto.cc | 0 .../test/dns-proto.h | 0 .../test/fuzzcheck.sh | 0 .../004a216d3cff18b0c5c6b68b807f1529 | Bin .../00539467ca159b36aea95e61f9729115 | Bin .../00e846db8f43f2f507cd1666ed5a753e | Bin .../0177b7566f08c013699eaea9a77abeb3 | Bin .../020a4fa317715bfdb236ed13751e6b65 | Bin .../0310f2e81bea31f4fe3f330872a877dd | Bin .../0449be67df1730b2d0887d412a9b7cc4 | Bin .../0449dd14f7aa94bf0d716bfe09b287a8 | Bin .../04c93cdf7208979aa4df80a3a0d5a2d8 | Bin .../0567e7171e08e75f3f91c4ca74c17adc | Bin .../05ba948578a397e9cbc6a7b3e78622fa | Bin .../060afe5ed25f3e2e86167e545f27edca | Bin .../06d47d3681493f1b1d41236f460d896f | Bin .../0724a810b0e131c2fddb6de9003b9064 | Bin .../0b5279148826f5b962bcf1896bdb4ede | Bin .../114048c0f6b10bdc67ce9166405d195e | Bin .../11b8464a0ef8735d202955c34c36b0c7 | Bin .../11cb626f1668c7b41954ce7d768fe528 | Bin .../14b133bf18125b75a1976fa63a1df6b7 | Bin .../153c6b3afa8faa03c8bc28f936a6d4cf | Bin .../182cad2a342ed7317b7c21a5d17020d1 | Bin .../1c61a61bb7057b52c5b15188345a5238 | Bin .../1dbe2cf62ed2e4fa1c3cb473f08710b5 | Bin .../21199be504fcfece5c7096ee0dbba507 | Bin .../21891480074b5635dbbe7137bdcabccd | Bin .../233aea42e15aa73e131eefabf16088c9 | Bin .../24660d4e7ac7aa21d600ea7a3d198bbb | Bin .../25589deb55c08429345f289d1c9b0254 | Bin .../2573bd823e4da11f727a17f8e1f35c26 | Bin .../276f12da56866273e76059ad0e7be97e | Bin .../29198a2e380cb19babec9e02116d213e | Bin .../2c94ba9434b1a1b9396fc5364f101363 | Bin .../2d578c357dc2f5e02dc55cddb30641d1 | Bin .../2dff6cc5a223e67fde9e5e79af456992 | Bin .../2f103b1f9477f2d8934bd84328d51c75 | Bin .../31cd3a8413de13d9624adbb1613784bf | Bin .../36415bdf1d180098fe6234b4186e69f3 | Bin .../3a04a80f0242e8dff0cd732e7c4767da | Bin .../44d0f973b7b0fb3e4a07770c943dcd5a | Bin .../50bc00daa0ddcd6cfb2b5d9f62c81f47 | Bin .../51ed2d1fb77b3078b54e94e85606b7df | Bin .../5c5e0e899cf2e7d053a9e45fb76f6e5a | Bin .../70152ed033f139443fbfb1b858bb3b1b | Bin .../7030ca2b24e5a7f9dd8f62096a48eb33 | Bin .../71eec1a0ef2d25bb9e2ef17f23be7e9e | Bin .../7a6b0177210ea4ef40b254daf99393c5 | Bin .../7f1567733711ffb61839621af0cbfa33 | Bin .../850c6d57c5bb7be8205fc2438d14d7e5 | Bin .../a5c8cd2784a5792b9e91c2d7895b3b34 | Bin .../a9135cdc7151d023300ff194bad90af9 | Bin .../af2597e8ac7dec1e8b4a47518312912a | Bin .../test/fuzzinput/answer_a | Bin .../test/fuzzinput/answer_aaaa | Bin .../b3f53ef826b831bb09dd25c7f5960249 | Bin .../cda0f8751f5c4993974c2b549d29bcc8 | Bin .../ce6c26c0e469339873d0e7f616ab0945 | Bin .../fuzzinput/clusterfuzz-5637790584012800 | Bin .../fuzzinput/clusterfuzz-5650695891451904 | Bin .../fuzzinput/clusterfuzz-5651369832218624 | Bin .../fuzzinput/clusterfuzz-5674462260756480 | Bin .../fuzzinput/clusterfuzz-5680630672654336 | Bin .../fuzzinput/clusterfuzz-5683497160671232 | Bin .../fuzzinput/clusterfuzz-5687310655422464 | Bin .../fuzzinput/clusterfuzz-5695341573177344 | Bin .../fuzzinput/clusterfuzz-5697835103682560 | Bin .../fuzzinput/clusterfuzz-5728518081609728 | Bin .../fuzzinput/clusterfuzz-5732960017317888 | Bin .../e4dd7e7c2dd4ed7c2e17a6af5d04f9c9 | Bin .../ed50ed8ee36230a5a69746ad830437e5 | Bin .../f1b900d50806021953321c3b604ee497 | Bin .../f6606f624be8c628328cea01d2cd07a9 | Bin .../f89f6c8176b564a7dd646f14305573ce | Bin .../f9ad508d2dbd08d3aaaabc7d1174677d | Bin .../test/fuzzinput/multi-indir | Bin .../test/fuzznames/name01 | 0 .../test/fuzznames/name02 | 0 .../test/fuzznames/name03 | 0 .../test/fuzznames/name04 | 0 .../test/fuzznames/name05 | 0 .../test/fuzznames/name06 | 0 .../test/fuzznames/name07 | 0 .../test/fuzznames/name08 | 0 .../test/fuzznames/name09 | 0 .../test/gmock-1.11.0/gmock-gtest-all.cc | 0 .../test/gmock-1.11.0/gmock/gmock.h | 0 .../test/gmock-1.11.0/gtest/gtest.h | 0 .../test/install-sh | 0 .../test/ltmain.sh | 0 .../test/missing | 0 .../test/test-driver | 0 386 files changed, 3848 insertions(+), 1388 deletions(-) delete mode 100644 lib/c-ares-1.19.0/RELEASE-NOTES delete mode 100644 lib/c-ares-1.19.0/m4/ax_cxx_compile_stdcxx_11.m4 delete mode 100644 lib/c-ares-1.19.0/m4/ax_pthread.m4 rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/AUTHORS (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/CHANGES (96%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/CMakeLists.txt (98%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/CONTRIBUTING.md (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/INSTALL.md (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/LICENSE.md (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/Makefile.Watcom (67%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/Makefile.am (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/Makefile.dj (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/Makefile.in (99%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/Makefile.m32 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/Makefile.msvc (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/Makefile.netware (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/NEWS (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/README.cares (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/README.md (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/README.msvc (100%) create mode 100644 lib/c-ares-1.19.1/RELEASE-NOTES rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/SECURITY.md (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/TODO (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/acinclude.m4 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/aclocal.m4 (99%) rename lib/{c-ares-1.19.0/test => c-ares-1.19.1}/aminclude_static.am (99%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/buildconf (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/buildconf.bat (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/c-ares-config.cmake.in (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/compile (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/config.guess (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/config.sub (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/configure (98%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/configure.ac (98%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/depcomp (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/docs/CMakeLists.txt (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/docs/Makefile.am (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/docs/Makefile.in (99%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/docs/Makefile.inc (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/docs/acountry.1 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/docs/adig.1 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/docs/ahost.1 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/docs/ares_cancel.3 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/docs/ares_create_query.3 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/docs/ares_destroy.3 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/docs/ares_destroy_options.3 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/docs/ares_dup.3 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/docs/ares_expand_name.3 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/docs/ares_expand_string.3 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/docs/ares_fds.3 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/docs/ares_free_data.3 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/docs/ares_free_hostent.3 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/docs/ares_free_string.3 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/docs/ares_freeaddrinfo.3 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/docs/ares_get_servers.3 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/docs/ares_get_servers_ports.3 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/docs/ares_getaddrinfo.3 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/docs/ares_gethostbyaddr.3 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/docs/ares_gethostbyname.3 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/docs/ares_gethostbyname_file.3 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/docs/ares_getnameinfo.3 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/docs/ares_getsock.3 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/docs/ares_inet_ntop.3 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/docs/ares_inet_pton.3 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/docs/ares_init.3 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/docs/ares_init_options.3 (99%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/docs/ares_library_cleanup.3 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/docs/ares_library_init.3 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/docs/ares_library_init_android.3 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/docs/ares_library_initialized.3 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/docs/ares_mkquery.3 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/docs/ares_parse_a_reply.3 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/docs/ares_parse_aaaa_reply.3 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/docs/ares_parse_caa_reply.3 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/docs/ares_parse_mx_reply.3 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/docs/ares_parse_naptr_reply.3 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/docs/ares_parse_ns_reply.3 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/docs/ares_parse_ptr_reply.3 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/docs/ares_parse_soa_reply.3 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/docs/ares_parse_srv_reply.3 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/docs/ares_parse_txt_reply.3 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/docs/ares_parse_uri_reply.3 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/docs/ares_process.3 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/docs/ares_query.3 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/docs/ares_save_options.3 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/docs/ares_search.3 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/docs/ares_send.3 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/docs/ares_set_local_dev.3 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/docs/ares_set_local_ip4.3 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/docs/ares_set_local_ip6.3 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/docs/ares_set_servers.3 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/docs/ares_set_servers_csv.3 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/docs/ares_set_servers_ports.3 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/docs/ares_set_servers_ports_csv.3 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/docs/ares_set_socket_callback.3 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/docs/ares_set_socket_configure_callback.3 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/docs/ares_set_socket_functions.3 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/docs/ares_set_sortlist.3 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/docs/ares_strerror.3 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/docs/ares_timeout.3 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/docs/ares_version.3 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/get_ver.awk (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/include/CMakeLists.txt (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/include/Makefile.am (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/include/Makefile.in (99%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/include/ares.h (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/include/ares_build.h (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/include/ares_build.h.cmake (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/include/ares_build.h.in (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/include/ares_dns.h (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/include/ares_nameser.h (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/include/ares_rules.h (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/include/ares_version.h (90%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/install-sh (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/libcares.pc.cmake (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/libcares.pc.in (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/ltmain.sh (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/m4/ax_ac_append_to_file.m4 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/m4/ax_ac_print_to_file.m4 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/m4/ax_add_am_macro_static.m4 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/m4/ax_am_macros_static.m4 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/m4/ax_check_gnu_make.m4 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/m4/ax_check_user_namespace.m4 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/m4/ax_check_uts_namespace.m4 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/m4/ax_code_coverage.m4 (100%) create mode 100644 lib/c-ares-1.19.1/m4/ax_cxx_compile_stdcxx.m4 create mode 100644 lib/c-ares-1.19.1/m4/ax_cxx_compile_stdcxx_11.m4 rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/m4/ax_file_escapes.m4 (100%) create mode 100644 lib/c-ares-1.19.1/m4/ax_pthread.m4 rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/m4/ax_require_defined.m4 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/m4/cares-compilers.m4 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/m4/cares-confopts.m4 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/m4/cares-functions.m4 (97%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/m4/cares-reentrant.m4 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/m4/libtool.m4 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/m4/ltoptions.m4 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/m4/ltsugar.m4 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/m4/ltversion.m4 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/m4/lt~obsolete.m4 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/m4/xc-am-iface.m4 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/m4/xc-cc-check.m4 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/m4/xc-lt-iface.m4 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/m4/xc-translit.m4 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/m4/xc-val-flgs.m4 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/m4/zz40-xc-ovr.m4 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/maketgz (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/missing (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/msvc_ver.inc (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/CMakeLists.txt (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/Makefile.am (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/Makefile.in (99%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/CMakeLists.txt (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/Makefile.am (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/Makefile.in (98%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/Makefile.inc (97%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares__addrinfo2hostent.c (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares__addrinfo_localhost.c (99%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares__close_sockets.c (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares__get_hostent.c (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares__parse_into_addrinfo.c (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares__read_line.c (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares__readaddrinfo.c (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares__sortaddrinfo.c (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares__timeval.c (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares_android.c (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares_android.h (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares_cancel.c (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares_config.h.cmake (99%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares_config.h.in (99%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares_create_query.c (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares_data.c (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares_data.h (99%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares_destroy.c (97%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares_expand_name.c (98%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares_expand_string.c (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares_fds.c (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares_free_hostent.c (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares_free_string.c (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares_freeaddrinfo.c (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares_getaddrinfo.c (96%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares_getenv.c (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares_getenv.h (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares_gethostbyaddr.c (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares_gethostbyname.c (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares_getnameinfo.c (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares_getsock.c (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares_inet_net_pton.h (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares_init.c (96%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares_iphlpapi.h (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares_ipv6.h (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares_library_init.c (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares_llist.c (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares_llist.h (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares_mkquery.c (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares_nowarn.c (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares_nowarn.h (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares_options.c (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares_parse_a_reply.c (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares_parse_aaaa_reply.c (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares_parse_caa_reply.c (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares_parse_mx_reply.c (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares_parse_naptr_reply.c (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares_parse_ns_reply.c (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares_parse_ptr_reply.c (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares_parse_soa_reply.c (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares_parse_srv_reply.c (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares_parse_txt_reply.c (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares_parse_uri_reply.c (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares_platform.c (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares_platform.h (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares_private.h (97%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares_process.c (97%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares_query.c (84%) create mode 100644 lib/c-ares-1.19.1/src/lib/ares_rand.c rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares_search.c (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares_send.c (99%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares_setup.h (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares_strcasecmp.c (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares_strcasecmp.h (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares_strdup.c (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares_strdup.h (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares_strerror.c (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares_strsplit.c (93%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares_strsplit.h (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares_timeout.c (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares_version.c (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares_writev.c (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/ares_writev.h (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/bitncmp.c (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/bitncmp.h (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/cares.rc (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/config-dos.h (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/config-win32.h (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/inet_net_pton.c (73%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/inet_ntop.c (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/setup_once.h (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/lib/windows_port.c (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/tools/CMakeLists.txt (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/tools/Makefile.am (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/tools/Makefile.in (99%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/tools/Makefile.inc (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/tools/acountry.c (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/tools/adig.c (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/tools/ahost.c (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/tools/ares_getopt.c (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/src/tools/ares_getopt.h (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/CMakeLists.txt (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/Makefile.am (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/Makefile.in (99%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/Makefile.inc (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/Makefile.m32 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/Makefile.msvc (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/README.md (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/aclocal.m4 (99%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1/test}/aminclude_static.am (99%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/ares-fuzz.c (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/ares-test-ai.h (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/ares-test-fuzz-name.c (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/ares-test-fuzz.c (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/ares-test-init.cc (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/ares-test-internal.cc (98%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/ares-test-live.cc (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/ares-test-main.cc (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/ares-test-misc.cc (99%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/ares-test-mock-ai.cc (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/ares-test-mock.cc (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/ares-test-ns.cc (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/ares-test-parse-a.cc (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/ares-test-parse-aaaa.cc (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/ares-test-parse-caa.cc (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/ares-test-parse-mx.cc (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/ares-test-parse-naptr.cc (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/ares-test-parse-ns.cc (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/ares-test-parse-ptr.cc (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/ares-test-parse-soa-any.cc (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/ares-test-parse-soa.cc (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/ares-test-parse-srv.cc (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/ares-test-parse-txt.cc (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/ares-test-parse-uri.cc (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/ares-test-parse.cc (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/ares-test.cc (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/ares-test.h (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/buildconf (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/compile (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/config.guess (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/config.h.in (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/config.sub (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/configure (95%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/configure.ac (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/depcomp (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/dns-dump.cc (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/dns-proto-test.cc (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/dns-proto.cc (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/dns-proto.h (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzcheck.sh (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/004a216d3cff18b0c5c6b68b807f1529 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/00539467ca159b36aea95e61f9729115 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/00e846db8f43f2f507cd1666ed5a753e (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/0177b7566f08c013699eaea9a77abeb3 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/020a4fa317715bfdb236ed13751e6b65 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/0310f2e81bea31f4fe3f330872a877dd (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/0449be67df1730b2d0887d412a9b7cc4 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/0449dd14f7aa94bf0d716bfe09b287a8 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/04c93cdf7208979aa4df80a3a0d5a2d8 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/0567e7171e08e75f3f91c4ca74c17adc (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/05ba948578a397e9cbc6a7b3e78622fa (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/060afe5ed25f3e2e86167e545f27edca (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/06d47d3681493f1b1d41236f460d896f (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/0724a810b0e131c2fddb6de9003b9064 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/0b5279148826f5b962bcf1896bdb4ede (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/114048c0f6b10bdc67ce9166405d195e (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/11b8464a0ef8735d202955c34c36b0c7 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/11cb626f1668c7b41954ce7d768fe528 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/14b133bf18125b75a1976fa63a1df6b7 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/153c6b3afa8faa03c8bc28f936a6d4cf (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/182cad2a342ed7317b7c21a5d17020d1 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/1c61a61bb7057b52c5b15188345a5238 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/1dbe2cf62ed2e4fa1c3cb473f08710b5 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/21199be504fcfece5c7096ee0dbba507 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/21891480074b5635dbbe7137bdcabccd (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/233aea42e15aa73e131eefabf16088c9 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/24660d4e7ac7aa21d600ea7a3d198bbb (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/25589deb55c08429345f289d1c9b0254 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/2573bd823e4da11f727a17f8e1f35c26 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/276f12da56866273e76059ad0e7be97e (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/29198a2e380cb19babec9e02116d213e (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/2c94ba9434b1a1b9396fc5364f101363 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/2d578c357dc2f5e02dc55cddb30641d1 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/2dff6cc5a223e67fde9e5e79af456992 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/2f103b1f9477f2d8934bd84328d51c75 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/31cd3a8413de13d9624adbb1613784bf (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/36415bdf1d180098fe6234b4186e69f3 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/3a04a80f0242e8dff0cd732e7c4767da (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/44d0f973b7b0fb3e4a07770c943dcd5a (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/50bc00daa0ddcd6cfb2b5d9f62c81f47 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/51ed2d1fb77b3078b54e94e85606b7df (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/5c5e0e899cf2e7d053a9e45fb76f6e5a (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/70152ed033f139443fbfb1b858bb3b1b (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/7030ca2b24e5a7f9dd8f62096a48eb33 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/71eec1a0ef2d25bb9e2ef17f23be7e9e (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/7a6b0177210ea4ef40b254daf99393c5 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/7f1567733711ffb61839621af0cbfa33 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/850c6d57c5bb7be8205fc2438d14d7e5 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/a5c8cd2784a5792b9e91c2d7895b3b34 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/a9135cdc7151d023300ff194bad90af9 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/af2597e8ac7dec1e8b4a47518312912a (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/answer_a (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/answer_aaaa (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/b3f53ef826b831bb09dd25c7f5960249 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/cda0f8751f5c4993974c2b549d29bcc8 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/ce6c26c0e469339873d0e7f616ab0945 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/clusterfuzz-5637790584012800 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/clusterfuzz-5650695891451904 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/clusterfuzz-5651369832218624 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/clusterfuzz-5674462260756480 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/clusterfuzz-5680630672654336 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/clusterfuzz-5683497160671232 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/clusterfuzz-5687310655422464 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/clusterfuzz-5695341573177344 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/clusterfuzz-5697835103682560 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/clusterfuzz-5728518081609728 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/clusterfuzz-5732960017317888 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/e4dd7e7c2dd4ed7c2e17a6af5d04f9c9 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/ed50ed8ee36230a5a69746ad830437e5 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/f1b900d50806021953321c3b604ee497 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/f6606f624be8c628328cea01d2cd07a9 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/f89f6c8176b564a7dd646f14305573ce (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/f9ad508d2dbd08d3aaaabc7d1174677d (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzzinput/multi-indir (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzznames/name01 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzznames/name02 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzznames/name03 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzznames/name04 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzznames/name05 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzznames/name06 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzznames/name07 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzznames/name08 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/fuzznames/name09 (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/gmock-1.11.0/gmock-gtest-all.cc (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/gmock-1.11.0/gmock/gmock.h (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/gmock-1.11.0/gtest/gtest.h (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/install-sh (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/ltmain.sh (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/missing (100%) rename lib/{c-ares-1.19.0 => c-ares-1.19.1}/test/test-driver (100%) diff --git a/cmake/libraries.cmake b/cmake/libraries.cmake index 098b4dba191..832d2da6e4a 100644 --- a/cmake/libraries.cmake +++ b/cmake/libraries.cmake @@ -19,7 +19,7 @@ set(FLB_PATH_LIB_ONIGMO "lib/onigmo") set(FLB_PATH_LIB_MPACK "lib/mpack-amalgamation-1.1") set(FLB_PATH_LIB_MINIZ "lib/miniz") set(FLB_PATH_LIB_TUTF8E "lib/tutf8e") -set(FLB_PATH_LIB_CARES "lib/c-ares-1.19.0") +set(FLB_PATH_LIB_CARES "lib/c-ares-1.19.1") set(FLB_PATH_LIB_SNAPPY "lib/snappy-fef67ac") set(FLB_PATH_LIB_RDKAFKA "lib/librdkafka-2.1.0") set(FLB_PATH_LIB_RING_BUFFER "lib/lwrb") diff --git a/lib/c-ares-1.19.0/RELEASE-NOTES b/lib/c-ares-1.19.0/RELEASE-NOTES deleted file mode 100644 index db705905bae..00000000000 --- a/lib/c-ares-1.19.0/RELEASE-NOTES +++ /dev/null @@ -1,91 +0,0 @@ -c-ares version 1.19.0 - -This is a feature and bugfix release. It addresses a couple of new feature -requests as well as a couple of bug fixes. - -Security: - o Low. Stack overflow in ares_set_sortlist() which is used during c-ares - initialization and typically provided by an administrator and not an - end user. [24] - -Changes: - o Windows: Drop support for XP and derivatives which greatly cleans up - initialization code. [3] - o Add ARES_OPT_HOSTS_FILE similar to ARES_OPT_RESOLVCONF for specifying a - custom hosts file location. [10] - o Add vcpkg installation instructions [13] - -Bug fixes: - o Fix cross-compilation from Windows to Linux due to CPACK logic. [1] - o Fix memory leak in reading /etc/hosts when using localhost fallback. [2] - o Fix chain building c-ares when libresolv is already included by another - project [4] - o File lookup should not immediately abort as there may be other tries due to - search criteria. - o Asterisks should be allowed in host validation as CNAMEs may reference - wildcard domains [5] - o AutoTools build system referenced bad STDC_HEADERS macro [6] - o Even if one address class returns a failure for ares_getaddrinfo() we should - still return the results we have - o CMake Windows: DLLs did not include resource file to include versions [7] [8] - o CMake: Guard target creation in exported config [9] - o Fix ares_getaddrinfo() numerical address resolution with AF_UNSPEC [11] - o Apple: fix libresolv configured query times. [12] - o Fix tools and help information [14] [15] - o Various documentation fixes and cleanups [16] [22] [25] - o Add include guards to ares_data.h [17] - o c-ares could try to exceed maximum number of iovec entries supported by - system [18] - o CMake package config generation allow for absolute install paths [19] - o Intel compiler fixes [20] - o ares_strsplit bugs [21] [23] - o The RFC6761 6.3 states localhost subdomains must be offline too. [26] - -Thanks go to these friendly people for their efforts and contributions: - Boby Reynolds (@reynoldsbd) - Brad House (@bradh352) - Brad Spencer (@b-spencer) - @bsergean - Daniel Stenberg (@bagder) - Dmitry Karpov - @FrankXie05 - @hopper-vul - Jonathan Ringer (@jonringer) - Kai Pastor (@dg0yt) - @lifenjoiner - Manish Mehra (@mmehra) - @marc-groundctl - Nikolaos Chatzikonstantinou (@createyourpersonalaccount) - Ridge Kennedy (@ridgek) - Sam James (@thesamesam) - Stephen Sachs (@stephenmsachs) - Thomas Dreibholz (@dreibh) -(18 contributors) - -References to bug reports and discussions on issues: - [1] = https://github.com/c-ares/c-ares/pull/436 - [2] = https://github.com/c-ares/c-ares/issues/439 - [3] = https://github.com/c-ares/c-ares/pull/445 - [4] = https://github.com/c-ares/c-ares/pull/451 - [5] = https://github.com/c-ares/c-ares/issues/457 - [6] = https://github.com/c-ares/c-ares/pull/459 - [7] = https://github.com/c-ares/c-ares/issues/460 - [8] = https://github.com/c-ares/c-ares/pull/468 - [9] = https://github.com/c-ares/c-ares/pull/464 - [10] = https://github.com/c-ares/c-ares/pull/465 - [11] = https://github.com/c-ares/c-ares/pull/469 - [12] = https://github.com/c-ares/c-ares/pull/467 - [13] = https://github.com/c-ares/c-ares/pull/478 - [14] = https://github.com/c-ares/c-ares/pull/479 - [15] = https://github.com/c-ares/c-ares/pull/481 - [16] = https://github.com/c-ares/c-ares/pull/490 - [17] = https://github.com/c-ares/c-ares/pull/491 - [18] = https://github.com/c-ares/c-ares/pull/489 - [19] = https://github.com/c-ares/c-ares/pull/486 - [20] = https://github.com/c-ares/c-ares/pull/485 - [21] = https://github.com/c-ares/c-ares/pull/492 - [22] = https://github.com/c-ares/c-ares/pull/494 - [23] = https://github.com/c-ares/c-ares/pull/495 - [24] = https://github.com/c-ares/c-ares/pull/497 - [25] = https://github.com/c-ares/c-ares/issues/487 - [26] = https://github.com/c-ares/c-ares/issues/477 diff --git a/lib/c-ares-1.19.0/m4/ax_cxx_compile_stdcxx_11.m4 b/lib/c-ares-1.19.0/m4/ax_cxx_compile_stdcxx_11.m4 deleted file mode 100644 index fe4a11c67e0..00000000000 --- a/lib/c-ares-1.19.0/m4/ax_cxx_compile_stdcxx_11.m4 +++ /dev/null @@ -1,166 +0,0 @@ -# ============================================================================ -# http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_11.html -# ============================================================================ -# -# SYNOPSIS -# -# AX_CXX_COMPILE_STDCXX_11([ext|noext],[mandatory|optional]) -# -# DESCRIPTION -# -# Check for baseline language coverage in the compiler for the C++11 -# standard; if necessary, add switches to CXXFLAGS to enable support. -# -# The first argument, if specified, indicates whether you insist on an -# extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g. -# -std=c++11). If neither is specified, you get whatever works, with -# preference for an extended mode. -# -# The second argument, if specified 'mandatory' or if left unspecified, -# indicates that baseline C++11 support is required and that the macro -# should error out if no mode with that support is found. If specified -# 'optional', then configuration proceeds regardless, after defining -# HAVE_CXX11 if and only if a supporting mode is found. -# -# LICENSE -# -# Copyright (c) 2008 Benjamin Kosnik -# Copyright (c) 2012 Zack Weinberg -# Copyright (c) 2013 Roy Stogner -# Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov -# -# Copying and distribution of this file, with or without modification, are -# permitted in any medium without royalty provided the copyright notice -# and this notice are preserved. This file is offered as-is, without any -# warranty. - -#serial 9 - -m4_define([_AX_CXX_COMPILE_STDCXX_11_testbody], [[ - -#define static_assert _Static_assert - - template - struct check - { - static_assert(sizeof(int) <= sizeof(T), "not big enough"); - }; - - struct Base { - virtual void f() {} - }; - struct Child : public Base { - virtual void f() override {} - }; - - typedef check> right_angle_brackets; - - int a; - decltype(a) b; - - typedef check check_type; - check_type c; - check_type&& cr = static_cast(c); - - auto d = a; - auto l = [](){}; - - // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae - // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function because of this - namespace test_template_alias_sfinae { - struct foo {}; - - template - using member = typename T::member_type; - - template - void func(...) {} - - template - void func(member*) {} - - void test(); - - void test() { - func(0); - } - } -]]) - -AC_DEFUN([AX_CXX_COMPILE_STDCXX_11], [dnl - m4_if([$1], [], [], - [$1], [ext], [], - [$1], [noext], [], - [m4_fatal([invalid argument `$1' to AX_CXX_COMPILE_STDCXX_11])])dnl - m4_if([$2], [], [ax_cxx_compile_cxx11_required=true], - [$2], [mandatory], [ax_cxx_compile_cxx11_required=true], - [$2], [optional], [ax_cxx_compile_cxx11_required=false], - [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX_11])]) - AC_LANG_PUSH([C++])dnl - ac_success=no - AC_CACHE_CHECK(whether $CXX supports C++11 features by default, - ax_cv_cxx_compile_cxx11, - [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])], - [ax_cv_cxx_compile_cxx11=yes], - [ax_cv_cxx_compile_cxx11=no])]) - if test x$ax_cv_cxx_compile_cxx11 = xyes; then - ac_success=yes - fi - - m4_if([$1], [noext], [], [dnl - if test x$ac_success = xno; then - for switch in -std=gnu++11 -std=gnu++0x; do - cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch]) - AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch, - $cachevar, - [ac_save_CXXFLAGS="$CXXFLAGS" - CXXFLAGS="$CXXFLAGS $switch" - AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])], - [eval $cachevar=yes], - [eval $cachevar=no]) - CXXFLAGS="$ac_save_CXXFLAGS"]) - if eval test x\$$cachevar = xyes; then - CXXFLAGS="$CXXFLAGS $switch" - ac_success=yes - break - fi - done - fi]) - - m4_if([$1], [ext], [], [dnl - if test x$ac_success = xno; then - for switch in -std=c++11 -std=c++0x; do - cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch]) - AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch, - $cachevar, - [ac_save_CXXFLAGS="$CXXFLAGS" - CXXFLAGS="$CXXFLAGS $switch" - AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])], - [eval $cachevar=yes], - [eval $cachevar=no]) - CXXFLAGS="$ac_save_CXXFLAGS"]) - if eval test x\$$cachevar = xyes; then - CXXFLAGS="$CXXFLAGS $switch" - ac_success=yes - break - fi - done - fi]) - AC_LANG_POP([C++]) - if test x$ax_cxx_compile_cxx11_required = xtrue; then - if test x$ac_success = xno; then - AC_MSG_ERROR([*** A compiler with support for C++11 language features is required.]) - fi - else - if test x$ac_success = xno; then - HAVE_CXX11=0 - AC_MSG_NOTICE([No compiler with C++11 support was found]) - else - HAVE_CXX11=1 - AC_DEFINE(HAVE_CXX11,1, - [define if the compiler supports basic C++11 syntax]) - fi - - AC_SUBST(HAVE_CXX11) - fi -]) diff --git a/lib/c-ares-1.19.0/m4/ax_pthread.m4 b/lib/c-ares-1.19.0/m4/ax_pthread.m4 deleted file mode 100644 index d383ad5c6d6..00000000000 --- a/lib/c-ares-1.19.0/m4/ax_pthread.m4 +++ /dev/null @@ -1,332 +0,0 @@ -# =========================================================================== -# http://www.gnu.org/software/autoconf-archive/ax_pthread.html -# =========================================================================== -# -# SYNOPSIS -# -# AX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) -# -# DESCRIPTION -# -# This macro figures out how to build C programs using POSIX threads. It -# sets the PTHREAD_LIBS output variable to the threads library and linker -# flags, and the PTHREAD_CFLAGS output variable to any special C compiler -# flags that are needed. (The user can also force certain compiler -# flags/libs to be tested by setting these environment variables.) -# -# Also sets PTHREAD_CC to any special C compiler that is needed for -# multi-threaded programs (defaults to the value of CC otherwise). (This -# is necessary on AIX to use the special cc_r compiler alias.) -# -# NOTE: You are assumed to not only compile your program with these flags, -# but also link it with them as well. e.g. you should link with -# $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS -# -# If you are only building threads programs, you may wish to use these -# variables in your default LIBS, CFLAGS, and CC: -# -# LIBS="$PTHREAD_LIBS $LIBS" -# CFLAGS="$CFLAGS $PTHREAD_CFLAGS" -# CC="$PTHREAD_CC" -# -# In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant -# has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to that name -# (e.g. PTHREAD_CREATE_UNDETACHED on AIX). -# -# Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the -# PTHREAD_PRIO_INHERIT symbol is defined when compiling with -# PTHREAD_CFLAGS. -# -# ACTION-IF-FOUND is a list of shell commands to run if a threads library -# is found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it -# is not found. If ACTION-IF-FOUND is not specified, the default action -# will define HAVE_PTHREAD. -# -# Please let the authors know if this macro fails on any platform, or if -# you have any other suggestions or comments. This macro was based on work -# by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) (with help -# from M. Frigo), as well as ac_pthread and hb_pthread macros posted by -# Alejandro Forero Cuervo to the autoconf macro repository. We are also -# grateful for the helpful feedback of numerous users. -# -# Updated for Autoconf 2.68 by Daniel Richard G. -# -# LICENSE -# -# Copyright (c) 2008 Steven G. Johnson -# Copyright (c) 2011 Daniel Richard G. -# -# This program is free software: you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by the -# Free Software Foundation, either version 3 of the License, or (at your -# option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General -# Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program. If not, see . -# -# As a special exception, the respective Autoconf Macro's copyright owner -# gives unlimited permission to copy, distribute and modify the configure -# scripts that are the output of Autoconf when processing the Macro. You -# need not follow the terms of the GNU General Public License when using -# or distributing such scripts, even though portions of the text of the -# Macro appear in them. The GNU General Public License (GPL) does govern -# all other use of the material that constitutes the Autoconf Macro. -# -# This special exception to the GPL applies to versions of the Autoconf -# Macro released by the Autoconf Archive. When you make and distribute a -# modified version of the Autoconf Macro, you may extend this special -# exception to the GPL to apply to your modified version as well. - -#serial 21 - -AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD]) -AC_DEFUN([AX_PTHREAD], [ -AC_REQUIRE([AC_CANONICAL_HOST]) -AC_LANG_PUSH([C]) -ax_pthread_ok=no - -# We used to check for pthread.h first, but this fails if pthread.h -# requires special compiler flags (e.g. on True64 or Sequent). -# It gets checked for in the link test anyway. - -# First of all, check if the user has set any of the PTHREAD_LIBS, -# etcetera environment variables, and if threads linking works using -# them: -if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then - save_CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS $PTHREAD_CFLAGS" - save_LIBS="$LIBS" - LIBS="$PTHREAD_LIBS $LIBS" - AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS]) - AC_TRY_LINK_FUNC([pthread_join], [ax_pthread_ok=yes]) - AC_MSG_RESULT([$ax_pthread_ok]) - if test x"$ax_pthread_ok" = xno; then - PTHREAD_LIBS="" - PTHREAD_CFLAGS="" - fi - LIBS="$save_LIBS" - CFLAGS="$save_CFLAGS" -fi - -# We must check for the threads library under a number of different -# names; the ordering is very important because some systems -# (e.g. DEC) have both -lpthread and -lpthreads, where one of the -# libraries is broken (non-POSIX). - -# Create a list of thread flags to try. Items starting with a "-" are -# C compiler flags, and other items are library names, except for "none" -# which indicates that we try without any flags at all, and "pthread-config" -# which is a program returning the flags for the Pth emulation library. - -ax_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" - -# The ordering *is* (sometimes) important. Some notes on the -# individual items follow: - -# pthreads: AIX (must check this before -lpthread) -# none: in case threads are in libc; should be tried before -Kthread and -# other compiler flags to prevent continual compiler warnings -# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) -# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) -# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) -# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads) -# -pthreads: Solaris/gcc -# -mthreads: Mingw32/gcc, Lynx/gcc -# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it -# doesn't hurt to check since this sometimes defines pthreads too; -# also defines -D_REENTRANT) -# ... -mt is also the pthreads flag for HP/aCC -# pthread: Linux, etcetera -# --thread-safe: KAI C++ -# pthread-config: use pthread-config program (for GNU Pth library) - -case ${host_os} in - solaris*) - - # On Solaris (at least, for some versions), libc contains stubbed - # (non-functional) versions of the pthreads routines, so link-based - # tests will erroneously succeed. (We need to link with -pthreads/-mt/ - # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather - # a function called by this macro, so we could check for that, but - # who knows whether they'll stub that too in a future libc.) So, - # we'll just look for -pthreads and -lpthread first: - - ax_pthread_flags="-pthreads pthread -mt -pthread $ax_pthread_flags" - ;; - - darwin*) - ax_pthread_flags="-pthread $ax_pthread_flags" - ;; -esac - -# Clang doesn't consider unrecognized options an error unless we specify -# -Werror. We throw in some extra Clang-specific options to ensure that -# this doesn't happen for GCC, which also accepts -Werror. - -AC_MSG_CHECKING([if compiler needs -Werror to reject unknown flags]) -save_CFLAGS="$CFLAGS" -ax_pthread_extra_flags="-Werror" -CFLAGS="$CFLAGS $ax_pthread_extra_flags -Wunknown-warning-option -Wsizeof-array-argument" -AC_COMPILE_IFELSE([AC_LANG_PROGRAM([int foo(void);],[foo()])], - [AC_MSG_RESULT([yes])], - [ax_pthread_extra_flags= - AC_MSG_RESULT([no])]) -CFLAGS="$save_CFLAGS" - -if test x"$ax_pthread_ok" = xno; then -for flag in $ax_pthread_flags; do - - case $flag in - none) - AC_MSG_CHECKING([whether pthreads work without any flags]) - ;; - - -*) - AC_MSG_CHECKING([whether pthreads work with $flag]) - PTHREAD_CFLAGS="$flag" - ;; - - pthread-config) - AC_CHECK_PROG([ax_pthread_config], [pthread-config], [yes], [no]) - if test x"$ax_pthread_config" = xno; then continue; fi - PTHREAD_CFLAGS="`pthread-config --cflags`" - PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" - ;; - - *) - AC_MSG_CHECKING([for the pthreads library -l$flag]) - PTHREAD_LIBS="-l$flag" - ;; - esac - - save_LIBS="$LIBS" - save_CFLAGS="$CFLAGS" - LIBS="$PTHREAD_LIBS $LIBS" - CFLAGS="$CFLAGS $PTHREAD_CFLAGS $ax_pthread_extra_flags" - - # Check for various functions. We must include pthread.h, - # since some functions may be macros. (On the Sequent, we - # need a special flag -Kthread to make this header compile.) - # We check for pthread_join because it is in -lpthread on IRIX - # while pthread_create is in libc. We check for pthread_attr_init - # due to DEC craziness with -lpthreads. We check for - # pthread_cleanup_push because it is one of the few pthread - # functions on Solaris that doesn't have a non-functional libc stub. - # We try pthread_create on general principles. - AC_LINK_IFELSE([AC_LANG_PROGRAM([#include - static void routine(void *a) { a = 0; } - static void *start_routine(void *a) { return a; }], - [pthread_t th; pthread_attr_t attr; - pthread_create(&th, 0, start_routine, 0); - pthread_join(th, 0); - pthread_attr_init(&attr); - pthread_cleanup_push(routine, 0); - pthread_cleanup_pop(0) /* ; */])], - [ax_pthread_ok=yes], - []) - - LIBS="$save_LIBS" - CFLAGS="$save_CFLAGS" - - AC_MSG_RESULT([$ax_pthread_ok]) - if test "x$ax_pthread_ok" = xyes; then - break; - fi - - PTHREAD_LIBS="" - PTHREAD_CFLAGS="" -done -fi - -# Various other checks: -if test "x$ax_pthread_ok" = xyes; then - save_LIBS="$LIBS" - LIBS="$PTHREAD_LIBS $LIBS" - save_CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS $PTHREAD_CFLAGS" - - # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. - AC_MSG_CHECKING([for joinable pthread attribute]) - attr_name=unknown - for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do - AC_LINK_IFELSE([AC_LANG_PROGRAM([#include ], - [int attr = $attr; return attr /* ; */])], - [attr_name=$attr; break], - []) - done - AC_MSG_RESULT([$attr_name]) - if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then - AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE], [$attr_name], - [Define to necessary symbol if this constant - uses a non-standard name on your system.]) - fi - - AC_MSG_CHECKING([if more special flags are required for pthreads]) - flag=no - case ${host_os} in - aix* | freebsd* | darwin*) flag="-D_THREAD_SAFE";; - osf* | hpux*) flag="-D_REENTRANT";; - solaris*) - if test "$GCC" = "yes"; then - flag="-D_REENTRANT" - else - # TODO: What about Clang on Solaris? - flag="-mt -D_REENTRANT" - fi - ;; - esac - AC_MSG_RESULT([$flag]) - if test "x$flag" != xno; then - PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" - fi - - AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT], - [ax_cv_PTHREAD_PRIO_INHERIT], [ - AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], - [[int i = PTHREAD_PRIO_INHERIT;]])], - [ax_cv_PTHREAD_PRIO_INHERIT=yes], - [ax_cv_PTHREAD_PRIO_INHERIT=no]) - ]) - AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes"], - [AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.])]) - - LIBS="$save_LIBS" - CFLAGS="$save_CFLAGS" - - # More AIX lossage: compile with *_r variant - if test "x$GCC" != xyes; then - case $host_os in - aix*) - AS_CASE(["x/$CC"], - [x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6], - [#handle absolute path differently from PATH based program lookup - AS_CASE(["x$CC"], - [x/*], - [AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"])], - [AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])])]) - ;; - esac - fi -fi - -test -n "$PTHREAD_CC" || PTHREAD_CC="$CC" - -AC_SUBST([PTHREAD_LIBS]) -AC_SUBST([PTHREAD_CFLAGS]) -AC_SUBST([PTHREAD_CC]) - -# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: -if test x"$ax_pthread_ok" = xyes; then - ifelse([$1],,[AC_DEFINE([HAVE_PTHREAD],[1],[Define if you have POSIX threads libraries and header files.])],[$1]) - : -else - ax_pthread_ok=no - $2 -fi -AC_LANG_POP -])dnl AX_PTHREAD diff --git a/lib/c-ares-1.19.0/AUTHORS b/lib/c-ares-1.19.1/AUTHORS similarity index 100% rename from lib/c-ares-1.19.0/AUTHORS rename to lib/c-ares-1.19.1/AUTHORS diff --git a/lib/c-ares-1.19.0/CHANGES b/lib/c-ares-1.19.1/CHANGES similarity index 96% rename from lib/c-ares-1.19.0/CHANGES rename to lib/c-ares-1.19.1/CHANGES index 5ecd504f063..d465143131d 100644 --- a/lib/c-ares-1.19.0/CHANGES +++ b/lib/c-ares-1.19.1/CHANGES @@ -1,5 +1,232 @@ Changelog for the c-ares project. Generated with git2changes.pl +Version 1.19.1 (22 May 2023) + +bradh352 (22 May 2023) +- Makefile.inc Windows requires tabs not spaces for nmake + +GitHub (22 May 2023) +- [Daniel Stenberg brought this change] + + ares_expand_name: fix compiler warnings (#522) + + Fix some compiler warnings (not introduced in this release) + + Fix By: Daniel Stenberg (@bagder) + +bradh352 (22 May 2023) +- windows MSVC compiler fix on 32bit + +- update security advisory links + +- minor CI issues fixes for imported inet_net_pton + +- ares_rand static analysis fixes from CI + +- windows build fix + +- security release notes + +GitHub (22 May 2023) +- [Brad House brought this change] + + Merge pull request from GHSA-9g78-jv2r-p7vc + +- [Brad House brought this change] + + Merge pull request from GHSA-x6mf-cxr9-8q6v + + * Merged latest OpenBSD changes for inet_net_pton_ipv6() into c-ares. + * Always use our own IP conversion functions now, do not delegate to OS + so we can have consistency in testing and fuzzing. + * Removed bogus test cases that never should have passed. + * Add new test case for crash bug found. + + Fix By: Brad House (@bradh352) + +- [Brad House brought this change] + + Merge pull request from GHSA-8r8p-23f3-64c2 + + * segment random number generation into own file + + * abstract random code to make it more modular so we can have multiple backends + + * rand: add support for arc4random_buf() and also direct CARES_RANDOM_FILE reading + + * autotools: fix detection of arc4random_buf + + * rework initial rc4 seed for PRNG as last fallback + + * rc4: more proper implementation, simplified for clarity + + * clarifications + +bradh352 (20 May 2023) +- add public release note information + +- bump version to 1.19.1 + +GitHub (6 May 2023) +- [Gregor Jasny brought this change] + + test: fix warning about uninitialized memory (#515) + + fix warning in tests + + Fix By: Gregor Jasny (@gjasny) + +- [lifenjoiner brought this change] + + Turn off IPV6_V6ONLY on Windows if it is supported (#520) + + Turn off IPV6_V6ONLY on Windows if it is supported, support for IPv4-mapped IPv6 addresses. + + IPV6_V6ONLY refs: + https://en.wikipedia.org/wiki/IPv6#IPv4-mapped_IPv6_addresses + https://github.com/golang/go/blob/master/src/net/ipsock_posix.go + https://en.wikipedia.org/wiki/Unix-like + off: + https://www.kernel.org/doc/html/latest/networking/ip-sysctl.html#proc-sys-net-ipv6-variables + https://man.netbsd.org/inet6.4 + https://man.freebsd.org/cgi/man.cgi?query=inet6 + https://github.com/apple-oss-distributions/xnu/blob/main/bsd/man/man4/inet6.4 + on: + https://learn.microsoft.com/en-us/windows/win32/winsock/ipproto-ipv6-socket-options + acts like off, but returns 1 and dummy setting: + https://man.dragonflybsd.org/?command=inet6 + https://man.dragonflybsd.org/?command=ip6 + unsupported and read-only returns 1: + https://man.openbsd.org/inet6.4 + + default value refs: + https://datatracker.ietf.org/doc/html/rfc3493#section-5.3 + https://www.kernel.org/doc/html/latest/networking/ip-sysctl.html#proc-sys-net-ipv6-variables + +- [Brad House brought this change] + + Merge pull request from GHSA-54xr-f67r-4pc4 + + * CARES_RANDOM_FILE should always default to /dev/urandom + + During cross-compilation, CARES_RANDOM_FILE may not be able to be appropriately + detected, therefore we should always set it to /dev/urandom and allow the + entity requesting compilation override the value. The code does appropriately + fall back if CARES_RANDOM_FILE cannot be opened. + + * use set not option + +bradh352 (18 Mar 2023) +- ares_getaddrinfo using service of "0" should be allowed + + As per #517 glibc allows a service/servname of "0" to be treated the + same as if NULL was provided. Also, add a sanity check to ensure + the port number is in range instead of a blind cast. + + Fixes: #517 + Fix By: Brad House (@bradh352) + +GitHub (10 Feb 2023) +- [Nikolaos Chatzikonstantinou brought this change] + + fix memory leak in ares_send (#511) + + When the condition channel->nservers < 1 holds, the function returns + prematurely, without deallocating query->tcpbuf. We rearrange the + check to be done prior to the allocations, avoiding the memory + leak. In this way, we also avoid unnecessary allocations if + channel->nservers < 1 holds. + + Fix By: Nikolaos Chatzikonstantinou (@createyourpersonalaccount) + +- [Nikolaos Chatzikonstantinou brought this change] + + change comment style to old-style (#513) + + Following the README.md guidelines, + + "Comments must be written in the old-style" + + the comment is changed to the old style. + + Fix By: Nikolaos Chatzikonstantinou (@createyourpersonalaccount) + +- [Nikolaos Chatzikonstantinou brought this change] + + use strncasecmp in ares__strsplit (#512) + + strncasecmp on platforms that don't already have it is already #define'd to a private implementation. There is no need to have OS-specific logic. Also removes ares__strsplit.h as a header as ares_private.h already includes it. + + Fix By: Nikolaos Chatzikonstantinou (@createyourpersonalaccount) + +- [Yijie Ma brought this change] + + Fix a typo in ares_init_options.3 (#510) + + that -> than + + Fix By: Yijie Ma (@yijiem) + +- [Douglas R. Reno brought this change] + + Watcom Portability Improvements (#509) + + - Modify the Watcom Makefile for the source code reorganization (#352) + - Add *.map files into .gitignore + - Fix build errors with Watcom's builtin Windows SDK (which is rather + outdated). It's smart enough to understand Windows Vista, but doesn't + have PMIB_UNICASTIPADDRESS_TABLE or MIB_IPFORWARD_ROW2. + + It may be possible to use a different Windows SDK with the Watcom + compiler, such as the most recent Windows 10 SDK. Alternatively the SDK + in OpenWatcom 2.0 (which is in development) should fix this. + + I have no problems testing this Makefile prior to releases, just give me + a ping. + + Tested with Windows Vista, Windows 7, and Windows 10 using 'adig', + 'acountry', and 'ahost'. This also seems to work on Windows XP, though + this is likely due to the compiler in use. + + Fix By: Douglas R. Reno (@renodr) + Fixes Bug: #352 + +- [Jay Freeman (saurik) brought this change] + + ignore aminclude_static.am, as generated by AX_AM_MACROS_STATIC (#508) + + Fix By: Jay Freeman (@saurik) + +- [Jay Freeman (saurik) brought this change] + + sync ax_pthread.m4 with upstream (#507) + + The version in the repository is many years old so this PR simply pulls in the latest + available revision from: + http://git.savannah.gnu.org/gitweb/?p=autoconf-archive.git;a=tree;f=m4 + + Fix By: Jay Freeman (@saurik) + +- [Chilledheart brought this change] + + Windows: Invalid stack variable out of scope for HOSTS file path (#502) + + In some conditions Windows might try to use a stack address that has gone out of scope when determining where to read the hosts data from for file lookups. + + Fix By: @Chilledheart + +- [Brad House brought this change] + + sync ax_cxx_compile_stdcxx_11.m4 with upstream (#505) + + It was reported that ax_cxx_compile_stdcxx_11.m4 was not compatible with uclibc. + The version in the repository is many years old so this PR simply pulls in the latest + available revision from: + http://git.savannah.gnu.org/gitweb/?p=autoconf-archive.git;a=tree;f=m4 + + Fixes Bug: #504 + Fix By: Brad House (@bradh352) + Version 1.19.0 (18 Jan 2023) bradh352 (18 Jan 2023) @@ -5325,76 +5552,3 @@ Daniel Stenberg (23 Mar 2010) - git now, not CVS - ignore lots of generated files - -- [Daniel Johnson brought this change] - - Fix warnings for clang - -Yang Tse (17 Mar 2010) -- replaced intel compiler option -no-ansi-alias with -fno-strict-aliasing - -- update outdated serial number - -- fix compiler warning - -- watt32 compilation fix - -- Added another VS10 version string - -- fix line break - -- removed usage of 's6_addr', fixing compilation issue triggered with no - longer using 'in6_addr' but only our 'ares_in6_addr' struct - -Daniel Stenberg (5 Mar 2010) -- Daniel Johnson provided fixes for building with the clang compiler - -Yang Tse (5 Mar 2010) -- Added IPv6 name servers support - -Gisle Vanem (5 Mar 2010) -- Ops!. Readded ares_nowarn.h. - -- Added ares_nowarn.c. - -Yang Tse (28 Feb 2010) -- Added SIZEOF_INT and SIZEOF_SHORT definitions for non-configure systems - -- Added ares_nowarn.* to VC6 project file - -- Added SIZEOF_INT definition - -- fix compiler warning - -- fix compiler warning - -- fix compiler warning - -Daniel Stenberg (17 Feb 2010) -- ares_reinit() - - - To allow an app to force a re-read of /etc/resolv.conf etc, pretty much - like the res_init() resolver function offers - -- - Tommie Gannert pointed out a silly bug in ares_process_fd() since it didn't - check for broken connections like ares_process() did. Based on that, I - merged the two functions into a single generic one with two front-ends. - -Yang Tse (30 Dec 2009) -- VMS specific preprocessor symbol checking adjustments - -- Mention last changes - -- - Fix configure_socket() to use ares_socket_t instead of int data type. - -- - Where run-time error checks enabling compiler option /GZ was used it is now - replaced with equivalent /RTCsu for Visual Studio 2003 and newer versions. - - - Compiler option /GX is now replaced with equivalent /EHsc for all versions. - -- - Ingmar Runge noticed that Windows config-win32.h configuration file - did not include a definition for HAVE_CLOSESOCKET which resulted in - function close() being inappropriately used to close sockets. - -Daniel Stenberg (30 Nov 2009) -- start working on 1.7.1 diff --git a/lib/c-ares-1.19.0/CMakeLists.txt b/lib/c-ares-1.19.1/CMakeLists.txt similarity index 98% rename from lib/c-ares-1.19.0/CMakeLists.txt rename to lib/c-ares-1.19.1/CMakeLists.txt index d11c0bba52d..9379014296c 100644 --- a/lib/c-ares-1.19.0/CMakeLists.txt +++ b/lib/c-ares-1.19.1/CMakeLists.txt @@ -8,10 +8,10 @@ INCLUDE (CheckCSourceCompiles) INCLUDE (CheckStructHasMember) INCLUDE (CheckLibraryExists) -PROJECT (c-ares LANGUAGES C VERSION "1.19.0" ) +PROJECT (c-ares LANGUAGES C VERSION "1.19.1" ) # Set this version before release -SET (CARES_VERSION "1.19.0") +SET (CARES_VERSION "1.19.1") INCLUDE (GNUInstallDirs) # include this *AFTER* PROJECT(), otherwise paths are wrong. @@ -26,7 +26,7 @@ INCLUDE (GNUInstallDirs) # include this *AFTER* PROJECT(), otherwise paths are w # For example, a version of 4:0:2 would generate output such as: # libname.so -> libname.so.2 # libname.so.2 -> libname.so.2.2.0 -SET (CARES_LIB_VERSIONINFO "8:0:6") +SET (CARES_LIB_VERSIONINFO "8:1:6") OPTION (CARES_STATIC "Build as a static library" OFF) @@ -36,6 +36,8 @@ OPTION (CARES_STATIC_PIC "Build the static library as PIC (position independent) OPTION (CARES_BUILD_TESTS "Build and run tests" OFF) OPTION (CARES_BUILD_CONTAINER_TESTS "Build and run container tests (implies CARES_BUILD_TESTS, Linux only)" OFF) OPTION (CARES_BUILD_TOOLS "Build tools" ON) +SET (CARES_RANDOM_FILE "/dev/urandom" CACHE STRING "Suitable File / Device Path for entropy, such as /dev/urandom") + # Tests require static to be enabled on Windows to be able to access otherwise hidden symbols IF (CARES_BUILD_TESTS AND (NOT CARES_STATIC) AND WIN32) @@ -391,6 +393,8 @@ CHECK_SYMBOL_EXISTS (strncasecmp "${CMAKE_EXTRA_INCLUDE_FILES}" HAVE_STRNCAS CHECK_SYMBOL_EXISTS (strncmpi "${CMAKE_EXTRA_INCLUDE_FILES}" HAVE_STRNCMPI) CHECK_SYMBOL_EXISTS (strnicmp "${CMAKE_EXTRA_INCLUDE_FILES}" HAVE_STRNICMP) CHECK_SYMBOL_EXISTS (writev "${CMAKE_EXTRA_INCLUDE_FILES}" HAVE_WRITEV) +CHECK_SYMBOL_EXISTS (arc4random_buf "${CMAKE_EXTRA_INCLUDE_FILES}" HAVE_ARC4RANDOM_BUF) + # On Android, the system headers may define __system_property_get(), but excluded # from libc. We need to perform a link test instead of a header/symbol test. @@ -402,10 +406,6 @@ SET (CMAKE_REQUIRED_DEFINITIONS) SET (CMAKE_REQUIRED_LIBRARIES) -find_file(CARES_RANDOM_FILE urandom /dev) -mark_as_advanced(CARES_RANDOM_FILE) - - ################################################################################ # recv, recvfrom, send, getnameinfo, gethostname # ARGUMENTS AND RETURN VALUES diff --git a/lib/c-ares-1.19.0/CONTRIBUTING.md b/lib/c-ares-1.19.1/CONTRIBUTING.md similarity index 100% rename from lib/c-ares-1.19.0/CONTRIBUTING.md rename to lib/c-ares-1.19.1/CONTRIBUTING.md diff --git a/lib/c-ares-1.19.0/INSTALL.md b/lib/c-ares-1.19.1/INSTALL.md similarity index 100% rename from lib/c-ares-1.19.0/INSTALL.md rename to lib/c-ares-1.19.1/INSTALL.md diff --git a/lib/c-ares-1.19.0/LICENSE.md b/lib/c-ares-1.19.1/LICENSE.md similarity index 100% rename from lib/c-ares-1.19.0/LICENSE.md rename to lib/c-ares-1.19.1/LICENSE.md diff --git a/lib/c-ares-1.19.0/Makefile.Watcom b/lib/c-ares-1.19.1/Makefile.Watcom similarity index 67% rename from lib/c-ares-1.19.0/Makefile.Watcom rename to lib/c-ares-1.19.1/Makefile.Watcom index fa529a56edc..34e07bb4c6b 100644 --- a/lib/c-ares-1.19.0/Makefile.Watcom +++ b/lib/c-ares-1.19.1/Makefile.Watcom @@ -1,6 +1,7 @@ # # Watcom / OpenWatcom / Win32 makefile for cares. # Quick hack by Guenter; comments to: /dev/nul +# Updated by Douglas R. Reno, comments to: renodr2002@gmail.com. 2023 # !ifndef %watcom @@ -38,9 +39,9 @@ MD = mkdir RD = rmdir /q /s 2>NUL CP = copy -CFLAGS = -3r -mf -hc -zff -zgf -zq -zm -zc -s -fr=con -w2 -fpi -oilrtfm & - -wcd=201 -bt=nt -d+ -dWIN32 -dCARES_BUILDING_LIBRARY & - -dNTDDI_VERSION=0x05010000 -I. $(SYS_INCL) +CFLAGS = -3r -mf -hc -zff -zgf -zq -zm -zc -s -fr=con -w2 -fpi -oilrtfm -aa & + -wcd=201 -bt=nt -d+ -dWIN32 -dCARES_BUILDING_LIBRARY & + -dNTDDI_VERSION=0x06000000 -I. -I.\include -I.\src\lib $(SYS_INCL) LFLAGS = option quiet, map, caseexact, eliminate @@ -69,7 +70,7 @@ LIB_ARG = $(OBJ_BASE)\stat\wlib.arg !ifneq __MAKEOPTS__ -u !error You MUST call wmake with the -u switch! !else -!include Makefile.inc +!include src\lib\Makefile.inc !endif OBJS = $(CSOURCES:.c=.obj) @@ -82,10 +83,11 @@ OBJ_DIR = $(OBJ_BASE)\stat OBJS_STAT = $+ $(OBJS) $- OBJ_DIR = $(OBJ_BASE)\dyn -OBJS_DYN = $+ $(OBJS) $- +OBJS_DYN += $(OBJS) $- ARESBUILDH = ares_build.h RESOURCE = $(OBJ_BASE)\dyn\cares.res +ARESBUILDH = include\ares_build.h all: $(ARESBUILDH) $(OBJ_BASE) $(TARGETS) $(DEMOS) .SYMBOLIC @echo Welcome to cares @@ -94,10 +96,10 @@ $(OBJ_BASE): -$(MD) $^@ -$(MD) $^@\stat -$(MD) $^@\dyn - -$(MD) $^@\demos + -$(MD) $^@\tools $(ARESBUILDH): .EXISTSONLY - $(CP) $^@.dist $^@ + @echo Make sure to run buildconf.bat! $(LIBNAME).dll: $(OBJS_DYN) $(RESOURCE) $(LINK_ARG) $(LD) name $^@ @$]@ @@ -105,14 +107,20 @@ $(LIBNAME).dll: $(OBJS_DYN) $(RESOURCE) $(LINK_ARG) $(LIBNAME).lib: $(OBJS_STAT) $(LIB_ARG) $(AR) -q -b -c $^@ @$]@ -adig.exe: $(OBJ_BASE)\demos\adig.obj $(OBJ_BASE)\demos\ares_getopt.obj $(LIBNAME).lib - $(LD) name $^@ system nt $(LFLAGS) file { $(OBJ_BASE)\demos\ares_getopt.obj $[@ } library $]@, ws2_32.lib +$(OBJ_BASE)\tools\ares_getopt.obj: + $(CC) $(CFLAGS) -DCARES_STATICLIB .\src\tools\ares_getopt.c -fo=$^@ -ahost.exe: $(OBJ_BASE)\demos\ahost.obj $(OBJ_BASE)\demos\ares_getopt.obj $(LIBNAME).lib - $(LD) name $^@ system nt $(LFLAGS) file { $(OBJ_BASE)\demos\ares_getopt.obj $[@ } library $]@, ws2_32.lib +adig.exe: $(OBJ_BASE)\tools\ares_getopt.obj $(LIBNAME).lib + $(CC) $(CFLAGS) src\tools\adig.c -fo=$(OBJ_BASE)\tools\adig.obj + $(LD) name $^@ system nt $(LFLAGS) file { $(OBJ_BASE)\tools\adig.obj $[@ } library $]@, ws2_32.lib, iphlpapi.lib -acountry.exe: $(OBJ_BASE)\demos\acountry.obj $(OBJ_BASE)\demos\ares_getopt.obj $(LIBNAME).lib - $(LD) name $^@ system nt $(LFLAGS) file { $(OBJ_BASE)\demos\ares_getopt.obj $[@ } library $]@, ws2_32.lib +ahost.exe: $(OBJ_BASE)\tools\ares_getopt.obj $(LIBNAME).lib + $(CC) $(CFLAGS) src\tools\ahost.c -fo=$(OBJ_BASE)\tools\ahost.obj + $(LD) name $^@ system nt $(LFLAGS) file { $(OBJ_BASE)\tools\ahost.obj $[@ } library $]@, ws2_32.lib, iphlpapi.lib + +acountry.exe: $(OBJ_BASE)\tools\ares_getopt.obj $(LIBNAME).lib + $(CC) $(CFLAGS) src\tools\acountry.c -fo=$(OBJ_BASE)\tools\acountry.obj + $(LD) name $^@ system nt $(LFLAGS) file { $(OBJ_BASE)\tools\acountry.obj $[@ } library $]@, ws2_32.lib, iphlpapi.lib clean: .SYMBOLIC -$(RM) $(OBJS_STAT) @@ -124,24 +132,23 @@ vclean realclean: clean .SYMBOLIC -$(RM) $(DEMOS) $(DEMOS:.exe=.map) -$(RD) $(OBJ_BASE)\stat -$(RD) $(OBJ_BASE)\dyn - -$(RD) $(OBJ_BASE)\demos + -$(RD) $(OBJ_BASE)\tools -$(RD) $(OBJ_BASE) .ERASE -$(RESOURCE): cares.rc .AUTODEPEND +.c: .\src\lib + +.ERASE +$(RESOURCE): src\lib\cares.rc .AUTODEPEND $(RC) $(DEBUG) -q -r -zm -I..\include $(SYS_INCL) $[@ -fo=$^@ .ERASE .c{$(OBJ_BASE)\dyn}.obj: - $(CC) $(CFLAGS) -bd $[@ -fo=$^@ + $(CC) $(CFLAGS) -bd .\src\lib\$^& -fo=$^@ .ERASE .c{$(OBJ_BASE)\stat}.obj: - $(CC) $(CFLAGS) -DCARES_STATICLIB $[@ -fo=$^@ - -.ERASE -.c{$(OBJ_BASE)\demos}.obj: - $(CC) $(CFLAGS) -DCARES_STATICLIB $[@ -fo=$^@ + $(CC) $(CFLAGS) -DCARES_STATICLIB .\src\lib\$^& -fo=$^@ $(LINK_ARG): $(__MAKEFILES__) %create $^@ @@ -155,6 +162,7 @@ $(LINK_ARG): $(__MAKEFILES__) @%append $^@ library $(%watt_root)\lib\wattcpw_imp.lib !else @%append $^@ library ws2_32.lib + @%append $^@ library iphlpapi.lib !endif $(LIB_ARG): $(__MAKEFILES__) diff --git a/lib/c-ares-1.19.0/Makefile.am b/lib/c-ares-1.19.1/Makefile.am similarity index 100% rename from lib/c-ares-1.19.0/Makefile.am rename to lib/c-ares-1.19.1/Makefile.am diff --git a/lib/c-ares-1.19.0/Makefile.dj b/lib/c-ares-1.19.1/Makefile.dj similarity index 100% rename from lib/c-ares-1.19.0/Makefile.dj rename to lib/c-ares-1.19.1/Makefile.dj diff --git a/lib/c-ares-1.19.0/Makefile.in b/lib/c-ares-1.19.1/Makefile.in similarity index 99% rename from lib/c-ares-1.19.0/Makefile.in rename to lib/c-ares-1.19.1/Makefile.in index a512effa1f6..3dfa479a244 100644 --- a/lib/c-ares-1.19.0/Makefile.in +++ b/lib/c-ares-1.19.1/Makefile.in @@ -96,6 +96,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_ac_append_to_file.m4 \ $(top_srcdir)/m4/ax_am_macros_static.m4 \ $(top_srcdir)/m4/ax_check_gnu_make.m4 \ $(top_srcdir)/m4/ax_code_coverage.m4 \ + $(top_srcdir)/m4/ax_cxx_compile_stdcxx.m4 \ $(top_srcdir)/m4/ax_cxx_compile_stdcxx_11.m4 \ $(top_srcdir)/m4/ax_file_escapes.m4 \ $(top_srcdir)/m4/ax_require_defined.m4 \ diff --git a/lib/c-ares-1.19.0/Makefile.m32 b/lib/c-ares-1.19.1/Makefile.m32 similarity index 100% rename from lib/c-ares-1.19.0/Makefile.m32 rename to lib/c-ares-1.19.1/Makefile.m32 diff --git a/lib/c-ares-1.19.0/Makefile.msvc b/lib/c-ares-1.19.1/Makefile.msvc similarity index 100% rename from lib/c-ares-1.19.0/Makefile.msvc rename to lib/c-ares-1.19.1/Makefile.msvc diff --git a/lib/c-ares-1.19.0/Makefile.netware b/lib/c-ares-1.19.1/Makefile.netware similarity index 100% rename from lib/c-ares-1.19.0/Makefile.netware rename to lib/c-ares-1.19.1/Makefile.netware diff --git a/lib/c-ares-1.19.0/NEWS b/lib/c-ares-1.19.1/NEWS similarity index 100% rename from lib/c-ares-1.19.0/NEWS rename to lib/c-ares-1.19.1/NEWS diff --git a/lib/c-ares-1.19.0/README.cares b/lib/c-ares-1.19.1/README.cares similarity index 100% rename from lib/c-ares-1.19.0/README.cares rename to lib/c-ares-1.19.1/README.cares diff --git a/lib/c-ares-1.19.0/README.md b/lib/c-ares-1.19.1/README.md similarity index 100% rename from lib/c-ares-1.19.0/README.md rename to lib/c-ares-1.19.1/README.md diff --git a/lib/c-ares-1.19.0/README.msvc b/lib/c-ares-1.19.1/README.msvc similarity index 100% rename from lib/c-ares-1.19.0/README.msvc rename to lib/c-ares-1.19.1/README.msvc diff --git a/lib/c-ares-1.19.1/RELEASE-NOTES b/lib/c-ares-1.19.1/RELEASE-NOTES new file mode 100644 index 00000000000..2524f3ccf41 --- /dev/null +++ b/lib/c-ares-1.19.1/RELEASE-NOTES @@ -0,0 +1,57 @@ +c-ares version 1.19.1 + +This is a security and bugfix release. + +A special thanks goes out to the Open Source Technology Improvement Fund +(https://ostif.org) for sponsoring a security audit of c-ares performed by X41 +(https://x41-dsec.de). + +Security: + o CVE-2023-32067. High. 0-byte UDP payload causes Denial of Service [12] + o CVE-2023-31147. Moderate. Insufficient randomness in generation of DNS + query IDs [13] + o CVE-2023-31130. Moderate. Buffer Underwrite in ares_inet_net_pton() [14] + o CVE-2023-31124. Low. AutoTools does not set CARES_RANDOM_FILE during cross + compilation [15] + +Bug fixes: + o Fix uninitialized memory warning in test [1] + o Turn off IPV6_V6ONLY on Windows to allow IPv4-mapped IPv6 addresses [2] + o ares_getaddrinfo() should allow a port of 0 [3] + o Fix memory leak in ares_send() on error [4] + o Fix comment style in ares_data.h [5] + o Remove unneeded ifdef for Windows [6] + o Fix typo in ares_init_options.3 [7] + o Re-add support for Watcom compiler [8] + o Sync ax_pthread.m4 with upstream [9] + o Windows: Invalid stack variable used out of scope for HOSTS path [10] + o Sync ax_cxx_compile_stdcxx_11.m4 with upstream to fix uclibc support [11] + +Thanks go to these friendly people for their efforts and contributions: + Brad House (@bradh352) + @Chilledheart + Daniel Stenberg (@bagder) + Douglas R. Reno (@renodr) + Gregor Jasny (@gjasny) + Jay Freeman (@saurik) + @lifenjoiner + Nikolaos Chatzikonstantinou (@createyourpersonalaccount) + Yijie Ma (@yijiem) +(9 contributors) + +References to bug reports and discussions on issues: + [1] = https://github.com/c-ares/c-ares/pull/515 + [2] = https://github.com/c-ares/c-ares/pull/520 + [3] = https://github.com/c-ares/c-ares/issues/517 + [4] = https://github.com/c-ares/c-ares/pull/511 + [5] = https://github.com/c-ares/c-ares/pull/513 + [6] = https://github.com/c-ares/c-ares/pull/512 + [7] = https://github.com/c-ares/c-ares/pull/510 + [8] = https://github.com/c-ares/c-ares/pull/509 + [9] = https://github.com/c-ares/c-ares/pull/507 + [10] = https://github.com/c-ares/c-ares/pull/502 + [11] = https://github.com/c-ares/c-ares/pull/505 + [12] = https://github.com/c-ares/c-ares/security/advisories/GHSA-9g78-jv2r-p7vc + [13] = https://github.com/c-ares/c-ares/security/advisories/GHSA-8r8p-23f3-64c2 + [14] = https://github.com/c-ares/c-ares/security/advisories/GHSA-x6mf-cxr9-8q6v + [15] = https://github.com/c-ares/c-ares/security/advisories/GHSA-54xr-f67r-4pc4 diff --git a/lib/c-ares-1.19.0/SECURITY.md b/lib/c-ares-1.19.1/SECURITY.md similarity index 100% rename from lib/c-ares-1.19.0/SECURITY.md rename to lib/c-ares-1.19.1/SECURITY.md diff --git a/lib/c-ares-1.19.0/TODO b/lib/c-ares-1.19.1/TODO similarity index 100% rename from lib/c-ares-1.19.0/TODO rename to lib/c-ares-1.19.1/TODO diff --git a/lib/c-ares-1.19.0/acinclude.m4 b/lib/c-ares-1.19.1/acinclude.m4 similarity index 100% rename from lib/c-ares-1.19.0/acinclude.m4 rename to lib/c-ares-1.19.1/acinclude.m4 diff --git a/lib/c-ares-1.19.0/aclocal.m4 b/lib/c-ares-1.19.1/aclocal.m4 similarity index 99% rename from lib/c-ares-1.19.0/aclocal.m4 rename to lib/c-ares-1.19.1/aclocal.m4 index e7ced790b91..ef2987bfa00 100644 --- a/lib/c-ares-1.19.0/aclocal.m4 +++ b/lib/c-ares-1.19.1/aclocal.m4 @@ -1190,6 +1190,7 @@ m4_include([m4/ax_add_am_macro_static.m4]) m4_include([m4/ax_am_macros_static.m4]) m4_include([m4/ax_check_gnu_make.m4]) m4_include([m4/ax_code_coverage.m4]) +m4_include([m4/ax_cxx_compile_stdcxx.m4]) m4_include([m4/ax_cxx_compile_stdcxx_11.m4]) m4_include([m4/ax_file_escapes.m4]) m4_include([m4/ax_require_defined.m4]) diff --git a/lib/c-ares-1.19.0/test/aminclude_static.am b/lib/c-ares-1.19.1/aminclude_static.am similarity index 99% rename from lib/c-ares-1.19.0/test/aminclude_static.am rename to lib/c-ares-1.19.1/aminclude_static.am index 306f5b68518..94db7e3a8c6 100644 --- a/lib/c-ares-1.19.0/test/aminclude_static.am +++ b/lib/c-ares-1.19.1/aminclude_static.am @@ -1,6 +1,6 @@ # aminclude_static.am generated automatically by Autoconf -# from AX_AM_MACROS_STATIC on Tue Nov 8 13:43:42 CET 2022 +# from AX_AM_MACROS_STATIC on Mon May 22 14:23:05 CEST 2023 # Code coverage diff --git a/lib/c-ares-1.19.0/buildconf b/lib/c-ares-1.19.1/buildconf similarity index 100% rename from lib/c-ares-1.19.0/buildconf rename to lib/c-ares-1.19.1/buildconf diff --git a/lib/c-ares-1.19.0/buildconf.bat b/lib/c-ares-1.19.1/buildconf.bat similarity index 100% rename from lib/c-ares-1.19.0/buildconf.bat rename to lib/c-ares-1.19.1/buildconf.bat diff --git a/lib/c-ares-1.19.0/c-ares-config.cmake.in b/lib/c-ares-1.19.1/c-ares-config.cmake.in similarity index 100% rename from lib/c-ares-1.19.0/c-ares-config.cmake.in rename to lib/c-ares-1.19.1/c-ares-config.cmake.in diff --git a/lib/c-ares-1.19.0/compile b/lib/c-ares-1.19.1/compile similarity index 100% rename from lib/c-ares-1.19.0/compile rename to lib/c-ares-1.19.1/compile diff --git a/lib/c-ares-1.19.0/config.guess b/lib/c-ares-1.19.1/config.guess similarity index 100% rename from lib/c-ares-1.19.0/config.guess rename to lib/c-ares-1.19.1/config.guess diff --git a/lib/c-ares-1.19.0/config.sub b/lib/c-ares-1.19.1/config.sub similarity index 100% rename from lib/c-ares-1.19.0/config.sub rename to lib/c-ares-1.19.1/config.sub diff --git a/lib/c-ares-1.19.0/configure b/lib/c-ares-1.19.1/configure similarity index 98% rename from lib/c-ares-1.19.0/configure rename to lib/c-ares-1.19.1/configure index 58712ec3414..2f182e0ce31 100755 --- a/lib/c-ares-1.19.0/configure +++ b/lib/c-ares-1.19.1/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.71 for c-ares 1.19.0. +# Generated by GNU Autoconf 2.71 for c-ares 1.19.1. # # Report bugs to . # @@ -855,8 +855,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='c-ares' PACKAGE_TARNAME='c-ares' -PACKAGE_VERSION='1.19.0' -PACKAGE_STRING='c-ares 1.19.0' +PACKAGE_VERSION='1.19.1' +PACKAGE_STRING='c-ares 1.19.1' PACKAGE_BUGREPORT='c-ares mailing list: http://lists.haxx.se/listinfo/c-ares' PACKAGE_URL='' @@ -1650,7 +1650,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures c-ares 1.19.0 to adapt to many kinds of systems. +\`configure' configures c-ares 1.19.1 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1721,7 +1721,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of c-ares 1.19.0:";; + short | recursive ) echo "Configuration of c-ares 1.19.1:";; esac cat <<\_ACEOF @@ -1861,7 +1861,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -c-ares configure 1.19.0 +c-ares configure 1.19.1 generated by GNU Autoconf 2.71 Copyright (C) 2021 Free Software Foundation, Inc. @@ -2453,7 +2453,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by c-ares $as_me 1.19.0, which was +It was created by c-ares $as_me 1.19.1, which was generated by GNU Autoconf 2.71. Invocation command line was $ $0$ac_configure_args_raw @@ -3426,7 +3426,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu -CARES_VERSION_INFO="8:0:6" +CARES_VERSION_INFO="8:1:6" @@ -6301,148 +6301,323 @@ ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ex ac_compiler_gnu=$ac_cv_cxx_compiler_gnu - ax_cxx_compile_cxx11_required=false + ax_cxx_compile_alternatives="11 0x" ax_cxx_compile_cxx11_required=false ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu ac_success=no - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CXX supports C++11 features by default" >&5 -printf %s "checking whether $CXX supports C++11 features by default... " >&6; } -if test ${ax_cv_cxx_compile_cxx11+y} + + + + + + if test x$ac_success = xno; then + for alternative in ${ax_cxx_compile_alternatives}; do + for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}"; do + cachevar=`printf "%s\n" "ax_cv_cxx_compile_cxx11_$switch" | $as_tr_sh` + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CXX supports C++11 features with $switch" >&5 +printf %s "checking whether $CXX supports C++11 features with $switch... " >&6; } +if eval test \${$cachevar+y} then : printf %s "(cached) " >&6 else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext + ac_save_CXX="$CXX" + CXX="$CXX $switch" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -#define static_assert _Static_assert - template +// If the compiler admits that it is not ready for C++11, why torture it? +// Hopefully, this will speed up the test. + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +// MSVC always sets __cplusplus to 199711L in older versions; newer versions +// only set it correctly if /Zc:__cplusplus is specified as well as a +// /std:c++NN switch: +// https://devblogs.microsoft.com/cppblog/msvc-now-correctly-reports-__cplusplus/ +#elif __cplusplus < 201103L && !defined _MSC_VER + +#error "This is not a C++11 compiler" + +#else + +namespace cxx11 +{ + + namespace test_static_assert + { + + template struct check { static_assert(sizeof(int) <= sizeof(T), "not big enough"); }; - struct Base { - virtual void f() {} + } + + namespace test_final_override + { + + struct Base + { + virtual ~Base() {} + virtual void f() {} }; - struct Child : public Base { - virtual void f() override {} + + struct Derived : public Base + { + virtual ~Derived() override {} + virtual void f() override {} }; - typedef check> right_angle_brackets; + } + + namespace test_double_right_angle_brackets + { + + template < typename T > + struct check {}; - int a; - decltype(a) b; + typedef check single_type; + typedef check> double_type; + typedef check>> triple_type; + typedef check>>> quadruple_type; + + } - typedef check check_type; - check_type c; - check_type&& cr = static_cast(c); + namespace test_decltype + { - auto d = a; - auto l = [](){}; + int + f() + { + int a = 1; + decltype(a) b = 2; + return a + b; + } - // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae - // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function because of this - namespace test_template_alias_sfinae { - struct foo {}; + } - template - using member = typename T::member_type; + namespace test_type_deduction + { - template - void func(...) {} + template < typename T1, typename T2 > + struct is_same + { + static const bool value = false; + }; - template - void func(member*) {} + template < typename T > + struct is_same + { + static const bool value = true; + }; - void test(); + template < typename T1, typename T2 > + auto + add(T1 a1, T2 a2) -> decltype(a1 + a2) + { + return a1 + a2; + } - void test() { - func(0); - } + int + test(const int c, volatile int v) + { + static_assert(is_same::value == true, ""); + static_assert(is_same::value == false, ""); + static_assert(is_same::value == false, ""); + auto ac = c; + auto av = v; + auto sumi = ac + av + 'x'; + auto sumf = ac + av + 1.0; + static_assert(is_same::value == true, ""); + static_assert(is_same::value == true, ""); + static_assert(is_same::value == true, ""); + static_assert(is_same::value == false, ""); + static_assert(is_same::value == true, ""); + return (sumf > 0.0) ? sumi : add(c, v); } -_ACEOF -if ac_fn_cxx_try_compile "$LINENO" -then : - ax_cv_cxx_compile_cxx11=yes -else $as_nop - ax_cv_cxx_compile_cxx11=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_cxx_compile_cxx11" >&5 -printf "%s\n" "$ax_cv_cxx_compile_cxx11" >&6; } - if test x$ax_cv_cxx_compile_cxx11 = xyes; then - ac_success=yes - fi + } + namespace test_noexcept + { + int f() { return 0; } + int g() noexcept { return 0; } - if test x$ac_success = xno; then - for switch in -std=c++11 -std=c++0x; do - cachevar=`printf "%s\n" "ax_cv_cxx_compile_cxx11_$switch" | $as_tr_sh` - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CXX supports C++11 features with $switch" >&5 -printf %s "checking whether $CXX supports C++11 features with $switch... " >&6; } -if eval test \${$cachevar+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_save_CXXFLAGS="$CXXFLAGS" - CXXFLAGS="$CXXFLAGS $switch" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ + static_assert(noexcept(f()) == false, ""); + static_assert(noexcept(g()) == true, ""); -#define static_assert _Static_assert + } - template - struct check + namespace test_constexpr + { + + template < typename CharT > + unsigned long constexpr + strlen_c_r(const CharT *const s, const unsigned long acc) noexcept { - static_assert(sizeof(int) <= sizeof(T), "not big enough"); + return *s ? strlen_c_r(s + 1, acc + 1) : acc; + } + + template < typename CharT > + unsigned long constexpr + strlen_c(const CharT *const s) noexcept + { + return strlen_c_r(s, 0UL); + } + + static_assert(strlen_c("") == 0UL, ""); + static_assert(strlen_c("1") == 1UL, ""); + static_assert(strlen_c("example") == 7UL, ""); + static_assert(strlen_c("another\0example") == 7UL, ""); + + } + + namespace test_rvalue_references + { + + template < int N > + struct answer + { + static constexpr int value = N; }; - struct Base { - virtual void f() {} + answer<1> f(int&) { return answer<1>(); } + answer<2> f(const int&) { return answer<2>(); } + answer<3> f(int&&) { return answer<3>(); } + + void + test() + { + int i = 0; + const int c = 0; + static_assert(decltype(f(i))::value == 1, ""); + static_assert(decltype(f(c))::value == 2, ""); + static_assert(decltype(f(0))::value == 3, ""); + } + + } + + namespace test_uniform_initialization + { + + struct test + { + static const int zero {}; + static const int one {1}; }; - struct Child : public Base { - virtual void f() override {} + + static_assert(test::zero == 0, ""); + static_assert(test::one == 1, ""); + + } + + namespace test_lambdas + { + + void + test1() + { + auto lambda1 = [](){}; + auto lambda2 = lambda1; + lambda1(); + lambda2(); + } + + int + test2() + { + auto a = [](int i, int j){ return i + j; }(1, 2); + auto b = []() -> int { return '0'; }(); + auto c = [=](){ return a + b; }(); + auto d = [&](){ return c; }(); + auto e = [a, &b](int x) mutable { + const auto identity = [](int y){ return y; }; + for (auto i = 0; i < a; ++i) + a += b--; + return x + identity(a + b); + }(0); + return a + b + c + d + e; + } + + int + test3() + { + const auto nullary = [](){ return 0; }; + const auto unary = [](int x){ return x; }; + using nullary_t = decltype(nullary); + using unary_t = decltype(unary); + const auto higher1st = [](nullary_t f){ return f(); }; + const auto higher2nd = [unary](nullary_t f1){ + return [unary, f1](unary_t f2){ return f2(unary(f1())); }; + }; + return higher1st(nullary) + higher2nd(nullary)(unary); + } + + } + + namespace test_variadic_templates + { + + template + struct sum; + + template + struct sum + { + static constexpr auto value = N0 + sum::value; }; - typedef check> right_angle_brackets; + template <> + struct sum<> + { + static constexpr auto value = 0; + }; - int a; - decltype(a) b; + static_assert(sum<>::value == 0, ""); + static_assert(sum<1>::value == 1, ""); + static_assert(sum<23>::value == 23, ""); + static_assert(sum<1, 2>::value == 3, ""); + static_assert(sum<5, 5, 11>::value == 21, ""); + static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, ""); - typedef check check_type; - check_type c; - check_type&& cr = static_cast(c); + } - auto d = a; - auto l = [](){}; + // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae + // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function + // because of this. + namespace test_template_alias_sfinae + { - // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae - // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function because of this - namespace test_template_alias_sfinae { - struct foo {}; + struct foo {}; - template - using member = typename T::member_type; + template + using member = typename T::member_type; - template - void func(...) {} + template + void func(...) {} - template - void func(member*) {} + template + void func(member*) {} + + void test(); + + void test() { func(0); } + + } + +} // namespace cxx11 + +#endif // __cplusplus >= 201103L - void test(); - void test() { - func(0); - } - } _ACEOF if ac_fn_cxx_try_compile "$LINENO" @@ -6452,14 +6627,21 @@ else $as_nop eval $cachevar=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - CXXFLAGS="$ac_save_CXXFLAGS" + CXX="$ac_save_CXX" fi eval ac_res=\$$cachevar { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } - if eval test x\$$cachevar = xyes; then - CXXFLAGS="$CXXFLAGS $switch" - ac_success=yes + if eval test x\$$cachevar = xyes; then + CXX="$CXX $switch" + if test -n "$CXXCPP" ; then + CXXCPP="$CXXCPP $switch" + fi + ac_success=yes + break + fi + done + if test x$ac_success = xyes; then break fi done @@ -6474,22 +6656,20 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu if test x$ac_success = xno; then as_fn_error $? "*** A compiler with support for C++11 language features is required." "$LINENO" 5 fi - else - if test x$ac_success = xno; then - HAVE_CXX11=0 - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: No compiler with C++11 support was found" >&5 + fi + if test x$ac_success = xno; then + HAVE_CXX11=0 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: No compiler with C++11 support was found" >&5 printf "%s\n" "$as_me: No compiler with C++11 support was found" >&6;} - else - HAVE_CXX11=1 + else + HAVE_CXX11=1 printf "%s\n" "#define HAVE_CXX11 1" >>confdefs.h - fi - - fi + am__api_version='1.16' { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 @@ -6880,7 +7060,7 @@ fi # Define the identity of the package. PACKAGE='c-ares' - VERSION='1.19.0' + VERSION='1.19.1' printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h @@ -33016,6 +33196,166 @@ printf "%s\n" "no" >&6; } fi + # + tst_links_arc4random_buf="unknown" + tst_proto_arc4random_buf="unknown" + tst_compi_arc4random_buf="unknown" + tst_allow_arc4random_buf="unknown" + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if arc4random_buf can be linked" >&5 +printf %s "checking if arc4random_buf can be linked... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + /* Define arc4random_buf to an innocuous variant, in case declares arc4random_buf. + For example, HP-UX 11i declares gettimeofday. */ +#define arc4random_buf innocuous_arc4random_buf + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char arc4random_buf (); below. */ + +#include +#undef arc4random_buf + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char arc4random_buf (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_arc4random_buf || defined __stub___arc4random_buf +choke me +#endif + +int +main (void) +{ +return arc4random_buf (); + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_links_arc4random_buf="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_links_arc4random_buf="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + # + if test "$tst_links_arc4random_buf" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if arc4random_buf is prototyped" >&5 +printf %s "checking if arc4random_buf is prototyped... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + $cares_includes_stdlib + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "arc4random_buf" >/dev/null 2>&1 +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_proto_arc4random_buf="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_proto_arc4random_buf="no" + +fi +rm -rf conftest* + + fi + # + if test "$tst_proto_arc4random_buf" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if arc4random_buf is compilable" >&5 +printf %s "checking if arc4random_buf is compilable... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + $cares_includes_stdlib + +int +main (void) +{ + + arc4random_buf(NULL, 0); + return 1; + + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_compi_arc4random_buf="yes" + +else $as_nop + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_compi_arc4random_buf="no" + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + fi + # + if test "$tst_compi_arc4random_buf" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if arc4random_buf usage allowed" >&5 +printf %s "checking if arc4random_buf usage allowed... " >&6; } + if test "x$cares_disallow_arc4random_buf" != "xyes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + tst_allow_arc4random_buf="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + tst_allow_arc4random_buf="no" + fi + fi + # + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if arc4random_buf might be used" >&5 +printf %s "checking if arc4random_buf might be used... " >&6; } + if test "$tst_links_arc4random_buf" = "yes" && + test "$tst_proto_arc4random_buf" = "yes" && + test "$tst_compi_arc4random_buf" = "yes" && + test "$tst_allow_arc4random_buf" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + +printf "%s\n" "#define HAVE_ARC4RANDOM_BUF 1" >>confdefs.h + + ac_cv_func_arc4random_buf="yes" + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + ac_cv_func_arc4random_buf="no" + fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for PF_INET6" >&5 @@ -33954,37 +34294,7 @@ if test ${with_random+y} then : withval=$with_random; CARES_RANDOM_FILE="$withval" else $as_nop - - if test "$cross_compiling" = "no"; then - as_ac_File=`printf "%s\n" "ac_cv_file_"/dev/urandom"" | $as_tr_sh` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for \"/dev/urandom\"" >&5 -printf %s "checking for \"/dev/urandom\"... " >&6; } -if eval test \${$as_ac_File+y} -then : - printf %s "(cached) " >&6 -else $as_nop - test "$cross_compiling" = yes && - as_fn_error $? "cannot check for file existence when cross compiling" "$LINENO" 5 -if test -r ""/dev/urandom""; then - eval "$as_ac_File=yes" -else - eval "$as_ac_File=no" -fi -fi -eval ac_res=\$$as_ac_File - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if eval test \"x\$"$as_ac_File"\" = x"yes" -then : CARES_RANDOM_FILE="/dev/urandom" -fi - - else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cannot check for /dev/urandom while cross compiling; assuming none" >&5 -printf "%s\n" "$as_me: WARNING: cannot check for /dev/urandom while cross compiling; assuming none" >&2;} - fi - - fi @@ -34868,7 +35178,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by c-ares $as_me 1.19.0, which was +This file was extended by c-ares $as_me 1.19.1, which was generated by GNU Autoconf 2.71. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -34936,7 +35246,7 @@ ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ -c-ares config.status 1.19.0 +c-ares config.status 1.19.1 configured by $0, generated by GNU Autoconf 2.71, with options \\"\$ac_cs_config\\" diff --git a/lib/c-ares-1.19.0/configure.ac b/lib/c-ares-1.19.1/configure.ac similarity index 98% rename from lib/c-ares-1.19.0/configure.ac rename to lib/c-ares-1.19.1/configure.ac index 56a570bce01..54e79d6e2a9 100644 --- a/lib/c-ares-1.19.0/configure.ac +++ b/lib/c-ares-1.19.1/configure.ac @@ -1,9 +1,9 @@ AC_PREREQ([2.60]) -AC_INIT([c-ares], [1.19.0], +AC_INIT([c-ares], [1.19.1], [c-ares mailing list: http://lists.haxx.se/listinfo/c-ares]) -CARES_VERSION_INFO="8:0:6" +CARES_VERSION_INFO="8:1:6" dnl This flag accepts an argument of the form current[:revision[:age]]. So, dnl passing -version-info 3:12:1 sets current to 3, revision to 12, and age to dnl 1. @@ -683,6 +683,7 @@ CARES_CHECK_FUNC_STRNCASECMP CARES_CHECK_FUNC_STRNCMPI CARES_CHECK_FUNC_STRNICMP CARES_CHECK_FUNC_WRITEV +CARES_CHECK_FUNC_ARC4RANDOM_BUF dnl check for AF_INET6 @@ -896,17 +897,7 @@ AC_ARG_WITH(random, AS_HELP_STRING([--with-random=FILE], [read randomness from FILE (default=/dev/urandom)]), [ CARES_RANDOM_FILE="$withval" ], - [ - dnl Check for random device. If we're cross compiling, we can't - dnl check, and it's better to assume it doesn't exist than it is - dnl to fail on AC_CHECK_FILE or later. - if test "$cross_compiling" = "no"; then - AC_CHECK_FILE("/dev/urandom", [ CARES_RANDOM_FILE="/dev/urandom"] ) - else - AC_MSG_WARN([cannot check for /dev/urandom while cross compiling; assuming none]) - fi - - ] + [ CARES_RANDOM_FILE="/dev/urandom" ] ) if test -n "$CARES_RANDOM_FILE" && test X"$CARES_RANDOM_FILE" != Xno ; then AC_SUBST(CARES_RANDOM_FILE) diff --git a/lib/c-ares-1.19.0/depcomp b/lib/c-ares-1.19.1/depcomp similarity index 100% rename from lib/c-ares-1.19.0/depcomp rename to lib/c-ares-1.19.1/depcomp diff --git a/lib/c-ares-1.19.0/docs/CMakeLists.txt b/lib/c-ares-1.19.1/docs/CMakeLists.txt similarity index 100% rename from lib/c-ares-1.19.0/docs/CMakeLists.txt rename to lib/c-ares-1.19.1/docs/CMakeLists.txt diff --git a/lib/c-ares-1.19.0/docs/Makefile.am b/lib/c-ares-1.19.1/docs/Makefile.am similarity index 100% rename from lib/c-ares-1.19.0/docs/Makefile.am rename to lib/c-ares-1.19.1/docs/Makefile.am diff --git a/lib/c-ares-1.19.0/docs/Makefile.in b/lib/c-ares-1.19.1/docs/Makefile.in similarity index 99% rename from lib/c-ares-1.19.0/docs/Makefile.in rename to lib/c-ares-1.19.1/docs/Makefile.in index 94dc18d1e04..b169b2a01d1 100644 --- a/lib/c-ares-1.19.0/docs/Makefile.in +++ b/lib/c-ares-1.19.1/docs/Makefile.in @@ -99,6 +99,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_ac_append_to_file.m4 \ $(top_srcdir)/m4/ax_am_macros_static.m4 \ $(top_srcdir)/m4/ax_check_gnu_make.m4 \ $(top_srcdir)/m4/ax_code_coverage.m4 \ + $(top_srcdir)/m4/ax_cxx_compile_stdcxx.m4 \ $(top_srcdir)/m4/ax_cxx_compile_stdcxx_11.m4 \ $(top_srcdir)/m4/ax_file_escapes.m4 \ $(top_srcdir)/m4/ax_require_defined.m4 \ diff --git a/lib/c-ares-1.19.0/docs/Makefile.inc b/lib/c-ares-1.19.1/docs/Makefile.inc similarity index 100% rename from lib/c-ares-1.19.0/docs/Makefile.inc rename to lib/c-ares-1.19.1/docs/Makefile.inc diff --git a/lib/c-ares-1.19.0/docs/acountry.1 b/lib/c-ares-1.19.1/docs/acountry.1 similarity index 100% rename from lib/c-ares-1.19.0/docs/acountry.1 rename to lib/c-ares-1.19.1/docs/acountry.1 diff --git a/lib/c-ares-1.19.0/docs/adig.1 b/lib/c-ares-1.19.1/docs/adig.1 similarity index 100% rename from lib/c-ares-1.19.0/docs/adig.1 rename to lib/c-ares-1.19.1/docs/adig.1 diff --git a/lib/c-ares-1.19.0/docs/ahost.1 b/lib/c-ares-1.19.1/docs/ahost.1 similarity index 100% rename from lib/c-ares-1.19.0/docs/ahost.1 rename to lib/c-ares-1.19.1/docs/ahost.1 diff --git a/lib/c-ares-1.19.0/docs/ares_cancel.3 b/lib/c-ares-1.19.1/docs/ares_cancel.3 similarity index 100% rename from lib/c-ares-1.19.0/docs/ares_cancel.3 rename to lib/c-ares-1.19.1/docs/ares_cancel.3 diff --git a/lib/c-ares-1.19.0/docs/ares_create_query.3 b/lib/c-ares-1.19.1/docs/ares_create_query.3 similarity index 100% rename from lib/c-ares-1.19.0/docs/ares_create_query.3 rename to lib/c-ares-1.19.1/docs/ares_create_query.3 diff --git a/lib/c-ares-1.19.0/docs/ares_destroy.3 b/lib/c-ares-1.19.1/docs/ares_destroy.3 similarity index 100% rename from lib/c-ares-1.19.0/docs/ares_destroy.3 rename to lib/c-ares-1.19.1/docs/ares_destroy.3 diff --git a/lib/c-ares-1.19.0/docs/ares_destroy_options.3 b/lib/c-ares-1.19.1/docs/ares_destroy_options.3 similarity index 100% rename from lib/c-ares-1.19.0/docs/ares_destroy_options.3 rename to lib/c-ares-1.19.1/docs/ares_destroy_options.3 diff --git a/lib/c-ares-1.19.0/docs/ares_dup.3 b/lib/c-ares-1.19.1/docs/ares_dup.3 similarity index 100% rename from lib/c-ares-1.19.0/docs/ares_dup.3 rename to lib/c-ares-1.19.1/docs/ares_dup.3 diff --git a/lib/c-ares-1.19.0/docs/ares_expand_name.3 b/lib/c-ares-1.19.1/docs/ares_expand_name.3 similarity index 100% rename from lib/c-ares-1.19.0/docs/ares_expand_name.3 rename to lib/c-ares-1.19.1/docs/ares_expand_name.3 diff --git a/lib/c-ares-1.19.0/docs/ares_expand_string.3 b/lib/c-ares-1.19.1/docs/ares_expand_string.3 similarity index 100% rename from lib/c-ares-1.19.0/docs/ares_expand_string.3 rename to lib/c-ares-1.19.1/docs/ares_expand_string.3 diff --git a/lib/c-ares-1.19.0/docs/ares_fds.3 b/lib/c-ares-1.19.1/docs/ares_fds.3 similarity index 100% rename from lib/c-ares-1.19.0/docs/ares_fds.3 rename to lib/c-ares-1.19.1/docs/ares_fds.3 diff --git a/lib/c-ares-1.19.0/docs/ares_free_data.3 b/lib/c-ares-1.19.1/docs/ares_free_data.3 similarity index 100% rename from lib/c-ares-1.19.0/docs/ares_free_data.3 rename to lib/c-ares-1.19.1/docs/ares_free_data.3 diff --git a/lib/c-ares-1.19.0/docs/ares_free_hostent.3 b/lib/c-ares-1.19.1/docs/ares_free_hostent.3 similarity index 100% rename from lib/c-ares-1.19.0/docs/ares_free_hostent.3 rename to lib/c-ares-1.19.1/docs/ares_free_hostent.3 diff --git a/lib/c-ares-1.19.0/docs/ares_free_string.3 b/lib/c-ares-1.19.1/docs/ares_free_string.3 similarity index 100% rename from lib/c-ares-1.19.0/docs/ares_free_string.3 rename to lib/c-ares-1.19.1/docs/ares_free_string.3 diff --git a/lib/c-ares-1.19.0/docs/ares_freeaddrinfo.3 b/lib/c-ares-1.19.1/docs/ares_freeaddrinfo.3 similarity index 100% rename from lib/c-ares-1.19.0/docs/ares_freeaddrinfo.3 rename to lib/c-ares-1.19.1/docs/ares_freeaddrinfo.3 diff --git a/lib/c-ares-1.19.0/docs/ares_get_servers.3 b/lib/c-ares-1.19.1/docs/ares_get_servers.3 similarity index 100% rename from lib/c-ares-1.19.0/docs/ares_get_servers.3 rename to lib/c-ares-1.19.1/docs/ares_get_servers.3 diff --git a/lib/c-ares-1.19.0/docs/ares_get_servers_ports.3 b/lib/c-ares-1.19.1/docs/ares_get_servers_ports.3 similarity index 100% rename from lib/c-ares-1.19.0/docs/ares_get_servers_ports.3 rename to lib/c-ares-1.19.1/docs/ares_get_servers_ports.3 diff --git a/lib/c-ares-1.19.0/docs/ares_getaddrinfo.3 b/lib/c-ares-1.19.1/docs/ares_getaddrinfo.3 similarity index 100% rename from lib/c-ares-1.19.0/docs/ares_getaddrinfo.3 rename to lib/c-ares-1.19.1/docs/ares_getaddrinfo.3 diff --git a/lib/c-ares-1.19.0/docs/ares_gethostbyaddr.3 b/lib/c-ares-1.19.1/docs/ares_gethostbyaddr.3 similarity index 100% rename from lib/c-ares-1.19.0/docs/ares_gethostbyaddr.3 rename to lib/c-ares-1.19.1/docs/ares_gethostbyaddr.3 diff --git a/lib/c-ares-1.19.0/docs/ares_gethostbyname.3 b/lib/c-ares-1.19.1/docs/ares_gethostbyname.3 similarity index 100% rename from lib/c-ares-1.19.0/docs/ares_gethostbyname.3 rename to lib/c-ares-1.19.1/docs/ares_gethostbyname.3 diff --git a/lib/c-ares-1.19.0/docs/ares_gethostbyname_file.3 b/lib/c-ares-1.19.1/docs/ares_gethostbyname_file.3 similarity index 100% rename from lib/c-ares-1.19.0/docs/ares_gethostbyname_file.3 rename to lib/c-ares-1.19.1/docs/ares_gethostbyname_file.3 diff --git a/lib/c-ares-1.19.0/docs/ares_getnameinfo.3 b/lib/c-ares-1.19.1/docs/ares_getnameinfo.3 similarity index 100% rename from lib/c-ares-1.19.0/docs/ares_getnameinfo.3 rename to lib/c-ares-1.19.1/docs/ares_getnameinfo.3 diff --git a/lib/c-ares-1.19.0/docs/ares_getsock.3 b/lib/c-ares-1.19.1/docs/ares_getsock.3 similarity index 100% rename from lib/c-ares-1.19.0/docs/ares_getsock.3 rename to lib/c-ares-1.19.1/docs/ares_getsock.3 diff --git a/lib/c-ares-1.19.0/docs/ares_inet_ntop.3 b/lib/c-ares-1.19.1/docs/ares_inet_ntop.3 similarity index 100% rename from lib/c-ares-1.19.0/docs/ares_inet_ntop.3 rename to lib/c-ares-1.19.1/docs/ares_inet_ntop.3 diff --git a/lib/c-ares-1.19.0/docs/ares_inet_pton.3 b/lib/c-ares-1.19.1/docs/ares_inet_pton.3 similarity index 100% rename from lib/c-ares-1.19.0/docs/ares_inet_pton.3 rename to lib/c-ares-1.19.1/docs/ares_inet_pton.3 diff --git a/lib/c-ares-1.19.0/docs/ares_init.3 b/lib/c-ares-1.19.1/docs/ares_init.3 similarity index 100% rename from lib/c-ares-1.19.0/docs/ares_init.3 rename to lib/c-ares-1.19.1/docs/ares_init.3 diff --git a/lib/c-ares-1.19.0/docs/ares_init_options.3 b/lib/c-ares-1.19.1/docs/ares_init_options.3 similarity index 99% rename from lib/c-ares-1.19.0/docs/ares_init_options.3 rename to lib/c-ares-1.19.1/docs/ares_init_options.3 index 02d30721080..b31f6637c75 100644 --- a/lib/c-ares-1.19.0/docs/ares_init_options.3 +++ b/lib/c-ares-1.19.1/docs/ares_init_options.3 @@ -283,7 +283,7 @@ When initializing from path location) \fBares_init_options(3)\fP reads the \fIdomain\fP and \fIsearch\fP directives to allow lookups of short names relative to the domains specified. The -\fIdomain\fP and \fIsearch\fP directives override one another. If more that +\fIdomain\fP and \fIsearch\fP directives override one another. If more than one instance of either \fIdomain\fP or \fIsearch\fP directives is specified, the last occurrence wins. For more information, please see the .BR resolv.conf (5) diff --git a/lib/c-ares-1.19.0/docs/ares_library_cleanup.3 b/lib/c-ares-1.19.1/docs/ares_library_cleanup.3 similarity index 100% rename from lib/c-ares-1.19.0/docs/ares_library_cleanup.3 rename to lib/c-ares-1.19.1/docs/ares_library_cleanup.3 diff --git a/lib/c-ares-1.19.0/docs/ares_library_init.3 b/lib/c-ares-1.19.1/docs/ares_library_init.3 similarity index 100% rename from lib/c-ares-1.19.0/docs/ares_library_init.3 rename to lib/c-ares-1.19.1/docs/ares_library_init.3 diff --git a/lib/c-ares-1.19.0/docs/ares_library_init_android.3 b/lib/c-ares-1.19.1/docs/ares_library_init_android.3 similarity index 100% rename from lib/c-ares-1.19.0/docs/ares_library_init_android.3 rename to lib/c-ares-1.19.1/docs/ares_library_init_android.3 diff --git a/lib/c-ares-1.19.0/docs/ares_library_initialized.3 b/lib/c-ares-1.19.1/docs/ares_library_initialized.3 similarity index 100% rename from lib/c-ares-1.19.0/docs/ares_library_initialized.3 rename to lib/c-ares-1.19.1/docs/ares_library_initialized.3 diff --git a/lib/c-ares-1.19.0/docs/ares_mkquery.3 b/lib/c-ares-1.19.1/docs/ares_mkquery.3 similarity index 100% rename from lib/c-ares-1.19.0/docs/ares_mkquery.3 rename to lib/c-ares-1.19.1/docs/ares_mkquery.3 diff --git a/lib/c-ares-1.19.0/docs/ares_parse_a_reply.3 b/lib/c-ares-1.19.1/docs/ares_parse_a_reply.3 similarity index 100% rename from lib/c-ares-1.19.0/docs/ares_parse_a_reply.3 rename to lib/c-ares-1.19.1/docs/ares_parse_a_reply.3 diff --git a/lib/c-ares-1.19.0/docs/ares_parse_aaaa_reply.3 b/lib/c-ares-1.19.1/docs/ares_parse_aaaa_reply.3 similarity index 100% rename from lib/c-ares-1.19.0/docs/ares_parse_aaaa_reply.3 rename to lib/c-ares-1.19.1/docs/ares_parse_aaaa_reply.3 diff --git a/lib/c-ares-1.19.0/docs/ares_parse_caa_reply.3 b/lib/c-ares-1.19.1/docs/ares_parse_caa_reply.3 similarity index 100% rename from lib/c-ares-1.19.0/docs/ares_parse_caa_reply.3 rename to lib/c-ares-1.19.1/docs/ares_parse_caa_reply.3 diff --git a/lib/c-ares-1.19.0/docs/ares_parse_mx_reply.3 b/lib/c-ares-1.19.1/docs/ares_parse_mx_reply.3 similarity index 100% rename from lib/c-ares-1.19.0/docs/ares_parse_mx_reply.3 rename to lib/c-ares-1.19.1/docs/ares_parse_mx_reply.3 diff --git a/lib/c-ares-1.19.0/docs/ares_parse_naptr_reply.3 b/lib/c-ares-1.19.1/docs/ares_parse_naptr_reply.3 similarity index 100% rename from lib/c-ares-1.19.0/docs/ares_parse_naptr_reply.3 rename to lib/c-ares-1.19.1/docs/ares_parse_naptr_reply.3 diff --git a/lib/c-ares-1.19.0/docs/ares_parse_ns_reply.3 b/lib/c-ares-1.19.1/docs/ares_parse_ns_reply.3 similarity index 100% rename from lib/c-ares-1.19.0/docs/ares_parse_ns_reply.3 rename to lib/c-ares-1.19.1/docs/ares_parse_ns_reply.3 diff --git a/lib/c-ares-1.19.0/docs/ares_parse_ptr_reply.3 b/lib/c-ares-1.19.1/docs/ares_parse_ptr_reply.3 similarity index 100% rename from lib/c-ares-1.19.0/docs/ares_parse_ptr_reply.3 rename to lib/c-ares-1.19.1/docs/ares_parse_ptr_reply.3 diff --git a/lib/c-ares-1.19.0/docs/ares_parse_soa_reply.3 b/lib/c-ares-1.19.1/docs/ares_parse_soa_reply.3 similarity index 100% rename from lib/c-ares-1.19.0/docs/ares_parse_soa_reply.3 rename to lib/c-ares-1.19.1/docs/ares_parse_soa_reply.3 diff --git a/lib/c-ares-1.19.0/docs/ares_parse_srv_reply.3 b/lib/c-ares-1.19.1/docs/ares_parse_srv_reply.3 similarity index 100% rename from lib/c-ares-1.19.0/docs/ares_parse_srv_reply.3 rename to lib/c-ares-1.19.1/docs/ares_parse_srv_reply.3 diff --git a/lib/c-ares-1.19.0/docs/ares_parse_txt_reply.3 b/lib/c-ares-1.19.1/docs/ares_parse_txt_reply.3 similarity index 100% rename from lib/c-ares-1.19.0/docs/ares_parse_txt_reply.3 rename to lib/c-ares-1.19.1/docs/ares_parse_txt_reply.3 diff --git a/lib/c-ares-1.19.0/docs/ares_parse_uri_reply.3 b/lib/c-ares-1.19.1/docs/ares_parse_uri_reply.3 similarity index 100% rename from lib/c-ares-1.19.0/docs/ares_parse_uri_reply.3 rename to lib/c-ares-1.19.1/docs/ares_parse_uri_reply.3 diff --git a/lib/c-ares-1.19.0/docs/ares_process.3 b/lib/c-ares-1.19.1/docs/ares_process.3 similarity index 100% rename from lib/c-ares-1.19.0/docs/ares_process.3 rename to lib/c-ares-1.19.1/docs/ares_process.3 diff --git a/lib/c-ares-1.19.0/docs/ares_query.3 b/lib/c-ares-1.19.1/docs/ares_query.3 similarity index 100% rename from lib/c-ares-1.19.0/docs/ares_query.3 rename to lib/c-ares-1.19.1/docs/ares_query.3 diff --git a/lib/c-ares-1.19.0/docs/ares_save_options.3 b/lib/c-ares-1.19.1/docs/ares_save_options.3 similarity index 100% rename from lib/c-ares-1.19.0/docs/ares_save_options.3 rename to lib/c-ares-1.19.1/docs/ares_save_options.3 diff --git a/lib/c-ares-1.19.0/docs/ares_search.3 b/lib/c-ares-1.19.1/docs/ares_search.3 similarity index 100% rename from lib/c-ares-1.19.0/docs/ares_search.3 rename to lib/c-ares-1.19.1/docs/ares_search.3 diff --git a/lib/c-ares-1.19.0/docs/ares_send.3 b/lib/c-ares-1.19.1/docs/ares_send.3 similarity index 100% rename from lib/c-ares-1.19.0/docs/ares_send.3 rename to lib/c-ares-1.19.1/docs/ares_send.3 diff --git a/lib/c-ares-1.19.0/docs/ares_set_local_dev.3 b/lib/c-ares-1.19.1/docs/ares_set_local_dev.3 similarity index 100% rename from lib/c-ares-1.19.0/docs/ares_set_local_dev.3 rename to lib/c-ares-1.19.1/docs/ares_set_local_dev.3 diff --git a/lib/c-ares-1.19.0/docs/ares_set_local_ip4.3 b/lib/c-ares-1.19.1/docs/ares_set_local_ip4.3 similarity index 100% rename from lib/c-ares-1.19.0/docs/ares_set_local_ip4.3 rename to lib/c-ares-1.19.1/docs/ares_set_local_ip4.3 diff --git a/lib/c-ares-1.19.0/docs/ares_set_local_ip6.3 b/lib/c-ares-1.19.1/docs/ares_set_local_ip6.3 similarity index 100% rename from lib/c-ares-1.19.0/docs/ares_set_local_ip6.3 rename to lib/c-ares-1.19.1/docs/ares_set_local_ip6.3 diff --git a/lib/c-ares-1.19.0/docs/ares_set_servers.3 b/lib/c-ares-1.19.1/docs/ares_set_servers.3 similarity index 100% rename from lib/c-ares-1.19.0/docs/ares_set_servers.3 rename to lib/c-ares-1.19.1/docs/ares_set_servers.3 diff --git a/lib/c-ares-1.19.0/docs/ares_set_servers_csv.3 b/lib/c-ares-1.19.1/docs/ares_set_servers_csv.3 similarity index 100% rename from lib/c-ares-1.19.0/docs/ares_set_servers_csv.3 rename to lib/c-ares-1.19.1/docs/ares_set_servers_csv.3 diff --git a/lib/c-ares-1.19.0/docs/ares_set_servers_ports.3 b/lib/c-ares-1.19.1/docs/ares_set_servers_ports.3 similarity index 100% rename from lib/c-ares-1.19.0/docs/ares_set_servers_ports.3 rename to lib/c-ares-1.19.1/docs/ares_set_servers_ports.3 diff --git a/lib/c-ares-1.19.0/docs/ares_set_servers_ports_csv.3 b/lib/c-ares-1.19.1/docs/ares_set_servers_ports_csv.3 similarity index 100% rename from lib/c-ares-1.19.0/docs/ares_set_servers_ports_csv.3 rename to lib/c-ares-1.19.1/docs/ares_set_servers_ports_csv.3 diff --git a/lib/c-ares-1.19.0/docs/ares_set_socket_callback.3 b/lib/c-ares-1.19.1/docs/ares_set_socket_callback.3 similarity index 100% rename from lib/c-ares-1.19.0/docs/ares_set_socket_callback.3 rename to lib/c-ares-1.19.1/docs/ares_set_socket_callback.3 diff --git a/lib/c-ares-1.19.0/docs/ares_set_socket_configure_callback.3 b/lib/c-ares-1.19.1/docs/ares_set_socket_configure_callback.3 similarity index 100% rename from lib/c-ares-1.19.0/docs/ares_set_socket_configure_callback.3 rename to lib/c-ares-1.19.1/docs/ares_set_socket_configure_callback.3 diff --git a/lib/c-ares-1.19.0/docs/ares_set_socket_functions.3 b/lib/c-ares-1.19.1/docs/ares_set_socket_functions.3 similarity index 100% rename from lib/c-ares-1.19.0/docs/ares_set_socket_functions.3 rename to lib/c-ares-1.19.1/docs/ares_set_socket_functions.3 diff --git a/lib/c-ares-1.19.0/docs/ares_set_sortlist.3 b/lib/c-ares-1.19.1/docs/ares_set_sortlist.3 similarity index 100% rename from lib/c-ares-1.19.0/docs/ares_set_sortlist.3 rename to lib/c-ares-1.19.1/docs/ares_set_sortlist.3 diff --git a/lib/c-ares-1.19.0/docs/ares_strerror.3 b/lib/c-ares-1.19.1/docs/ares_strerror.3 similarity index 100% rename from lib/c-ares-1.19.0/docs/ares_strerror.3 rename to lib/c-ares-1.19.1/docs/ares_strerror.3 diff --git a/lib/c-ares-1.19.0/docs/ares_timeout.3 b/lib/c-ares-1.19.1/docs/ares_timeout.3 similarity index 100% rename from lib/c-ares-1.19.0/docs/ares_timeout.3 rename to lib/c-ares-1.19.1/docs/ares_timeout.3 diff --git a/lib/c-ares-1.19.0/docs/ares_version.3 b/lib/c-ares-1.19.1/docs/ares_version.3 similarity index 100% rename from lib/c-ares-1.19.0/docs/ares_version.3 rename to lib/c-ares-1.19.1/docs/ares_version.3 diff --git a/lib/c-ares-1.19.0/get_ver.awk b/lib/c-ares-1.19.1/get_ver.awk similarity index 100% rename from lib/c-ares-1.19.0/get_ver.awk rename to lib/c-ares-1.19.1/get_ver.awk diff --git a/lib/c-ares-1.19.0/include/CMakeLists.txt b/lib/c-ares-1.19.1/include/CMakeLists.txt similarity index 100% rename from lib/c-ares-1.19.0/include/CMakeLists.txt rename to lib/c-ares-1.19.1/include/CMakeLists.txt diff --git a/lib/c-ares-1.19.0/include/Makefile.am b/lib/c-ares-1.19.1/include/Makefile.am similarity index 100% rename from lib/c-ares-1.19.0/include/Makefile.am rename to lib/c-ares-1.19.1/include/Makefile.am diff --git a/lib/c-ares-1.19.0/include/Makefile.in b/lib/c-ares-1.19.1/include/Makefile.in similarity index 99% rename from lib/c-ares-1.19.0/include/Makefile.in rename to lib/c-ares-1.19.1/include/Makefile.in index 40c1d51fb17..8586bd52f11 100644 --- a/lib/c-ares-1.19.0/include/Makefile.in +++ b/lib/c-ares-1.19.1/include/Makefile.in @@ -96,6 +96,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_ac_append_to_file.m4 \ $(top_srcdir)/m4/ax_am_macros_static.m4 \ $(top_srcdir)/m4/ax_check_gnu_make.m4 \ $(top_srcdir)/m4/ax_code_coverage.m4 \ + $(top_srcdir)/m4/ax_cxx_compile_stdcxx.m4 \ $(top_srcdir)/m4/ax_cxx_compile_stdcxx_11.m4 \ $(top_srcdir)/m4/ax_file_escapes.m4 \ $(top_srcdir)/m4/ax_require_defined.m4 \ diff --git a/lib/c-ares-1.19.0/include/ares.h b/lib/c-ares-1.19.1/include/ares.h similarity index 100% rename from lib/c-ares-1.19.0/include/ares.h rename to lib/c-ares-1.19.1/include/ares.h diff --git a/lib/c-ares-1.19.0/include/ares_build.h b/lib/c-ares-1.19.1/include/ares_build.h similarity index 100% rename from lib/c-ares-1.19.0/include/ares_build.h rename to lib/c-ares-1.19.1/include/ares_build.h diff --git a/lib/c-ares-1.19.0/include/ares_build.h.cmake b/lib/c-ares-1.19.1/include/ares_build.h.cmake similarity index 100% rename from lib/c-ares-1.19.0/include/ares_build.h.cmake rename to lib/c-ares-1.19.1/include/ares_build.h.cmake diff --git a/lib/c-ares-1.19.0/include/ares_build.h.in b/lib/c-ares-1.19.1/include/ares_build.h.in similarity index 100% rename from lib/c-ares-1.19.0/include/ares_build.h.in rename to lib/c-ares-1.19.1/include/ares_build.h.in diff --git a/lib/c-ares-1.19.0/include/ares_dns.h b/lib/c-ares-1.19.1/include/ares_dns.h similarity index 100% rename from lib/c-ares-1.19.0/include/ares_dns.h rename to lib/c-ares-1.19.1/include/ares_dns.h diff --git a/lib/c-ares-1.19.0/include/ares_nameser.h b/lib/c-ares-1.19.1/include/ares_nameser.h similarity index 100% rename from lib/c-ares-1.19.0/include/ares_nameser.h rename to lib/c-ares-1.19.1/include/ares_nameser.h diff --git a/lib/c-ares-1.19.0/include/ares_rules.h b/lib/c-ares-1.19.1/include/ares_rules.h similarity index 100% rename from lib/c-ares-1.19.0/include/ares_rules.h rename to lib/c-ares-1.19.1/include/ares_rules.h diff --git a/lib/c-ares-1.19.0/include/ares_version.h b/lib/c-ares-1.19.1/include/ares_version.h similarity index 90% rename from lib/c-ares-1.19.0/include/ares_version.h rename to lib/c-ares-1.19.1/include/ares_version.h index 4d8d62fd18e..35a1ed1a3d3 100644 --- a/lib/c-ares-1.19.0/include/ares_version.h +++ b/lib/c-ares-1.19.1/include/ares_version.h @@ -7,11 +7,11 @@ #define ARES_VERSION_MAJOR 1 #define ARES_VERSION_MINOR 19 -#define ARES_VERSION_PATCH 0 +#define ARES_VERSION_PATCH 1 #define ARES_VERSION ((ARES_VERSION_MAJOR<<16)|\ (ARES_VERSION_MINOR<<8)|\ (ARES_VERSION_PATCH)) -#define ARES_VERSION_STR "1.19.0" +#define ARES_VERSION_STR "1.19.1" #if (ARES_VERSION >= 0x010700) # define CARES_HAVE_ARES_LIBRARY_INIT 1 diff --git a/lib/c-ares-1.19.0/install-sh b/lib/c-ares-1.19.1/install-sh similarity index 100% rename from lib/c-ares-1.19.0/install-sh rename to lib/c-ares-1.19.1/install-sh diff --git a/lib/c-ares-1.19.0/libcares.pc.cmake b/lib/c-ares-1.19.1/libcares.pc.cmake similarity index 100% rename from lib/c-ares-1.19.0/libcares.pc.cmake rename to lib/c-ares-1.19.1/libcares.pc.cmake diff --git a/lib/c-ares-1.19.0/libcares.pc.in b/lib/c-ares-1.19.1/libcares.pc.in similarity index 100% rename from lib/c-ares-1.19.0/libcares.pc.in rename to lib/c-ares-1.19.1/libcares.pc.in diff --git a/lib/c-ares-1.19.0/ltmain.sh b/lib/c-ares-1.19.1/ltmain.sh similarity index 100% rename from lib/c-ares-1.19.0/ltmain.sh rename to lib/c-ares-1.19.1/ltmain.sh diff --git a/lib/c-ares-1.19.0/m4/ax_ac_append_to_file.m4 b/lib/c-ares-1.19.1/m4/ax_ac_append_to_file.m4 similarity index 100% rename from lib/c-ares-1.19.0/m4/ax_ac_append_to_file.m4 rename to lib/c-ares-1.19.1/m4/ax_ac_append_to_file.m4 diff --git a/lib/c-ares-1.19.0/m4/ax_ac_print_to_file.m4 b/lib/c-ares-1.19.1/m4/ax_ac_print_to_file.m4 similarity index 100% rename from lib/c-ares-1.19.0/m4/ax_ac_print_to_file.m4 rename to lib/c-ares-1.19.1/m4/ax_ac_print_to_file.m4 diff --git a/lib/c-ares-1.19.0/m4/ax_add_am_macro_static.m4 b/lib/c-ares-1.19.1/m4/ax_add_am_macro_static.m4 similarity index 100% rename from lib/c-ares-1.19.0/m4/ax_add_am_macro_static.m4 rename to lib/c-ares-1.19.1/m4/ax_add_am_macro_static.m4 diff --git a/lib/c-ares-1.19.0/m4/ax_am_macros_static.m4 b/lib/c-ares-1.19.1/m4/ax_am_macros_static.m4 similarity index 100% rename from lib/c-ares-1.19.0/m4/ax_am_macros_static.m4 rename to lib/c-ares-1.19.1/m4/ax_am_macros_static.m4 diff --git a/lib/c-ares-1.19.0/m4/ax_check_gnu_make.m4 b/lib/c-ares-1.19.1/m4/ax_check_gnu_make.m4 similarity index 100% rename from lib/c-ares-1.19.0/m4/ax_check_gnu_make.m4 rename to lib/c-ares-1.19.1/m4/ax_check_gnu_make.m4 diff --git a/lib/c-ares-1.19.0/m4/ax_check_user_namespace.m4 b/lib/c-ares-1.19.1/m4/ax_check_user_namespace.m4 similarity index 100% rename from lib/c-ares-1.19.0/m4/ax_check_user_namespace.m4 rename to lib/c-ares-1.19.1/m4/ax_check_user_namespace.m4 diff --git a/lib/c-ares-1.19.0/m4/ax_check_uts_namespace.m4 b/lib/c-ares-1.19.1/m4/ax_check_uts_namespace.m4 similarity index 100% rename from lib/c-ares-1.19.0/m4/ax_check_uts_namespace.m4 rename to lib/c-ares-1.19.1/m4/ax_check_uts_namespace.m4 diff --git a/lib/c-ares-1.19.0/m4/ax_code_coverage.m4 b/lib/c-ares-1.19.1/m4/ax_code_coverage.m4 similarity index 100% rename from lib/c-ares-1.19.0/m4/ax_code_coverage.m4 rename to lib/c-ares-1.19.1/m4/ax_code_coverage.m4 diff --git a/lib/c-ares-1.19.1/m4/ax_cxx_compile_stdcxx.m4 b/lib/c-ares-1.19.1/m4/ax_cxx_compile_stdcxx.m4 new file mode 100644 index 00000000000..a3d964c699a --- /dev/null +++ b/lib/c-ares-1.19.1/m4/ax_cxx_compile_stdcxx.m4 @@ -0,0 +1,1009 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CXX_COMPILE_STDCXX(VERSION, [ext|noext], [mandatory|optional]) +# +# DESCRIPTION +# +# Check for baseline language coverage in the compiler for the specified +# version of the C++ standard. If necessary, add switches to CXX and +# CXXCPP to enable support. VERSION may be '11', '14', '17', or '20' for +# the respective C++ standard version. +# +# The second argument, if specified, indicates whether you insist on an +# extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g. +# -std=c++11). If neither is specified, you get whatever works, with +# preference for no added switch, and then for an extended mode. +# +# The third argument, if specified 'mandatory' or if left unspecified, +# indicates that baseline support for the specified C++ standard is +# required and that the macro should error out if no mode with that +# support is found. If specified 'optional', then configuration proceeds +# regardless, after defining HAVE_CXX${VERSION} if and only if a +# supporting mode is found. +# +# LICENSE +# +# Copyright (c) 2008 Benjamin Kosnik +# Copyright (c) 2012 Zack Weinberg +# Copyright (c) 2013 Roy Stogner +# Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov +# Copyright (c) 2015 Paul Norman +# Copyright (c) 2015 Moritz Klammler +# Copyright (c) 2016, 2018 Krzesimir Nowak +# Copyright (c) 2019 Enji Cooper +# Copyright (c) 2020 Jason Merrill +# Copyright (c) 2021 Jörn Heusipp +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 15 + +dnl This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro +dnl (serial version number 13). + +AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl + m4_if([$1], [11], [ax_cxx_compile_alternatives="11 0x"], + [$1], [14], [ax_cxx_compile_alternatives="14 1y"], + [$1], [17], [ax_cxx_compile_alternatives="17 1z"], + [$1], [20], [ax_cxx_compile_alternatives="20"], + [m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl + m4_if([$2], [], [], + [$2], [ext], [], + [$2], [noext], [], + [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX])])dnl + m4_if([$3], [], [ax_cxx_compile_cxx$1_required=true], + [$3], [mandatory], [ax_cxx_compile_cxx$1_required=true], + [$3], [optional], [ax_cxx_compile_cxx$1_required=false], + [m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])]) + AC_LANG_PUSH([C++])dnl + ac_success=no + + m4_if([$2], [], [dnl + AC_CACHE_CHECK(whether $CXX supports C++$1 features by default, + ax_cv_cxx_compile_cxx$1, + [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], + [ax_cv_cxx_compile_cxx$1=yes], + [ax_cv_cxx_compile_cxx$1=no])]) + if test x$ax_cv_cxx_compile_cxx$1 = xyes; then + ac_success=yes + fi]) + + m4_if([$2], [noext], [], [dnl + if test x$ac_success = xno; then + for alternative in ${ax_cxx_compile_alternatives}; do + switch="-std=gnu++${alternative}" + cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch]) + AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch, + $cachevar, + [ac_save_CXX="$CXX" + CXX="$CXX $switch" + AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], + [eval $cachevar=yes], + [eval $cachevar=no]) + CXX="$ac_save_CXX"]) + if eval test x\$$cachevar = xyes; then + CXX="$CXX $switch" + if test -n "$CXXCPP" ; then + CXXCPP="$CXXCPP $switch" + fi + ac_success=yes + break + fi + done + fi]) + + m4_if([$2], [ext], [], [dnl + if test x$ac_success = xno; then + dnl HP's aCC needs +std=c++11 according to: + dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf + dnl Cray's crayCC needs "-h std=c++11" + for alternative in ${ax_cxx_compile_alternatives}; do + for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}"; do + cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch]) + AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch, + $cachevar, + [ac_save_CXX="$CXX" + CXX="$CXX $switch" + AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], + [eval $cachevar=yes], + [eval $cachevar=no]) + CXX="$ac_save_CXX"]) + if eval test x\$$cachevar = xyes; then + CXX="$CXX $switch" + if test -n "$CXXCPP" ; then + CXXCPP="$CXXCPP $switch" + fi + ac_success=yes + break + fi + done + if test x$ac_success = xyes; then + break + fi + done + fi]) + AC_LANG_POP([C++]) + if test x$ax_cxx_compile_cxx$1_required = xtrue; then + if test x$ac_success = xno; then + AC_MSG_ERROR([*** A compiler with support for C++$1 language features is required.]) + fi + fi + if test x$ac_success = xno; then + HAVE_CXX$1=0 + AC_MSG_NOTICE([No compiler with C++$1 support was found]) + else + HAVE_CXX$1=1 + AC_DEFINE(HAVE_CXX$1,1, + [define if the compiler supports basic C++$1 syntax]) + fi + AC_SUBST(HAVE_CXX$1) +]) + + +dnl Test body for checking C++11 support + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_11], + _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 +) + +dnl Test body for checking C++14 support + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14], + _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 + _AX_CXX_COMPILE_STDCXX_testbody_new_in_14 +) + +dnl Test body for checking C++17 support + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_17], + _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 + _AX_CXX_COMPILE_STDCXX_testbody_new_in_14 + _AX_CXX_COMPILE_STDCXX_testbody_new_in_17 +) + +dnl Test body for checking C++20 support + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_20], + _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 + _AX_CXX_COMPILE_STDCXX_testbody_new_in_14 + _AX_CXX_COMPILE_STDCXX_testbody_new_in_17 + _AX_CXX_COMPILE_STDCXX_testbody_new_in_20 +) + + +dnl Tests for new features in C++11 + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[ + +// If the compiler admits that it is not ready for C++11, why torture it? +// Hopefully, this will speed up the test. + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +// MSVC always sets __cplusplus to 199711L in older versions; newer versions +// only set it correctly if /Zc:__cplusplus is specified as well as a +// /std:c++NN switch: +// https://devblogs.microsoft.com/cppblog/msvc-now-correctly-reports-__cplusplus/ +#elif __cplusplus < 201103L && !defined _MSC_VER + +#error "This is not a C++11 compiler" + +#else + +namespace cxx11 +{ + + namespace test_static_assert + { + + template + struct check + { + static_assert(sizeof(int) <= sizeof(T), "not big enough"); + }; + + } + + namespace test_final_override + { + + struct Base + { + virtual ~Base() {} + virtual void f() {} + }; + + struct Derived : public Base + { + virtual ~Derived() override {} + virtual void f() override {} + }; + + } + + namespace test_double_right_angle_brackets + { + + template < typename T > + struct check {}; + + typedef check single_type; + typedef check> double_type; + typedef check>> triple_type; + typedef check>>> quadruple_type; + + } + + namespace test_decltype + { + + int + f() + { + int a = 1; + decltype(a) b = 2; + return a + b; + } + + } + + namespace test_type_deduction + { + + template < typename T1, typename T2 > + struct is_same + { + static const bool value = false; + }; + + template < typename T > + struct is_same + { + static const bool value = true; + }; + + template < typename T1, typename T2 > + auto + add(T1 a1, T2 a2) -> decltype(a1 + a2) + { + return a1 + a2; + } + + int + test(const int c, volatile int v) + { + static_assert(is_same::value == true, ""); + static_assert(is_same::value == false, ""); + static_assert(is_same::value == false, ""); + auto ac = c; + auto av = v; + auto sumi = ac + av + 'x'; + auto sumf = ac + av + 1.0; + static_assert(is_same::value == true, ""); + static_assert(is_same::value == true, ""); + static_assert(is_same::value == true, ""); + static_assert(is_same::value == false, ""); + static_assert(is_same::value == true, ""); + return (sumf > 0.0) ? sumi : add(c, v); + } + + } + + namespace test_noexcept + { + + int f() { return 0; } + int g() noexcept { return 0; } + + static_assert(noexcept(f()) == false, ""); + static_assert(noexcept(g()) == true, ""); + + } + + namespace test_constexpr + { + + template < typename CharT > + unsigned long constexpr + strlen_c_r(const CharT *const s, const unsigned long acc) noexcept + { + return *s ? strlen_c_r(s + 1, acc + 1) : acc; + } + + template < typename CharT > + unsigned long constexpr + strlen_c(const CharT *const s) noexcept + { + return strlen_c_r(s, 0UL); + } + + static_assert(strlen_c("") == 0UL, ""); + static_assert(strlen_c("1") == 1UL, ""); + static_assert(strlen_c("example") == 7UL, ""); + static_assert(strlen_c("another\0example") == 7UL, ""); + + } + + namespace test_rvalue_references + { + + template < int N > + struct answer + { + static constexpr int value = N; + }; + + answer<1> f(int&) { return answer<1>(); } + answer<2> f(const int&) { return answer<2>(); } + answer<3> f(int&&) { return answer<3>(); } + + void + test() + { + int i = 0; + const int c = 0; + static_assert(decltype(f(i))::value == 1, ""); + static_assert(decltype(f(c))::value == 2, ""); + static_assert(decltype(f(0))::value == 3, ""); + } + + } + + namespace test_uniform_initialization + { + + struct test + { + static const int zero {}; + static const int one {1}; + }; + + static_assert(test::zero == 0, ""); + static_assert(test::one == 1, ""); + + } + + namespace test_lambdas + { + + void + test1() + { + auto lambda1 = [](){}; + auto lambda2 = lambda1; + lambda1(); + lambda2(); + } + + int + test2() + { + auto a = [](int i, int j){ return i + j; }(1, 2); + auto b = []() -> int { return '0'; }(); + auto c = [=](){ return a + b; }(); + auto d = [&](){ return c; }(); + auto e = [a, &b](int x) mutable { + const auto identity = [](int y){ return y; }; + for (auto i = 0; i < a; ++i) + a += b--; + return x + identity(a + b); + }(0); + return a + b + c + d + e; + } + + int + test3() + { + const auto nullary = [](){ return 0; }; + const auto unary = [](int x){ return x; }; + using nullary_t = decltype(nullary); + using unary_t = decltype(unary); + const auto higher1st = [](nullary_t f){ return f(); }; + const auto higher2nd = [unary](nullary_t f1){ + return [unary, f1](unary_t f2){ return f2(unary(f1())); }; + }; + return higher1st(nullary) + higher2nd(nullary)(unary); + } + + } + + namespace test_variadic_templates + { + + template + struct sum; + + template + struct sum + { + static constexpr auto value = N0 + sum::value; + }; + + template <> + struct sum<> + { + static constexpr auto value = 0; + }; + + static_assert(sum<>::value == 0, ""); + static_assert(sum<1>::value == 1, ""); + static_assert(sum<23>::value == 23, ""); + static_assert(sum<1, 2>::value == 3, ""); + static_assert(sum<5, 5, 11>::value == 21, ""); + static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, ""); + + } + + // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae + // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function + // because of this. + namespace test_template_alias_sfinae + { + + struct foo {}; + + template + using member = typename T::member_type; + + template + void func(...) {} + + template + void func(member*) {} + + void test(); + + void test() { func(0); } + + } + +} // namespace cxx11 + +#endif // __cplusplus >= 201103L + +]]) + + +dnl Tests for new features in C++14 + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_14], [[ + +// If the compiler admits that it is not ready for C++14, why torture it? +// Hopefully, this will speed up the test. + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +#elif __cplusplus < 201402L && !defined _MSC_VER + +#error "This is not a C++14 compiler" + +#else + +namespace cxx14 +{ + + namespace test_polymorphic_lambdas + { + + int + test() + { + const auto lambda = [](auto&&... args){ + const auto istiny = [](auto x){ + return (sizeof(x) == 1UL) ? 1 : 0; + }; + const int aretiny[] = { istiny(args)... }; + return aretiny[0]; + }; + return lambda(1, 1L, 1.0f, '1'); + } + + } + + namespace test_binary_literals + { + + constexpr auto ivii = 0b0000000000101010; + static_assert(ivii == 42, "wrong value"); + + } + + namespace test_generalized_constexpr + { + + template < typename CharT > + constexpr unsigned long + strlen_c(const CharT *const s) noexcept + { + auto length = 0UL; + for (auto p = s; *p; ++p) + ++length; + return length; + } + + static_assert(strlen_c("") == 0UL, ""); + static_assert(strlen_c("x") == 1UL, ""); + static_assert(strlen_c("test") == 4UL, ""); + static_assert(strlen_c("another\0test") == 7UL, ""); + + } + + namespace test_lambda_init_capture + { + + int + test() + { + auto x = 0; + const auto lambda1 = [a = x](int b){ return a + b; }; + const auto lambda2 = [a = lambda1(x)](){ return a; }; + return lambda2(); + } + + } + + namespace test_digit_separators + { + + constexpr auto ten_million = 100'000'000; + static_assert(ten_million == 100000000, ""); + + } + + namespace test_return_type_deduction + { + + auto f(int& x) { return x; } + decltype(auto) g(int& x) { return x; } + + template < typename T1, typename T2 > + struct is_same + { + static constexpr auto value = false; + }; + + template < typename T > + struct is_same + { + static constexpr auto value = true; + }; + + int + test() + { + auto x = 0; + static_assert(is_same::value, ""); + static_assert(is_same::value, ""); + return x; + } + + } + +} // namespace cxx14 + +#endif // __cplusplus >= 201402L + +]]) + + +dnl Tests for new features in C++17 + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_17], [[ + +// If the compiler admits that it is not ready for C++17, why torture it? +// Hopefully, this will speed up the test. + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +#elif __cplusplus < 201703L && !defined _MSC_VER + +#error "This is not a C++17 compiler" + +#else + +#include +#include +#include + +namespace cxx17 +{ + + namespace test_constexpr_lambdas + { + + constexpr int foo = [](){return 42;}(); + + } + + namespace test::nested_namespace::definitions + { + + } + + namespace test_fold_expression + { + + template + int multiply(Args... args) + { + return (args * ... * 1); + } + + template + bool all(Args... args) + { + return (args && ...); + } + + } + + namespace test_extended_static_assert + { + + static_assert (true); + + } + + namespace test_auto_brace_init_list + { + + auto foo = {5}; + auto bar {5}; + + static_assert(std::is_same, decltype(foo)>::value); + static_assert(std::is_same::value); + } + + namespace test_typename_in_template_template_parameter + { + + template typename X> struct D; + + } + + namespace test_fallthrough_nodiscard_maybe_unused_attributes + { + + int f1() + { + return 42; + } + + [[nodiscard]] int f2() + { + [[maybe_unused]] auto unused = f1(); + + switch (f1()) + { + case 17: + f1(); + [[fallthrough]]; + case 42: + f1(); + } + return f1(); + } + + } + + namespace test_extended_aggregate_initialization + { + + struct base1 + { + int b1, b2 = 42; + }; + + struct base2 + { + base2() { + b3 = 42; + } + int b3; + }; + + struct derived : base1, base2 + { + int d; + }; + + derived d1 {{1, 2}, {}, 4}; // full initialization + derived d2 {{}, {}, 4}; // value-initialized bases + + } + + namespace test_general_range_based_for_loop + { + + struct iter + { + int i; + + int& operator* () + { + return i; + } + + const int& operator* () const + { + return i; + } + + iter& operator++() + { + ++i; + return *this; + } + }; + + struct sentinel + { + int i; + }; + + bool operator== (const iter& i, const sentinel& s) + { + return i.i == s.i; + } + + bool operator!= (const iter& i, const sentinel& s) + { + return !(i == s); + } + + struct range + { + iter begin() const + { + return {0}; + } + + sentinel end() const + { + return {5}; + } + }; + + void f() + { + range r {}; + + for (auto i : r) + { + [[maybe_unused]] auto v = i; + } + } + + } + + namespace test_lambda_capture_asterisk_this_by_value + { + + struct t + { + int i; + int foo() + { + return [*this]() + { + return i; + }(); + } + }; + + } + + namespace test_enum_class_construction + { + + enum class byte : unsigned char + {}; + + byte foo {42}; + + } + + namespace test_constexpr_if + { + + template + int f () + { + if constexpr(cond) + { + return 13; + } + else + { + return 42; + } + } + + } + + namespace test_selection_statement_with_initializer + { + + int f() + { + return 13; + } + + int f2() + { + if (auto i = f(); i > 0) + { + return 3; + } + + switch (auto i = f(); i + 4) + { + case 17: + return 2; + + default: + return 1; + } + } + + } + + namespace test_template_argument_deduction_for_class_templates + { + + template + struct pair + { + pair (T1 p1, T2 p2) + : m1 {p1}, + m2 {p2} + {} + + T1 m1; + T2 m2; + }; + + void f() + { + [[maybe_unused]] auto p = pair{13, 42u}; + } + + } + + namespace test_non_type_auto_template_parameters + { + + template + struct B + {}; + + B<5> b1; + B<'a'> b2; + + } + + namespace test_structured_bindings + { + + int arr[2] = { 1, 2 }; + std::pair pr = { 1, 2 }; + + auto f1() -> int(&)[2] + { + return arr; + } + + auto f2() -> std::pair& + { + return pr; + } + + struct S + { + int x1 : 2; + volatile double y1; + }; + + S f3() + { + return {}; + } + + auto [ x1, y1 ] = f1(); + auto& [ xr1, yr1 ] = f1(); + auto [ x2, y2 ] = f2(); + auto& [ xr2, yr2 ] = f2(); + const auto [ x3, y3 ] = f3(); + + } + + namespace test_exception_spec_type_system + { + + struct Good {}; + struct Bad {}; + + void g1() noexcept; + void g2(); + + template + Bad + f(T*, T*); + + template + Good + f(T1*, T2*); + + static_assert (std::is_same_v); + + } + + namespace test_inline_variables + { + + template void f(T) + {} + + template inline T g(T) + { + return T{}; + } + + template<> inline void f<>(int) + {} + + template<> int g<>(int) + { + return 5; + } + + } + +} // namespace cxx17 + +#endif // __cplusplus < 201703L && !defined _MSC_VER + +]]) + + +dnl Tests for new features in C++20 + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_20], [[ + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +#elif __cplusplus < 202002L && !defined _MSC_VER + +#error "This is not a C++20 compiler" + +#else + +#include + +namespace cxx20 +{ + +// As C++20 supports feature test macros in the standard, there is no +// immediate need to actually test for feature availability on the +// Autoconf side. + +} // namespace cxx20 + +#endif // __cplusplus < 202002L && !defined _MSC_VER + +]]) diff --git a/lib/c-ares-1.19.1/m4/ax_cxx_compile_stdcxx_11.m4 b/lib/c-ares-1.19.1/m4/ax_cxx_compile_stdcxx_11.m4 new file mode 100644 index 00000000000..1733fd85f95 --- /dev/null +++ b/lib/c-ares-1.19.1/m4/ax_cxx_compile_stdcxx_11.m4 @@ -0,0 +1,39 @@ +# ============================================================================= +# https://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_11.html +# ============================================================================= +# +# SYNOPSIS +# +# AX_CXX_COMPILE_STDCXX_11([ext|noext], [mandatory|optional]) +# +# DESCRIPTION +# +# Check for baseline language coverage in the compiler for the C++11 +# standard; if necessary, add switches to CXX and CXXCPP to enable +# support. +# +# This macro is a convenience alias for calling the AX_CXX_COMPILE_STDCXX +# macro with the version set to C++11. The two optional arguments are +# forwarded literally as the second and third argument respectively. +# Please see the documentation for the AX_CXX_COMPILE_STDCXX macro for +# more information. If you want to use this macro, you also need to +# download the ax_cxx_compile_stdcxx.m4 file. +# +# LICENSE +# +# Copyright (c) 2008 Benjamin Kosnik +# Copyright (c) 2012 Zack Weinberg +# Copyright (c) 2013 Roy Stogner +# Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov +# Copyright (c) 2015 Paul Norman +# Copyright (c) 2015 Moritz Klammler +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 18 + +AX_REQUIRE_DEFINED([AX_CXX_COMPILE_STDCXX]) +AC_DEFUN([AX_CXX_COMPILE_STDCXX_11], [AX_CXX_COMPILE_STDCXX([11], [$1], [$2])]) diff --git a/lib/c-ares-1.19.0/m4/ax_file_escapes.m4 b/lib/c-ares-1.19.1/m4/ax_file_escapes.m4 similarity index 100% rename from lib/c-ares-1.19.0/m4/ax_file_escapes.m4 rename to lib/c-ares-1.19.1/m4/ax_file_escapes.m4 diff --git a/lib/c-ares-1.19.1/m4/ax_pthread.m4 b/lib/c-ares-1.19.1/m4/ax_pthread.m4 new file mode 100644 index 00000000000..9f35d139149 --- /dev/null +++ b/lib/c-ares-1.19.1/m4/ax_pthread.m4 @@ -0,0 +1,522 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_pthread.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) +# +# DESCRIPTION +# +# This macro figures out how to build C programs using POSIX threads. It +# sets the PTHREAD_LIBS output variable to the threads library and linker +# flags, and the PTHREAD_CFLAGS output variable to any special C compiler +# flags that are needed. (The user can also force certain compiler +# flags/libs to be tested by setting these environment variables.) +# +# Also sets PTHREAD_CC and PTHREAD_CXX to any special C compiler that is +# needed for multi-threaded programs (defaults to the value of CC +# respectively CXX otherwise). (This is necessary on e.g. AIX to use the +# special cc_r/CC_r compiler alias.) +# +# NOTE: You are assumed to not only compile your program with these flags, +# but also to link with them as well. For example, you might link with +# $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS +# $PTHREAD_CXX $CXXFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS +# +# If you are only building threaded programs, you may wish to use these +# variables in your default LIBS, CFLAGS, and CC: +# +# LIBS="$PTHREAD_LIBS $LIBS" +# CFLAGS="$CFLAGS $PTHREAD_CFLAGS" +# CXXFLAGS="$CXXFLAGS $PTHREAD_CFLAGS" +# CC="$PTHREAD_CC" +# CXX="$PTHREAD_CXX" +# +# In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant +# has a nonstandard name, this macro defines PTHREAD_CREATE_JOINABLE to +# that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX). +# +# Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the +# PTHREAD_PRIO_INHERIT symbol is defined when compiling with +# PTHREAD_CFLAGS. +# +# ACTION-IF-FOUND is a list of shell commands to run if a threads library +# is found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it +# is not found. If ACTION-IF-FOUND is not specified, the default action +# will define HAVE_PTHREAD. +# +# Please let the authors know if this macro fails on any platform, or if +# you have any other suggestions or comments. This macro was based on work +# by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) (with help +# from M. Frigo), as well as ac_pthread and hb_pthread macros posted by +# Alejandro Forero Cuervo to the autoconf macro repository. We are also +# grateful for the helpful feedback of numerous users. +# +# Updated for Autoconf 2.68 by Daniel Richard G. +# +# LICENSE +# +# Copyright (c) 2008 Steven G. Johnson +# Copyright (c) 2011 Daniel Richard G. +# Copyright (c) 2019 Marc Stevens +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 31 + +AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD]) +AC_DEFUN([AX_PTHREAD], [ +AC_REQUIRE([AC_CANONICAL_HOST]) +AC_REQUIRE([AC_PROG_CC]) +AC_REQUIRE([AC_PROG_SED]) +AC_LANG_PUSH([C]) +ax_pthread_ok=no + +# We used to check for pthread.h first, but this fails if pthread.h +# requires special compiler flags (e.g. on Tru64 or Sequent). +# It gets checked for in the link test anyway. + +# First of all, check if the user has set any of the PTHREAD_LIBS, +# etcetera environment variables, and if threads linking works using +# them: +if test "x$PTHREAD_CFLAGS$PTHREAD_LIBS" != "x"; then + ax_pthread_save_CC="$CC" + ax_pthread_save_CFLAGS="$CFLAGS" + ax_pthread_save_LIBS="$LIBS" + AS_IF([test "x$PTHREAD_CC" != "x"], [CC="$PTHREAD_CC"]) + AS_IF([test "x$PTHREAD_CXX" != "x"], [CXX="$PTHREAD_CXX"]) + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + LIBS="$PTHREAD_LIBS $LIBS" + AC_MSG_CHECKING([for pthread_join using $CC $PTHREAD_CFLAGS $PTHREAD_LIBS]) + AC_LINK_IFELSE([AC_LANG_CALL([], [pthread_join])], [ax_pthread_ok=yes]) + AC_MSG_RESULT([$ax_pthread_ok]) + if test "x$ax_pthread_ok" = "xno"; then + PTHREAD_LIBS="" + PTHREAD_CFLAGS="" + fi + CC="$ax_pthread_save_CC" + CFLAGS="$ax_pthread_save_CFLAGS" + LIBS="$ax_pthread_save_LIBS" +fi + +# We must check for the threads library under a number of different +# names; the ordering is very important because some systems +# (e.g. DEC) have both -lpthread and -lpthreads, where one of the +# libraries is broken (non-POSIX). + +# Create a list of thread flags to try. Items with a "," contain both +# C compiler flags (before ",") and linker flags (after ","). Other items +# starting with a "-" are C compiler flags, and remaining items are +# library names, except for "none" which indicates that we try without +# any flags at all, and "pthread-config" which is a program returning +# the flags for the Pth emulation library. + +ax_pthread_flags="pthreads none -Kthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" + +# The ordering *is* (sometimes) important. Some notes on the +# individual items follow: + +# pthreads: AIX (must check this before -lpthread) +# none: in case threads are in libc; should be tried before -Kthread and +# other compiler flags to prevent continual compiler warnings +# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) +# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads), Tru64 +# (Note: HP C rejects this with "bad form for `-t' option") +# -pthreads: Solaris/gcc (Note: HP C also rejects) +# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it +# doesn't hurt to check since this sometimes defines pthreads and +# -D_REENTRANT too), HP C (must be checked before -lpthread, which +# is present but should not be used directly; and before -mthreads, +# because the compiler interprets this as "-mt" + "-hreads") +# -mthreads: Mingw32/gcc, Lynx/gcc +# pthread: Linux, etcetera +# --thread-safe: KAI C++ +# pthread-config: use pthread-config program (for GNU Pth library) + +case $host_os in + + freebsd*) + + # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) + # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) + + ax_pthread_flags="-kthread lthread $ax_pthread_flags" + ;; + + hpux*) + + # From the cc(1) man page: "[-mt] Sets various -D flags to enable + # multi-threading and also sets -lpthread." + + ax_pthread_flags="-mt -pthread pthread $ax_pthread_flags" + ;; + + openedition*) + + # IBM z/OS requires a feature-test macro to be defined in order to + # enable POSIX threads at all, so give the user a hint if this is + # not set. (We don't define these ourselves, as they can affect + # other portions of the system API in unpredictable ways.) + + AC_EGREP_CPP([AX_PTHREAD_ZOS_MISSING], + [ +# if !defined(_OPEN_THREADS) && !defined(_UNIX03_THREADS) + AX_PTHREAD_ZOS_MISSING +# endif + ], + [AC_MSG_WARN([IBM z/OS requires -D_OPEN_THREADS or -D_UNIX03_THREADS to enable pthreads support.])]) + ;; + + solaris*) + + # On Solaris (at least, for some versions), libc contains stubbed + # (non-functional) versions of the pthreads routines, so link-based + # tests will erroneously succeed. (N.B.: The stubs are missing + # pthread_cleanup_push, or rather a function called by this macro, + # so we could check for that, but who knows whether they'll stub + # that too in a future libc.) So we'll check first for the + # standard Solaris way of linking pthreads (-mt -lpthread). + + ax_pthread_flags="-mt,-lpthread pthread $ax_pthread_flags" + ;; +esac + +# Are we compiling with Clang? + +AC_CACHE_CHECK([whether $CC is Clang], + [ax_cv_PTHREAD_CLANG], + [ax_cv_PTHREAD_CLANG=no + # Note that Autoconf sets GCC=yes for Clang as well as GCC + if test "x$GCC" = "xyes"; then + AC_EGREP_CPP([AX_PTHREAD_CC_IS_CLANG], + [/* Note: Clang 2.7 lacks __clang_[a-z]+__ */ +# if defined(__clang__) && defined(__llvm__) + AX_PTHREAD_CC_IS_CLANG +# endif + ], + [ax_cv_PTHREAD_CLANG=yes]) + fi + ]) +ax_pthread_clang="$ax_cv_PTHREAD_CLANG" + + +# GCC generally uses -pthread, or -pthreads on some platforms (e.g. SPARC) + +# Note that for GCC and Clang -pthread generally implies -lpthread, +# except when -nostdlib is passed. +# This is problematic using libtool to build C++ shared libraries with pthread: +# [1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=25460 +# [2] https://bugzilla.redhat.com/show_bug.cgi?id=661333 +# [3] https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=468555 +# To solve this, first try -pthread together with -lpthread for GCC + +AS_IF([test "x$GCC" = "xyes"], + [ax_pthread_flags="-pthread,-lpthread -pthread -pthreads $ax_pthread_flags"]) + +# Clang takes -pthread (never supported any other flag), but we'll try with -lpthread first + +AS_IF([test "x$ax_pthread_clang" = "xyes"], + [ax_pthread_flags="-pthread,-lpthread -pthread"]) + + +# The presence of a feature test macro requesting re-entrant function +# definitions is, on some systems, a strong hint that pthreads support is +# correctly enabled + +case $host_os in + darwin* | hpux* | linux* | osf* | solaris*) + ax_pthread_check_macro="_REENTRANT" + ;; + + aix*) + ax_pthread_check_macro="_THREAD_SAFE" + ;; + + *) + ax_pthread_check_macro="--" + ;; +esac +AS_IF([test "x$ax_pthread_check_macro" = "x--"], + [ax_pthread_check_cond=0], + [ax_pthread_check_cond="!defined($ax_pthread_check_macro)"]) + + +if test "x$ax_pthread_ok" = "xno"; then +for ax_pthread_try_flag in $ax_pthread_flags; do + + case $ax_pthread_try_flag in + none) + AC_MSG_CHECKING([whether pthreads work without any flags]) + ;; + + *,*) + PTHREAD_CFLAGS=`echo $ax_pthread_try_flag | sed "s/^\(.*\),\(.*\)$/\1/"` + PTHREAD_LIBS=`echo $ax_pthread_try_flag | sed "s/^\(.*\),\(.*\)$/\2/"` + AC_MSG_CHECKING([whether pthreads work with "$PTHREAD_CFLAGS" and "$PTHREAD_LIBS"]) + ;; + + -*) + AC_MSG_CHECKING([whether pthreads work with $ax_pthread_try_flag]) + PTHREAD_CFLAGS="$ax_pthread_try_flag" + ;; + + pthread-config) + AC_CHECK_PROG([ax_pthread_config], [pthread-config], [yes], [no]) + AS_IF([test "x$ax_pthread_config" = "xno"], [continue]) + PTHREAD_CFLAGS="`pthread-config --cflags`" + PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" + ;; + + *) + AC_MSG_CHECKING([for the pthreads library -l$ax_pthread_try_flag]) + PTHREAD_LIBS="-l$ax_pthread_try_flag" + ;; + esac + + ax_pthread_save_CFLAGS="$CFLAGS" + ax_pthread_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + LIBS="$PTHREAD_LIBS $LIBS" + + # Check for various functions. We must include pthread.h, + # since some functions may be macros. (On the Sequent, we + # need a special flag -Kthread to make this header compile.) + # We check for pthread_join because it is in -lpthread on IRIX + # while pthread_create is in libc. We check for pthread_attr_init + # due to DEC craziness with -lpthreads. We check for + # pthread_cleanup_push because it is one of the few pthread + # functions on Solaris that doesn't have a non-functional libc stub. + # We try pthread_create on general principles. + + AC_LINK_IFELSE([AC_LANG_PROGRAM([#include +# if $ax_pthread_check_cond +# error "$ax_pthread_check_macro must be defined" +# endif + static void *some_global = NULL; + static void routine(void *a) + { + /* To avoid any unused-parameter or + unused-but-set-parameter warning. */ + some_global = a; + } + static void *start_routine(void *a) { return a; }], + [pthread_t th; pthread_attr_t attr; + pthread_create(&th, 0, start_routine, 0); + pthread_join(th, 0); + pthread_attr_init(&attr); + pthread_cleanup_push(routine, 0); + pthread_cleanup_pop(0) /* ; */])], + [ax_pthread_ok=yes], + []) + + CFLAGS="$ax_pthread_save_CFLAGS" + LIBS="$ax_pthread_save_LIBS" + + AC_MSG_RESULT([$ax_pthread_ok]) + AS_IF([test "x$ax_pthread_ok" = "xyes"], [break]) + + PTHREAD_LIBS="" + PTHREAD_CFLAGS="" +done +fi + + +# Clang needs special handling, because older versions handle the -pthread +# option in a rather... idiosyncratic way + +if test "x$ax_pthread_clang" = "xyes"; then + + # Clang takes -pthread; it has never supported any other flag + + # (Note 1: This will need to be revisited if a system that Clang + # supports has POSIX threads in a separate library. This tends not + # to be the way of modern systems, but it's conceivable.) + + # (Note 2: On some systems, notably Darwin, -pthread is not needed + # to get POSIX threads support; the API is always present and + # active. We could reasonably leave PTHREAD_CFLAGS empty. But + # -pthread does define _REENTRANT, and while the Darwin headers + # ignore this macro, third-party headers might not.) + + # However, older versions of Clang make a point of warning the user + # that, in an invocation where only linking and no compilation is + # taking place, the -pthread option has no effect ("argument unused + # during compilation"). They expect -pthread to be passed in only + # when source code is being compiled. + # + # Problem is, this is at odds with the way Automake and most other + # C build frameworks function, which is that the same flags used in + # compilation (CFLAGS) are also used in linking. Many systems + # supported by AX_PTHREAD require exactly this for POSIX threads + # support, and in fact it is often not straightforward to specify a + # flag that is used only in the compilation phase and not in + # linking. Such a scenario is extremely rare in practice. + # + # Even though use of the -pthread flag in linking would only print + # a warning, this can be a nuisance for well-run software projects + # that build with -Werror. So if the active version of Clang has + # this misfeature, we search for an option to squash it. + + AC_CACHE_CHECK([whether Clang needs flag to prevent "argument unused" warning when linking with -pthread], + [ax_cv_PTHREAD_CLANG_NO_WARN_FLAG], + [ax_cv_PTHREAD_CLANG_NO_WARN_FLAG=unknown + # Create an alternate version of $ac_link that compiles and + # links in two steps (.c -> .o, .o -> exe) instead of one + # (.c -> exe), because the warning occurs only in the second + # step + ax_pthread_save_ac_link="$ac_link" + ax_pthread_sed='s/conftest\.\$ac_ext/conftest.$ac_objext/g' + ax_pthread_link_step=`AS_ECHO(["$ac_link"]) | sed "$ax_pthread_sed"` + ax_pthread_2step_ac_link="($ac_compile) && (echo ==== >&5) && ($ax_pthread_link_step)" + ax_pthread_save_CFLAGS="$CFLAGS" + for ax_pthread_try in '' -Qunused-arguments -Wno-unused-command-line-argument unknown; do + AS_IF([test "x$ax_pthread_try" = "xunknown"], [break]) + CFLAGS="-Werror -Wunknown-warning-option $ax_pthread_try -pthread $ax_pthread_save_CFLAGS" + ac_link="$ax_pthread_save_ac_link" + AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])], + [ac_link="$ax_pthread_2step_ac_link" + AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])], + [break]) + ]) + done + ac_link="$ax_pthread_save_ac_link" + CFLAGS="$ax_pthread_save_CFLAGS" + AS_IF([test "x$ax_pthread_try" = "x"], [ax_pthread_try=no]) + ax_cv_PTHREAD_CLANG_NO_WARN_FLAG="$ax_pthread_try" + ]) + + case "$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" in + no | unknown) ;; + *) PTHREAD_CFLAGS="$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG $PTHREAD_CFLAGS" ;; + esac + +fi # $ax_pthread_clang = yes + + + +# Various other checks: +if test "x$ax_pthread_ok" = "xyes"; then + ax_pthread_save_CFLAGS="$CFLAGS" + ax_pthread_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + LIBS="$PTHREAD_LIBS $LIBS" + + # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. + AC_CACHE_CHECK([for joinable pthread attribute], + [ax_cv_PTHREAD_JOINABLE_ATTR], + [ax_cv_PTHREAD_JOINABLE_ATTR=unknown + for ax_pthread_attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do + AC_LINK_IFELSE([AC_LANG_PROGRAM([#include ], + [int attr = $ax_pthread_attr; return attr /* ; */])], + [ax_cv_PTHREAD_JOINABLE_ATTR=$ax_pthread_attr; break], + []) + done + ]) + AS_IF([test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xunknown" && \ + test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xPTHREAD_CREATE_JOINABLE" && \ + test "x$ax_pthread_joinable_attr_defined" != "xyes"], + [AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE], + [$ax_cv_PTHREAD_JOINABLE_ATTR], + [Define to necessary symbol if this constant + uses a non-standard name on your system.]) + ax_pthread_joinable_attr_defined=yes + ]) + + AC_CACHE_CHECK([whether more special flags are required for pthreads], + [ax_cv_PTHREAD_SPECIAL_FLAGS], + [ax_cv_PTHREAD_SPECIAL_FLAGS=no + case $host_os in + solaris*) + ax_cv_PTHREAD_SPECIAL_FLAGS="-D_POSIX_PTHREAD_SEMANTICS" + ;; + esac + ]) + AS_IF([test "x$ax_cv_PTHREAD_SPECIAL_FLAGS" != "xno" && \ + test "x$ax_pthread_special_flags_added" != "xyes"], + [PTHREAD_CFLAGS="$ax_cv_PTHREAD_SPECIAL_FLAGS $PTHREAD_CFLAGS" + ax_pthread_special_flags_added=yes]) + + AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT], + [ax_cv_PTHREAD_PRIO_INHERIT], + [AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], + [[int i = PTHREAD_PRIO_INHERIT; + return i;]])], + [ax_cv_PTHREAD_PRIO_INHERIT=yes], + [ax_cv_PTHREAD_PRIO_INHERIT=no]) + ]) + AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes" && \ + test "x$ax_pthread_prio_inherit_defined" != "xyes"], + [AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.]) + ax_pthread_prio_inherit_defined=yes + ]) + + CFLAGS="$ax_pthread_save_CFLAGS" + LIBS="$ax_pthread_save_LIBS" + + # More AIX lossage: compile with *_r variant + if test "x$GCC" != "xyes"; then + case $host_os in + aix*) + AS_CASE(["x/$CC"], + [x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6], + [#handle absolute path differently from PATH based program lookup + AS_CASE(["x$CC"], + [x/*], + [ + AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"]) + AS_IF([test "x${CXX}" != "x"], [AS_IF([AS_EXECUTABLE_P([${CXX}_r])],[PTHREAD_CXX="${CXX}_r"])]) + ], + [ + AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC]) + AS_IF([test "x${CXX}" != "x"], [AC_CHECK_PROGS([PTHREAD_CXX],[${CXX}_r],[$CXX])]) + ] + ) + ]) + ;; + esac + fi +fi + +test -n "$PTHREAD_CC" || PTHREAD_CC="$CC" +test -n "$PTHREAD_CXX" || PTHREAD_CXX="$CXX" + +AC_SUBST([PTHREAD_LIBS]) +AC_SUBST([PTHREAD_CFLAGS]) +AC_SUBST([PTHREAD_CC]) +AC_SUBST([PTHREAD_CXX]) + +# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: +if test "x$ax_pthread_ok" = "xyes"; then + ifelse([$1],,[AC_DEFINE([HAVE_PTHREAD],[1],[Define if you have POSIX threads libraries and header files.])],[$1]) + : +else + ax_pthread_ok=no + $2 +fi +AC_LANG_POP +])dnl AX_PTHREAD diff --git a/lib/c-ares-1.19.0/m4/ax_require_defined.m4 b/lib/c-ares-1.19.1/m4/ax_require_defined.m4 similarity index 100% rename from lib/c-ares-1.19.0/m4/ax_require_defined.m4 rename to lib/c-ares-1.19.1/m4/ax_require_defined.m4 diff --git a/lib/c-ares-1.19.0/m4/cares-compilers.m4 b/lib/c-ares-1.19.1/m4/cares-compilers.m4 similarity index 100% rename from lib/c-ares-1.19.0/m4/cares-compilers.m4 rename to lib/c-ares-1.19.1/m4/cares-compilers.m4 diff --git a/lib/c-ares-1.19.0/m4/cares-confopts.m4 b/lib/c-ares-1.19.1/m4/cares-confopts.m4 similarity index 100% rename from lib/c-ares-1.19.0/m4/cares-confopts.m4 rename to lib/c-ares-1.19.1/m4/cares-confopts.m4 diff --git a/lib/c-ares-1.19.0/m4/cares-functions.m4 b/lib/c-ares-1.19.1/m4/cares-functions.m4 similarity index 97% rename from lib/c-ares-1.19.0/m4/cares-functions.m4 rename to lib/c-ares-1.19.1/m4/cares-functions.m4 index 0f3992c7f08..d4f4f994c6f 100644 --- a/lib/c-ares-1.19.0/m4/cares-functions.m4 +++ b/lib/c-ares-1.19.1/m4/cares-functions.m4 @@ -3753,3 +3753,88 @@ AC_DEFUN([CARES_CHECK_FUNC_WRITEV], [ ac_cv_func_writev="no" fi ]) + +dnl CARES_CHECK_FUNC_ARC4RANDOM_BUF +dnl ------------------------------------------------- +dnl Verify if arc4random_buf is available, prototyped, and +dnl can be compiled. If all of these are true, and +dnl usage has not been previously disallowed with +dnl shell variable cares_disallow_arc4random_buf, then +dnl HAVE_ARC4RANDOM_BUF will be defined. + +AC_DEFUN([CARES_CHECK_FUNC_ARC4RANDOM_BUF], [ + AC_REQUIRE([CARES_INCLUDES_STDLIB])dnl + # + tst_links_arc4random_buf="unknown" + tst_proto_arc4random_buf="unknown" + tst_compi_arc4random_buf="unknown" + tst_allow_arc4random_buf="unknown" + # + AC_MSG_CHECKING([if arc4random_buf can be linked]) + AC_LINK_IFELSE([ + AC_LANG_FUNC_LINK_TRY([arc4random_buf]) + ],[ + AC_MSG_RESULT([yes]) + tst_links_arc4random_buf="yes" + ],[ + AC_MSG_RESULT([no]) + tst_links_arc4random_buf="no" + ]) + # + if test "$tst_links_arc4random_buf" = "yes"; then + AC_MSG_CHECKING([if arc4random_buf is prototyped]) + AC_EGREP_CPP([arc4random_buf],[ + $cares_includes_stdlib + ],[ + AC_MSG_RESULT([yes]) + tst_proto_arc4random_buf="yes" + ],[ + AC_MSG_RESULT([no]) + tst_proto_arc4random_buf="no" + ]) + fi + # + if test "$tst_proto_arc4random_buf" = "yes"; then + AC_MSG_CHECKING([if arc4random_buf is compilable]) + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([[ + $cares_includes_stdlib + ]],[[ + arc4random_buf(NULL, 0); + return 1; + ]]) + ],[ + AC_MSG_RESULT([yes]) + tst_compi_arc4random_buf="yes" + ],[ + AC_MSG_RESULT([no]) + tst_compi_arc4random_buf="no" + ]) + fi + # + if test "$tst_compi_arc4random_buf" = "yes"; then + AC_MSG_CHECKING([if arc4random_buf usage allowed]) + if test "x$cares_disallow_arc4random_buf" != "xyes"; then + AC_MSG_RESULT([yes]) + tst_allow_arc4random_buf="yes" + else + AC_MSG_RESULT([no]) + tst_allow_arc4random_buf="no" + fi + fi + # + AC_MSG_CHECKING([if arc4random_buf might be used]) + if test "$tst_links_arc4random_buf" = "yes" && + test "$tst_proto_arc4random_buf" = "yes" && + test "$tst_compi_arc4random_buf" = "yes" && + test "$tst_allow_arc4random_buf" = "yes"; then + AC_MSG_RESULT([yes]) + AC_DEFINE_UNQUOTED(HAVE_ARC4RANDOM_BUF, 1, + [Define to 1 if you have the arc4random_buf function.]) + ac_cv_func_arc4random_buf="yes" + else + AC_MSG_RESULT([no]) + ac_cv_func_arc4random_buf="no" + fi +]) + diff --git a/lib/c-ares-1.19.0/m4/cares-reentrant.m4 b/lib/c-ares-1.19.1/m4/cares-reentrant.m4 similarity index 100% rename from lib/c-ares-1.19.0/m4/cares-reentrant.m4 rename to lib/c-ares-1.19.1/m4/cares-reentrant.m4 diff --git a/lib/c-ares-1.19.0/m4/libtool.m4 b/lib/c-ares-1.19.1/m4/libtool.m4 similarity index 100% rename from lib/c-ares-1.19.0/m4/libtool.m4 rename to lib/c-ares-1.19.1/m4/libtool.m4 diff --git a/lib/c-ares-1.19.0/m4/ltoptions.m4 b/lib/c-ares-1.19.1/m4/ltoptions.m4 similarity index 100% rename from lib/c-ares-1.19.0/m4/ltoptions.m4 rename to lib/c-ares-1.19.1/m4/ltoptions.m4 diff --git a/lib/c-ares-1.19.0/m4/ltsugar.m4 b/lib/c-ares-1.19.1/m4/ltsugar.m4 similarity index 100% rename from lib/c-ares-1.19.0/m4/ltsugar.m4 rename to lib/c-ares-1.19.1/m4/ltsugar.m4 diff --git a/lib/c-ares-1.19.0/m4/ltversion.m4 b/lib/c-ares-1.19.1/m4/ltversion.m4 similarity index 100% rename from lib/c-ares-1.19.0/m4/ltversion.m4 rename to lib/c-ares-1.19.1/m4/ltversion.m4 diff --git a/lib/c-ares-1.19.0/m4/lt~obsolete.m4 b/lib/c-ares-1.19.1/m4/lt~obsolete.m4 similarity index 100% rename from lib/c-ares-1.19.0/m4/lt~obsolete.m4 rename to lib/c-ares-1.19.1/m4/lt~obsolete.m4 diff --git a/lib/c-ares-1.19.0/m4/xc-am-iface.m4 b/lib/c-ares-1.19.1/m4/xc-am-iface.m4 similarity index 100% rename from lib/c-ares-1.19.0/m4/xc-am-iface.m4 rename to lib/c-ares-1.19.1/m4/xc-am-iface.m4 diff --git a/lib/c-ares-1.19.0/m4/xc-cc-check.m4 b/lib/c-ares-1.19.1/m4/xc-cc-check.m4 similarity index 100% rename from lib/c-ares-1.19.0/m4/xc-cc-check.m4 rename to lib/c-ares-1.19.1/m4/xc-cc-check.m4 diff --git a/lib/c-ares-1.19.0/m4/xc-lt-iface.m4 b/lib/c-ares-1.19.1/m4/xc-lt-iface.m4 similarity index 100% rename from lib/c-ares-1.19.0/m4/xc-lt-iface.m4 rename to lib/c-ares-1.19.1/m4/xc-lt-iface.m4 diff --git a/lib/c-ares-1.19.0/m4/xc-translit.m4 b/lib/c-ares-1.19.1/m4/xc-translit.m4 similarity index 100% rename from lib/c-ares-1.19.0/m4/xc-translit.m4 rename to lib/c-ares-1.19.1/m4/xc-translit.m4 diff --git a/lib/c-ares-1.19.0/m4/xc-val-flgs.m4 b/lib/c-ares-1.19.1/m4/xc-val-flgs.m4 similarity index 100% rename from lib/c-ares-1.19.0/m4/xc-val-flgs.m4 rename to lib/c-ares-1.19.1/m4/xc-val-flgs.m4 diff --git a/lib/c-ares-1.19.0/m4/zz40-xc-ovr.m4 b/lib/c-ares-1.19.1/m4/zz40-xc-ovr.m4 similarity index 100% rename from lib/c-ares-1.19.0/m4/zz40-xc-ovr.m4 rename to lib/c-ares-1.19.1/m4/zz40-xc-ovr.m4 diff --git a/lib/c-ares-1.19.0/maketgz b/lib/c-ares-1.19.1/maketgz similarity index 100% rename from lib/c-ares-1.19.0/maketgz rename to lib/c-ares-1.19.1/maketgz diff --git a/lib/c-ares-1.19.0/missing b/lib/c-ares-1.19.1/missing similarity index 100% rename from lib/c-ares-1.19.0/missing rename to lib/c-ares-1.19.1/missing diff --git a/lib/c-ares-1.19.0/msvc_ver.inc b/lib/c-ares-1.19.1/msvc_ver.inc similarity index 100% rename from lib/c-ares-1.19.0/msvc_ver.inc rename to lib/c-ares-1.19.1/msvc_ver.inc diff --git a/lib/c-ares-1.19.0/src/CMakeLists.txt b/lib/c-ares-1.19.1/src/CMakeLists.txt similarity index 100% rename from lib/c-ares-1.19.0/src/CMakeLists.txt rename to lib/c-ares-1.19.1/src/CMakeLists.txt diff --git a/lib/c-ares-1.19.0/src/Makefile.am b/lib/c-ares-1.19.1/src/Makefile.am similarity index 100% rename from lib/c-ares-1.19.0/src/Makefile.am rename to lib/c-ares-1.19.1/src/Makefile.am diff --git a/lib/c-ares-1.19.0/src/Makefile.in b/lib/c-ares-1.19.1/src/Makefile.in similarity index 99% rename from lib/c-ares-1.19.0/src/Makefile.in rename to lib/c-ares-1.19.1/src/Makefile.in index da56f4c23ca..6aa63b002ad 100644 --- a/lib/c-ares-1.19.0/src/Makefile.in +++ b/lib/c-ares-1.19.1/src/Makefile.in @@ -95,6 +95,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_ac_append_to_file.m4 \ $(top_srcdir)/m4/ax_am_macros_static.m4 \ $(top_srcdir)/m4/ax_check_gnu_make.m4 \ $(top_srcdir)/m4/ax_code_coverage.m4 \ + $(top_srcdir)/m4/ax_cxx_compile_stdcxx.m4 \ $(top_srcdir)/m4/ax_cxx_compile_stdcxx_11.m4 \ $(top_srcdir)/m4/ax_file_escapes.m4 \ $(top_srcdir)/m4/ax_require_defined.m4 \ diff --git a/lib/c-ares-1.19.0/src/lib/CMakeLists.txt b/lib/c-ares-1.19.1/src/lib/CMakeLists.txt similarity index 100% rename from lib/c-ares-1.19.0/src/lib/CMakeLists.txt rename to lib/c-ares-1.19.1/src/lib/CMakeLists.txt diff --git a/lib/c-ares-1.19.0/src/lib/Makefile.am b/lib/c-ares-1.19.1/src/lib/Makefile.am similarity index 100% rename from lib/c-ares-1.19.0/src/lib/Makefile.am rename to lib/c-ares-1.19.1/src/lib/Makefile.am diff --git a/lib/c-ares-1.19.0/src/lib/Makefile.in b/lib/c-ares-1.19.1/src/lib/Makefile.in similarity index 98% rename from lib/c-ares-1.19.0/src/lib/Makefile.in rename to lib/c-ares-1.19.1/src/lib/Makefile.in index 71449c1c43b..f1ed8a0b0c5 100644 --- a/lib/c-ares-1.19.0/src/lib/Makefile.in +++ b/lib/c-ares-1.19.1/src/lib/Makefile.in @@ -15,7 +15,7 @@ @SET_MAKE@ # aminclude_static.am generated automatically by Autoconf -# from AX_AM_MACROS_STATIC on Sat Jan 28 10:29:54 CET 2023 +# from AX_AM_MACROS_STATIC on Mon May 22 13:34:17 CEST 2023 VPATH = @srcdir@ am__is_gnu_make = { \ @@ -106,6 +106,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_ac_append_to_file.m4 \ $(top_srcdir)/m4/ax_am_macros_static.m4 \ $(top_srcdir)/m4/ax_check_gnu_make.m4 \ $(top_srcdir)/m4/ax_code_coverage.m4 \ + $(top_srcdir)/m4/ax_cxx_compile_stdcxx.m4 \ $(top_srcdir)/m4/ax_cxx_compile_stdcxx_11.m4 \ $(top_srcdir)/m4/ax_file_escapes.m4 \ $(top_srcdir)/m4/ax_require_defined.m4 \ @@ -194,13 +195,14 @@ am__objects_1 = libcares_la-ares__addrinfo2hostent.lo \ libcares_la-ares_parse_txt_reply.lo \ libcares_la-ares_parse_uri_reply.lo \ libcares_la-ares_platform.lo libcares_la-ares_process.lo \ - libcares_la-ares_query.lo libcares_la-ares_search.lo \ - libcares_la-ares_send.lo libcares_la-ares_strcasecmp.lo \ - libcares_la-ares_strdup.lo libcares_la-ares_strerror.lo \ - libcares_la-ares_strsplit.lo libcares_la-ares_timeout.lo \ - libcares_la-ares_version.lo libcares_la-ares_writev.lo \ - libcares_la-bitncmp.lo libcares_la-inet_net_pton.lo \ - libcares_la-inet_ntop.lo libcares_la-windows_port.lo + libcares_la-ares_query.lo libcares_la-ares_rand.lo \ + libcares_la-ares_search.lo libcares_la-ares_send.lo \ + libcares_la-ares_strcasecmp.lo libcares_la-ares_strdup.lo \ + libcares_la-ares_strerror.lo libcares_la-ares_strsplit.lo \ + libcares_la-ares_timeout.lo libcares_la-ares_version.lo \ + libcares_la-ares_writev.lo libcares_la-bitncmp.lo \ + libcares_la-inet_net_pton.lo libcares_la-inet_ntop.lo \ + libcares_la-windows_port.lo am__objects_2 = am_libcares_la_OBJECTS = $(am__objects_1) $(am__objects_2) libcares_la_OBJECTS = $(am_libcares_la_OBJECTS) @@ -273,6 +275,7 @@ am__depfiles_remade = \ ./$(DEPDIR)/libcares_la-ares_platform.Plo \ ./$(DEPDIR)/libcares_la-ares_process.Plo \ ./$(DEPDIR)/libcares_la-ares_query.Plo \ + ./$(DEPDIR)/libcares_la-ares_rand.Plo \ ./$(DEPDIR)/libcares_la-ares_search.Plo \ ./$(DEPDIR)/libcares_la-ares_send.Plo \ ./$(DEPDIR)/libcares_la-ares_strcasecmp.Plo \ @@ -617,6 +620,7 @@ CSOURCES = ares__addrinfo2hostent.c \ ares_platform.c \ ares_process.c \ ares_query.c \ + ares_rand.c \ ares_search.c \ ares_send.c \ ares_strcasecmp.c \ @@ -793,6 +797,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcares_la-ares_platform.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcares_la-ares_process.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcares_la-ares_query.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcares_la-ares_rand.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcares_la-ares_search.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcares_la-ares_send.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcares_la-ares_strcasecmp.Plo@am__quote@ # am--include-marker @@ -1159,6 +1164,13 @@ libcares_la-ares_query.lo: ares_query.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcares_la_CPPFLAGS) $(CPPFLAGS) $(libcares_la_CFLAGS) $(CFLAGS) -c -o libcares_la-ares_query.lo `test -f 'ares_query.c' || echo '$(srcdir)/'`ares_query.c +libcares_la-ares_rand.lo: ares_rand.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcares_la_CPPFLAGS) $(CPPFLAGS) $(libcares_la_CFLAGS) $(CFLAGS) -MT libcares_la-ares_rand.lo -MD -MP -MF $(DEPDIR)/libcares_la-ares_rand.Tpo -c -o libcares_la-ares_rand.lo `test -f 'ares_rand.c' || echo '$(srcdir)/'`ares_rand.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcares_la-ares_rand.Tpo $(DEPDIR)/libcares_la-ares_rand.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ares_rand.c' object='libcares_la-ares_rand.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcares_la_CPPFLAGS) $(CPPFLAGS) $(libcares_la_CFLAGS) $(CFLAGS) -c -o libcares_la-ares_rand.lo `test -f 'ares_rand.c' || echo '$(srcdir)/'`ares_rand.c + libcares_la-ares_search.lo: ares_search.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcares_la_CPPFLAGS) $(CPPFLAGS) $(libcares_la_CFLAGS) $(CFLAGS) -MT libcares_la-ares_search.lo -MD -MP -MF $(DEPDIR)/libcares_la-ares_search.Tpo -c -o libcares_la-ares_search.lo `test -f 'ares_search.c' || echo '$(srcdir)/'`ares_search.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcares_la-ares_search.Tpo $(DEPDIR)/libcares_la-ares_search.Plo @@ -1503,6 +1515,7 @@ distclean: distclean-recursive -rm -f ./$(DEPDIR)/libcares_la-ares_platform.Plo -rm -f ./$(DEPDIR)/libcares_la-ares_process.Plo -rm -f ./$(DEPDIR)/libcares_la-ares_query.Plo + -rm -f ./$(DEPDIR)/libcares_la-ares_rand.Plo -rm -f ./$(DEPDIR)/libcares_la-ares_search.Plo -rm -f ./$(DEPDIR)/libcares_la-ares_send.Plo -rm -f ./$(DEPDIR)/libcares_la-ares_strcasecmp.Plo @@ -1607,6 +1620,7 @@ maintainer-clean: maintainer-clean-recursive -rm -f ./$(DEPDIR)/libcares_la-ares_platform.Plo -rm -f ./$(DEPDIR)/libcares_la-ares_process.Plo -rm -f ./$(DEPDIR)/libcares_la-ares_query.Plo + -rm -f ./$(DEPDIR)/libcares_la-ares_rand.Plo -rm -f ./$(DEPDIR)/libcares_la-ares_search.Plo -rm -f ./$(DEPDIR)/libcares_la-ares_send.Plo -rm -f ./$(DEPDIR)/libcares_la-ares_strcasecmp.Plo diff --git a/lib/c-ares-1.19.0/src/lib/Makefile.inc b/lib/c-ares-1.19.1/src/lib/Makefile.inc similarity index 97% rename from lib/c-ares-1.19.0/src/lib/Makefile.inc rename to lib/c-ares-1.19.1/src/lib/Makefile.inc index 140378d67e2..02d8d58a6d5 100644 --- a/lib/c-ares-1.19.0/src/lib/Makefile.inc +++ b/lib/c-ares-1.19.1/src/lib/Makefile.inc @@ -45,6 +45,7 @@ CSOURCES = ares__addrinfo2hostent.c \ ares_platform.c \ ares_process.c \ ares_query.c \ + ares_rand.c \ ares_search.c \ ares_send.c \ ares_strcasecmp.c \ @@ -59,7 +60,7 @@ CSOURCES = ares__addrinfo2hostent.c \ inet_ntop.c \ windows_port.c -HHEADERS = ares_android.h \ +HHEADERS = ares_android.h \ ares_data.h \ ares_getenv.h \ ares_inet_net_pton.h \ diff --git a/lib/c-ares-1.19.0/src/lib/ares__addrinfo2hostent.c b/lib/c-ares-1.19.1/src/lib/ares__addrinfo2hostent.c similarity index 100% rename from lib/c-ares-1.19.0/src/lib/ares__addrinfo2hostent.c rename to lib/c-ares-1.19.1/src/lib/ares__addrinfo2hostent.c diff --git a/lib/c-ares-1.19.0/src/lib/ares__addrinfo_localhost.c b/lib/c-ares-1.19.1/src/lib/ares__addrinfo_localhost.c similarity index 99% rename from lib/c-ares-1.19.0/src/lib/ares__addrinfo_localhost.c rename to lib/c-ares-1.19.1/src/lib/ares__addrinfo_localhost.c index 7940ecdae7d..5bc1e0bff08 100644 --- a/lib/c-ares-1.19.0/src/lib/ares__addrinfo_localhost.c +++ b/lib/c-ares-1.19.1/src/lib/ares__addrinfo_localhost.c @@ -131,7 +131,7 @@ static int ares__system_loopback_addrs(int aftype, unsigned short port, struct ares_addrinfo_node **nodes) { -#if defined(_WIN32) && defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0600 +#if defined(_WIN32) && defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0600 && !defined(__WATCOMC__) PMIB_UNICASTIPADDRESS_TABLE table; unsigned int i; int status; diff --git a/lib/c-ares-1.19.0/src/lib/ares__close_sockets.c b/lib/c-ares-1.19.1/src/lib/ares__close_sockets.c similarity index 100% rename from lib/c-ares-1.19.0/src/lib/ares__close_sockets.c rename to lib/c-ares-1.19.1/src/lib/ares__close_sockets.c diff --git a/lib/c-ares-1.19.0/src/lib/ares__get_hostent.c b/lib/c-ares-1.19.1/src/lib/ares__get_hostent.c similarity index 100% rename from lib/c-ares-1.19.0/src/lib/ares__get_hostent.c rename to lib/c-ares-1.19.1/src/lib/ares__get_hostent.c diff --git a/lib/c-ares-1.19.0/src/lib/ares__parse_into_addrinfo.c b/lib/c-ares-1.19.1/src/lib/ares__parse_into_addrinfo.c similarity index 100% rename from lib/c-ares-1.19.0/src/lib/ares__parse_into_addrinfo.c rename to lib/c-ares-1.19.1/src/lib/ares__parse_into_addrinfo.c diff --git a/lib/c-ares-1.19.0/src/lib/ares__read_line.c b/lib/c-ares-1.19.1/src/lib/ares__read_line.c similarity index 100% rename from lib/c-ares-1.19.0/src/lib/ares__read_line.c rename to lib/c-ares-1.19.1/src/lib/ares__read_line.c diff --git a/lib/c-ares-1.19.0/src/lib/ares__readaddrinfo.c b/lib/c-ares-1.19.1/src/lib/ares__readaddrinfo.c similarity index 100% rename from lib/c-ares-1.19.0/src/lib/ares__readaddrinfo.c rename to lib/c-ares-1.19.1/src/lib/ares__readaddrinfo.c diff --git a/lib/c-ares-1.19.0/src/lib/ares__sortaddrinfo.c b/lib/c-ares-1.19.1/src/lib/ares__sortaddrinfo.c similarity index 100% rename from lib/c-ares-1.19.0/src/lib/ares__sortaddrinfo.c rename to lib/c-ares-1.19.1/src/lib/ares__sortaddrinfo.c diff --git a/lib/c-ares-1.19.0/src/lib/ares__timeval.c b/lib/c-ares-1.19.1/src/lib/ares__timeval.c similarity index 100% rename from lib/c-ares-1.19.0/src/lib/ares__timeval.c rename to lib/c-ares-1.19.1/src/lib/ares__timeval.c diff --git a/lib/c-ares-1.19.0/src/lib/ares_android.c b/lib/c-ares-1.19.1/src/lib/ares_android.c similarity index 100% rename from lib/c-ares-1.19.0/src/lib/ares_android.c rename to lib/c-ares-1.19.1/src/lib/ares_android.c diff --git a/lib/c-ares-1.19.0/src/lib/ares_android.h b/lib/c-ares-1.19.1/src/lib/ares_android.h similarity index 100% rename from lib/c-ares-1.19.0/src/lib/ares_android.h rename to lib/c-ares-1.19.1/src/lib/ares_android.h diff --git a/lib/c-ares-1.19.0/src/lib/ares_cancel.c b/lib/c-ares-1.19.1/src/lib/ares_cancel.c similarity index 100% rename from lib/c-ares-1.19.0/src/lib/ares_cancel.c rename to lib/c-ares-1.19.1/src/lib/ares_cancel.c diff --git a/lib/c-ares-1.19.0/src/lib/ares_config.h.cmake b/lib/c-ares-1.19.1/src/lib/ares_config.h.cmake similarity index 99% rename from lib/c-ares-1.19.0/src/lib/ares_config.h.cmake rename to lib/c-ares-1.19.1/src/lib/ares_config.h.cmake index fddb7853514..798820a3a68 100644 --- a/lib/c-ares-1.19.0/src/lib/ares_config.h.cmake +++ b/lib/c-ares-1.19.1/src/lib/ares_config.h.cmake @@ -346,6 +346,9 @@ /* Define to 1 if you need the memory.h header file even with stdlib.h */ #cmakedefine NEED_MEMORY_H +/* Define if have arc4random_buf() */ +#cmakedefine HAVE_ARC4RANDOM_BUF + /* a suitable file/device to read random data from */ #cmakedefine CARES_RANDOM_FILE "@CARES_RANDOM_FILE@" diff --git a/lib/c-ares-1.19.0/src/lib/ares_config.h.in b/lib/c-ares-1.19.1/src/lib/ares_config.h.in similarity index 99% rename from lib/c-ares-1.19.0/src/lib/ares_config.h.in rename to lib/c-ares-1.19.1/src/lib/ares_config.h.in index b260c08fe62..3f6954a74db 100644 --- a/lib/c-ares-1.19.0/src/lib/ares_config.h.in +++ b/lib/c-ares-1.19.1/src/lib/ares_config.h.in @@ -54,6 +54,9 @@ /* Define to 1 if you have AF_INET6. */ #undef HAVE_AF_INET6 +/* Define to 1 if you have the arc4random_buf function. */ +#undef HAVE_ARC4RANDOM_BUF + /* Define to 1 if you have the header file. */ #undef HAVE_ARPA_INET_H diff --git a/lib/c-ares-1.19.0/src/lib/ares_create_query.c b/lib/c-ares-1.19.1/src/lib/ares_create_query.c similarity index 100% rename from lib/c-ares-1.19.0/src/lib/ares_create_query.c rename to lib/c-ares-1.19.1/src/lib/ares_create_query.c diff --git a/lib/c-ares-1.19.0/src/lib/ares_data.c b/lib/c-ares-1.19.1/src/lib/ares_data.c similarity index 100% rename from lib/c-ares-1.19.0/src/lib/ares_data.c rename to lib/c-ares-1.19.1/src/lib/ares_data.c diff --git a/lib/c-ares-1.19.0/src/lib/ares_data.h b/lib/c-ares-1.19.1/src/lib/ares_data.h similarity index 99% rename from lib/c-ares-1.19.0/src/lib/ares_data.h rename to lib/c-ares-1.19.1/src/lib/ares_data.h index 54d729d0e7e..a682ad54cb9 100644 --- a/lib/c-ares-1.19.0/src/lib/ares_data.h +++ b/lib/c-ares-1.19.1/src/lib/ares_data.h @@ -78,4 +78,4 @@ struct ares_data { void *ares_malloc_data(ares_datatype type); -#endif // __ARES_DATA_H +#endif /* __ARES_DATA_H */ diff --git a/lib/c-ares-1.19.0/src/lib/ares_destroy.c b/lib/c-ares-1.19.1/src/lib/ares_destroy.c similarity index 97% rename from lib/c-ares-1.19.0/src/lib/ares_destroy.c rename to lib/c-ares-1.19.1/src/lib/ares_destroy.c index 7ec2bde5a45..62c899f82e0 100644 --- a/lib/c-ares-1.19.0/src/lib/ares_destroy.c +++ b/lib/c-ares-1.19.1/src/lib/ares_destroy.c @@ -95,6 +95,9 @@ void ares_destroy(ares_channel channel) if (channel->hosts_path) ares_free(channel->hosts_path); + if (channel->rand_state) + ares__destroy_rand_state(channel->rand_state); + ares_free(channel); } diff --git a/lib/c-ares-1.19.0/src/lib/ares_expand_name.c b/lib/c-ares-1.19.1/src/lib/ares_expand_name.c similarity index 98% rename from lib/c-ares-1.19.0/src/lib/ares_expand_name.c rename to lib/c-ares-1.19.1/src/lib/ares_expand_name.c index 6c7a35a715b..ad1c97f9377 100644 --- a/lib/c-ares-1.19.0/src/lib/ares_expand_name.c +++ b/lib/c-ares-1.19.1/src/lib/ares_expand_name.c @@ -179,9 +179,9 @@ int ares__expand_name_validated(const unsigned char *encoded, if (!ares__isprint(*p) && !(name_len == 1 && *p == 0)) { *q++ = '\\'; - *q++ = '0' + *p / 100; - *q++ = '0' + (*p % 100) / 10; - *q++ = '0' + (*p % 10); + *q++ = (char)('0' + *p / 100); + *q++ = (char)('0' + (*p % 100) / 10); + *q++ = (char)('0' + (*p % 10)); } else if (is_reservedch(*p)) { diff --git a/lib/c-ares-1.19.0/src/lib/ares_expand_string.c b/lib/c-ares-1.19.1/src/lib/ares_expand_string.c similarity index 100% rename from lib/c-ares-1.19.0/src/lib/ares_expand_string.c rename to lib/c-ares-1.19.1/src/lib/ares_expand_string.c diff --git a/lib/c-ares-1.19.0/src/lib/ares_fds.c b/lib/c-ares-1.19.1/src/lib/ares_fds.c similarity index 100% rename from lib/c-ares-1.19.0/src/lib/ares_fds.c rename to lib/c-ares-1.19.1/src/lib/ares_fds.c diff --git a/lib/c-ares-1.19.0/src/lib/ares_free_hostent.c b/lib/c-ares-1.19.1/src/lib/ares_free_hostent.c similarity index 100% rename from lib/c-ares-1.19.0/src/lib/ares_free_hostent.c rename to lib/c-ares-1.19.1/src/lib/ares_free_hostent.c diff --git a/lib/c-ares-1.19.0/src/lib/ares_free_string.c b/lib/c-ares-1.19.1/src/lib/ares_free_string.c similarity index 100% rename from lib/c-ares-1.19.0/src/lib/ares_free_string.c rename to lib/c-ares-1.19.1/src/lib/ares_free_string.c diff --git a/lib/c-ares-1.19.0/src/lib/ares_freeaddrinfo.c b/lib/c-ares-1.19.1/src/lib/ares_freeaddrinfo.c similarity index 100% rename from lib/c-ares-1.19.0/src/lib/ares_freeaddrinfo.c rename to lib/c-ares-1.19.1/src/lib/ares_freeaddrinfo.c diff --git a/lib/c-ares-1.19.0/src/lib/ares_getaddrinfo.c b/lib/c-ares-1.19.1/src/lib/ares_getaddrinfo.c similarity index 96% rename from lib/c-ares-1.19.0/src/lib/ares_getaddrinfo.c rename to lib/c-ares-1.19.1/src/lib/ares_getaddrinfo.c index bc9f19bf849..cb494242f28 100644 --- a/lib/c-ares-1.19.0/src/lib/ares_getaddrinfo.c +++ b/lib/c-ares-1.19.1/src/lib/ares_getaddrinfo.c @@ -430,16 +430,20 @@ static int file_lookup(struct host_query *hquery) FILE *fp; int error; int status; - const char *path_hosts = NULL; + char *path_hosts = NULL; if (hquery->hints.ai_flags & ARES_AI_ENVHOSTS) { - path_hosts = getenv("CARES_HOSTS"); + path_hosts = ares_strdup(getenv("CARES_HOSTS")); + if (!path_hosts) + return ARES_ENOMEM; } if (hquery->channel->hosts_path) { - path_hosts = hquery->channel->hosts_path; + path_hosts = ares_strdup(hquery->channel->hosts_path); + if (!path_hosts) + return ARES_ENOMEM; } if (!path_hosts) @@ -473,15 +477,15 @@ static int file_lookup(struct host_query *hquery) return ARES_ENOTFOUND; strcat(PATH_HOSTS, WIN_PATH_HOSTS); - path_hosts = PATH_HOSTS; - #elif defined(WATT32) const char *PATH_HOSTS = _w32_GetHostsFile(); if (!PATH_HOSTS) return ARES_ENOTFOUND; #endif - path_hosts = PATH_HOSTS; + path_hosts = ares_strdup(PATH_HOSTS); + if (!path_hosts) + return ARES_ENOMEM; } fp = fopen(path_hosts, "r"); @@ -507,6 +511,7 @@ static int file_lookup(struct host_query *hquery) status = ares__readaddrinfo(fp, hquery->name, hquery->port, &hquery->hints, hquery->ai); fclose(fp); } + ares_free(path_hosts); /* RFC6761 section 6.3 #3 states that "Name resolution APIs and libraries * SHOULD recognize localhost names as special and SHOULD always return the @@ -665,26 +670,32 @@ void ares_getaddrinfo(ares_channel channel, { if (hints->ai_flags & ARES_AI_NUMERICSERV) { - port = (unsigned short)strtoul(service, NULL, 0); - if (!port) + unsigned long val; + errno = 0; + val = strtoul(service, NULL, 0); + if ((val == 0 && errno != 0) || val > 65535) { ares_free(alias_name); callback(arg, ARES_ESERVICE, 0, NULL); return; } + port = (unsigned short)val; } else { port = lookup_service(service, 0); if (!port) { - port = (unsigned short)strtoul(service, NULL, 0); - if (!port) + unsigned long val; + errno = 0; + val = strtoul(service, NULL, 0); + if ((val == 0 && errno != 0) || val > 65535) { ares_free(alias_name); callback(arg, ARES_ESERVICE, 0, NULL); return; } + port = (unsigned short)val; } } } diff --git a/lib/c-ares-1.19.0/src/lib/ares_getenv.c b/lib/c-ares-1.19.1/src/lib/ares_getenv.c similarity index 100% rename from lib/c-ares-1.19.0/src/lib/ares_getenv.c rename to lib/c-ares-1.19.1/src/lib/ares_getenv.c diff --git a/lib/c-ares-1.19.0/src/lib/ares_getenv.h b/lib/c-ares-1.19.1/src/lib/ares_getenv.h similarity index 100% rename from lib/c-ares-1.19.0/src/lib/ares_getenv.h rename to lib/c-ares-1.19.1/src/lib/ares_getenv.h diff --git a/lib/c-ares-1.19.0/src/lib/ares_gethostbyaddr.c b/lib/c-ares-1.19.1/src/lib/ares_gethostbyaddr.c similarity index 100% rename from lib/c-ares-1.19.0/src/lib/ares_gethostbyaddr.c rename to lib/c-ares-1.19.1/src/lib/ares_gethostbyaddr.c diff --git a/lib/c-ares-1.19.0/src/lib/ares_gethostbyname.c b/lib/c-ares-1.19.1/src/lib/ares_gethostbyname.c similarity index 100% rename from lib/c-ares-1.19.0/src/lib/ares_gethostbyname.c rename to lib/c-ares-1.19.1/src/lib/ares_gethostbyname.c diff --git a/lib/c-ares-1.19.0/src/lib/ares_getnameinfo.c b/lib/c-ares-1.19.1/src/lib/ares_getnameinfo.c similarity index 100% rename from lib/c-ares-1.19.0/src/lib/ares_getnameinfo.c rename to lib/c-ares-1.19.1/src/lib/ares_getnameinfo.c diff --git a/lib/c-ares-1.19.0/src/lib/ares_getsock.c b/lib/c-ares-1.19.1/src/lib/ares_getsock.c similarity index 100% rename from lib/c-ares-1.19.0/src/lib/ares_getsock.c rename to lib/c-ares-1.19.1/src/lib/ares_getsock.c diff --git a/lib/c-ares-1.19.0/src/lib/ares_inet_net_pton.h b/lib/c-ares-1.19.1/src/lib/ares_inet_net_pton.h similarity index 100% rename from lib/c-ares-1.19.0/src/lib/ares_inet_net_pton.h rename to lib/c-ares-1.19.1/src/lib/ares_inet_net_pton.h diff --git a/lib/c-ares-1.19.0/src/lib/ares_init.c b/lib/c-ares-1.19.1/src/lib/ares_init.c similarity index 96% rename from lib/c-ares-1.19.0/src/lib/ares_init.c rename to lib/c-ares-1.19.1/src/lib/ares_init.c index 3f9cec65213..0519f43e561 100644 --- a/lib/c-ares-1.19.0/src/lib/ares_init.c +++ b/lib/c-ares-1.19.1/src/lib/ares_init.c @@ -61,17 +61,6 @@ #undef WIN32 /* Redefined in MingW/MSVC headers */ #endif -/* Define RtlGenRandom = SystemFunction036. This is in advapi32.dll. There is - * no need to dynamically load this, other software used widely does not. - * http://blogs.msdn.com/michael_howard/archive/2005/01/14/353379.aspx - * https://docs.microsoft.com/en-us/windows/win32/api/ntsecapi/nf-ntsecapi-rtlgenrandom - */ -#ifdef _WIN32 -BOOLEAN WINAPI SystemFunction036(PVOID RandomBuffer, ULONG RandomBufferLength); -# ifndef RtlGenRandom -# define RtlGenRandom(a,b) SystemFunction036(a,b) -# endif -#endif static int init_by_options(ares_channel channel, const struct ares_options *options, @@ -87,7 +76,6 @@ static int config_nameserver(struct server_state **servers, int *nservers, static int set_search(ares_channel channel, const char *str); static int set_options(ares_channel channel, const char *str); static const char *try_option(const char *p, const char *q, const char *opt); -static int init_id_key(rc4_key* key,int key_data_len); static int config_sortlist(struct apattern **sortlist, int *nsort, const char *str); @@ -165,6 +153,7 @@ int ares_init_options(ares_channel *channelptr, struct ares_options *options, channel->sock_func_cb_data = NULL; channel->resolvconf_path = NULL; channel->hosts_path = NULL; + channel->rand_state = NULL; channel->last_server = 0; channel->last_timeout_processed = (time_t)now.tv_sec; @@ -218,9 +207,13 @@ int ares_init_options(ares_channel *channelptr, struct ares_options *options, /* Generate random key */ if (status == ARES_SUCCESS) { - status = init_id_key(&channel->id_key, ARES_ID_KEY_LEN); + channel->rand_state = ares__init_rand_state(); + if (channel->rand_state == NULL) { + status = ARES_ENOMEM; + } + if (status == ARES_SUCCESS) - channel->next_id = ares__generate_new_id(&channel->id_key); + channel->next_id = ares__generate_new_id(channel->rand_state); else DEBUGF(fprintf(stderr, "Error: init_id_key failed: %s\n", ares_strerror(status))); @@ -242,6 +235,8 @@ int ares_init_options(ares_channel *channelptr, struct ares_options *options, ares_free(channel->resolvconf_path); if(channel->hosts_path) ares_free(channel->hosts_path); + if (channel->rand_state) + ares__destroy_rand_state(channel->rand_state); ares_free(channel); return status; } @@ -746,6 +741,17 @@ static ULONG getBestRouteMetric(IF_LUID * const luid, /* Can't be const :( */ const ULONG interfaceMetric) { /* On this interface, get the best route to that destination. */ +#if defined(__WATCOMC__) + /* OpenWatcom's builtin Windows SDK does not have a definition for + * MIB_IPFORWARD_ROW2, and also does not allow the usage of SOCKADDR_INET + * as a variable. Let's work around this by returning the worst possible + * metric, but only when using the OpenWatcom compiler. + * It may be worth investigating using a different version of the Windows + * SDK with OpenWatcom in the future, though this may be fixed in OpenWatcom + * 2.0. + */ + return (ULONG)-1; +#else MIB_IPFORWARD_ROW2 row; SOCKADDR_INET ignored; if(GetBestRoute2(/* The interface to use. The index is ignored since we are @@ -778,6 +784,7 @@ static ULONG getBestRouteMetric(IF_LUID * const luid, /* Can't be const :( */ * which describes the combination as a "sum". */ return row.Metric + interfaceMetric; +#endif /* __WATCOMC__ */ } /* @@ -2170,72 +2177,6 @@ static int sortlist_alloc(struct apattern **sortlist, int *nsort, } -/* initialize an rc4 key. If possible a cryptographically secure random key - is generated using a suitable function otherwise the code defaults to - cross-platform albeit less secure mechanism using rand -*/ -static void randomize_key(unsigned char* key,int key_data_len) -{ - int randomized = 0; - int counter=0; -#ifdef WIN32 - BOOLEAN res; - - res = RtlGenRandom(key, key_data_len); - if (res) - randomized = 1; - -#else /* !WIN32 */ -# ifdef CARES_RANDOM_FILE - FILE *f = fopen(CARES_RANDOM_FILE, "rb"); - if(f) { - setvbuf(f, NULL, _IONBF, 0); - counter = aresx_uztosi(fread(key, 1, key_data_len, f)); - fclose(f); - } -# endif -#endif /* WIN32 */ - - if (!randomized) { - for (;counterstate[0]; - for(counter = 0; counter < 256; counter++) - /* unnecessary AND but it keeps some compilers happier */ - state[counter] = (unsigned char)(counter & 0xff); - randomize_key(key->state,key_data_len); - key->x = 0; - key->y = 0; - index1 = 0; - index2 = 0; - for(counter = 0; counter < 256; counter++) - { - index2 = (unsigned char)((key_data_ptr[index1] + state[counter] + - index2) % 256); - ARES_SWAP_BYTE(&state[counter], &state[index2]); - - index1 = (unsigned char)((index1 + 1) % key_data_len); - } - ares_free(key_data_ptr); - return ARES_SUCCESS; -} - void ares_set_local_ip4(ares_channel channel, unsigned int local_ip) { channel->local_ip4 = local_ip; diff --git a/lib/c-ares-1.19.0/src/lib/ares_iphlpapi.h b/lib/c-ares-1.19.1/src/lib/ares_iphlpapi.h similarity index 100% rename from lib/c-ares-1.19.0/src/lib/ares_iphlpapi.h rename to lib/c-ares-1.19.1/src/lib/ares_iphlpapi.h diff --git a/lib/c-ares-1.19.0/src/lib/ares_ipv6.h b/lib/c-ares-1.19.1/src/lib/ares_ipv6.h similarity index 100% rename from lib/c-ares-1.19.0/src/lib/ares_ipv6.h rename to lib/c-ares-1.19.1/src/lib/ares_ipv6.h diff --git a/lib/c-ares-1.19.0/src/lib/ares_library_init.c b/lib/c-ares-1.19.1/src/lib/ares_library_init.c similarity index 100% rename from lib/c-ares-1.19.0/src/lib/ares_library_init.c rename to lib/c-ares-1.19.1/src/lib/ares_library_init.c diff --git a/lib/c-ares-1.19.0/src/lib/ares_llist.c b/lib/c-ares-1.19.1/src/lib/ares_llist.c similarity index 100% rename from lib/c-ares-1.19.0/src/lib/ares_llist.c rename to lib/c-ares-1.19.1/src/lib/ares_llist.c diff --git a/lib/c-ares-1.19.0/src/lib/ares_llist.h b/lib/c-ares-1.19.1/src/lib/ares_llist.h similarity index 100% rename from lib/c-ares-1.19.0/src/lib/ares_llist.h rename to lib/c-ares-1.19.1/src/lib/ares_llist.h diff --git a/lib/c-ares-1.19.0/src/lib/ares_mkquery.c b/lib/c-ares-1.19.1/src/lib/ares_mkquery.c similarity index 100% rename from lib/c-ares-1.19.0/src/lib/ares_mkquery.c rename to lib/c-ares-1.19.1/src/lib/ares_mkquery.c diff --git a/lib/c-ares-1.19.0/src/lib/ares_nowarn.c b/lib/c-ares-1.19.1/src/lib/ares_nowarn.c similarity index 100% rename from lib/c-ares-1.19.0/src/lib/ares_nowarn.c rename to lib/c-ares-1.19.1/src/lib/ares_nowarn.c diff --git a/lib/c-ares-1.19.0/src/lib/ares_nowarn.h b/lib/c-ares-1.19.1/src/lib/ares_nowarn.h similarity index 100% rename from lib/c-ares-1.19.0/src/lib/ares_nowarn.h rename to lib/c-ares-1.19.1/src/lib/ares_nowarn.h diff --git a/lib/c-ares-1.19.0/src/lib/ares_options.c b/lib/c-ares-1.19.1/src/lib/ares_options.c similarity index 100% rename from lib/c-ares-1.19.0/src/lib/ares_options.c rename to lib/c-ares-1.19.1/src/lib/ares_options.c diff --git a/lib/c-ares-1.19.0/src/lib/ares_parse_a_reply.c b/lib/c-ares-1.19.1/src/lib/ares_parse_a_reply.c similarity index 100% rename from lib/c-ares-1.19.0/src/lib/ares_parse_a_reply.c rename to lib/c-ares-1.19.1/src/lib/ares_parse_a_reply.c diff --git a/lib/c-ares-1.19.0/src/lib/ares_parse_aaaa_reply.c b/lib/c-ares-1.19.1/src/lib/ares_parse_aaaa_reply.c similarity index 100% rename from lib/c-ares-1.19.0/src/lib/ares_parse_aaaa_reply.c rename to lib/c-ares-1.19.1/src/lib/ares_parse_aaaa_reply.c diff --git a/lib/c-ares-1.19.0/src/lib/ares_parse_caa_reply.c b/lib/c-ares-1.19.1/src/lib/ares_parse_caa_reply.c similarity index 100% rename from lib/c-ares-1.19.0/src/lib/ares_parse_caa_reply.c rename to lib/c-ares-1.19.1/src/lib/ares_parse_caa_reply.c diff --git a/lib/c-ares-1.19.0/src/lib/ares_parse_mx_reply.c b/lib/c-ares-1.19.1/src/lib/ares_parse_mx_reply.c similarity index 100% rename from lib/c-ares-1.19.0/src/lib/ares_parse_mx_reply.c rename to lib/c-ares-1.19.1/src/lib/ares_parse_mx_reply.c diff --git a/lib/c-ares-1.19.0/src/lib/ares_parse_naptr_reply.c b/lib/c-ares-1.19.1/src/lib/ares_parse_naptr_reply.c similarity index 100% rename from lib/c-ares-1.19.0/src/lib/ares_parse_naptr_reply.c rename to lib/c-ares-1.19.1/src/lib/ares_parse_naptr_reply.c diff --git a/lib/c-ares-1.19.0/src/lib/ares_parse_ns_reply.c b/lib/c-ares-1.19.1/src/lib/ares_parse_ns_reply.c similarity index 100% rename from lib/c-ares-1.19.0/src/lib/ares_parse_ns_reply.c rename to lib/c-ares-1.19.1/src/lib/ares_parse_ns_reply.c diff --git a/lib/c-ares-1.19.0/src/lib/ares_parse_ptr_reply.c b/lib/c-ares-1.19.1/src/lib/ares_parse_ptr_reply.c similarity index 100% rename from lib/c-ares-1.19.0/src/lib/ares_parse_ptr_reply.c rename to lib/c-ares-1.19.1/src/lib/ares_parse_ptr_reply.c diff --git a/lib/c-ares-1.19.0/src/lib/ares_parse_soa_reply.c b/lib/c-ares-1.19.1/src/lib/ares_parse_soa_reply.c similarity index 100% rename from lib/c-ares-1.19.0/src/lib/ares_parse_soa_reply.c rename to lib/c-ares-1.19.1/src/lib/ares_parse_soa_reply.c diff --git a/lib/c-ares-1.19.0/src/lib/ares_parse_srv_reply.c b/lib/c-ares-1.19.1/src/lib/ares_parse_srv_reply.c similarity index 100% rename from lib/c-ares-1.19.0/src/lib/ares_parse_srv_reply.c rename to lib/c-ares-1.19.1/src/lib/ares_parse_srv_reply.c diff --git a/lib/c-ares-1.19.0/src/lib/ares_parse_txt_reply.c b/lib/c-ares-1.19.1/src/lib/ares_parse_txt_reply.c similarity index 100% rename from lib/c-ares-1.19.0/src/lib/ares_parse_txt_reply.c rename to lib/c-ares-1.19.1/src/lib/ares_parse_txt_reply.c diff --git a/lib/c-ares-1.19.0/src/lib/ares_parse_uri_reply.c b/lib/c-ares-1.19.1/src/lib/ares_parse_uri_reply.c similarity index 100% rename from lib/c-ares-1.19.0/src/lib/ares_parse_uri_reply.c rename to lib/c-ares-1.19.1/src/lib/ares_parse_uri_reply.c diff --git a/lib/c-ares-1.19.0/src/lib/ares_platform.c b/lib/c-ares-1.19.1/src/lib/ares_platform.c similarity index 100% rename from lib/c-ares-1.19.0/src/lib/ares_platform.c rename to lib/c-ares-1.19.1/src/lib/ares_platform.c diff --git a/lib/c-ares-1.19.0/src/lib/ares_platform.h b/lib/c-ares-1.19.1/src/lib/ares_platform.h similarity index 100% rename from lib/c-ares-1.19.0/src/lib/ares_platform.h rename to lib/c-ares-1.19.1/src/lib/ares_platform.h diff --git a/lib/c-ares-1.19.0/src/lib/ares_private.h b/lib/c-ares-1.19.1/src/lib/ares_private.h similarity index 97% rename from lib/c-ares-1.19.0/src/lib/ares_private.h rename to lib/c-ares-1.19.1/src/lib/ares_private.h index 53043a65137..b6eab8a7d9b 100644 --- a/lib/c-ares-1.19.0/src/lib/ares_private.h +++ b/lib/c-ares-1.19.1/src/lib/ares_private.h @@ -101,8 +101,6 @@ W32_FUNC const char *_w32_GetHostsFile (void); #endif -#define ARES_ID_KEY_LEN 31 - #include "ares_ipv6.h" #include "ares_llist.h" @@ -262,12 +260,8 @@ struct apattern { unsigned short type; }; -typedef struct rc4_key -{ - unsigned char state[256]; - unsigned char x; - unsigned char y; -} rc4_key; +struct ares_rand_state; +typedef struct ares_rand_state ares_rand_state; struct ares_channeldata { /* Configuration data */ @@ -302,8 +296,8 @@ struct ares_channeldata { /* ID to use for next query */ unsigned short next_id; - /* key to use when generating new ids */ - rc4_key id_key; + /* random state to use when generating new ids */ + ares_rand_state *rand_state; /* Generation number to use for the next TCP socket open/close */ int tcp_connection_generation; @@ -362,7 +356,10 @@ void ares__close_sockets(ares_channel channel, struct server_state *server); int ares__get_hostent(FILE *fp, int family, struct hostent **host); int ares__read_line(FILE *fp, char **buf, size_t *bufsize); void ares__free_query(struct query *query); -unsigned short ares__generate_new_id(rc4_key* key); + +ares_rand_state *ares__init_rand_state(void); +void ares__destroy_rand_state(ares_rand_state *state); +unsigned short ares__generate_new_id(ares_rand_state *state); struct timeval ares__tvnow(void); int ares__expand_name_validated(const unsigned char *encoded, const unsigned char *abuf, diff --git a/lib/c-ares-1.19.0/src/lib/ares_process.c b/lib/c-ares-1.19.1/src/lib/ares_process.c similarity index 97% rename from lib/c-ares-1.19.0/src/lib/ares_process.c rename to lib/c-ares-1.19.1/src/lib/ares_process.c index d5a6df8ba7c..6cac0a99fdf 100644 --- a/lib/c-ares-1.19.0/src/lib/ares_process.c +++ b/lib/c-ares-1.19.1/src/lib/ares_process.c @@ -470,7 +470,7 @@ static void read_udp_packets(ares_channel channel, fd_set *read_fds, { struct server_state *server; int i; - ares_ssize_t count; + ares_ssize_t read_len; unsigned char buf[MAXENDSSZ + 1]; #ifdef HAVE_RECVFROM ares_socklen_t fromlen; @@ -513,32 +513,41 @@ static void read_udp_packets(ares_channel channel, fd_set *read_fds, /* To reduce event loop overhead, read and process as many * packets as we can. */ do { - if (server->udp_socket == ARES_SOCKET_BAD) - count = 0; - - else { - if (server->addr.family == AF_INET) + if (server->udp_socket == ARES_SOCKET_BAD) { + read_len = -1; + } else { + if (server->addr.family == AF_INET) { fromlen = sizeof(from.sa4); - else + } else { fromlen = sizeof(from.sa6); - count = socket_recvfrom(channel, server->udp_socket, (void *)buf, - sizeof(buf), 0, &from.sa, &fromlen); + } + read_len = socket_recvfrom(channel, server->udp_socket, (void *)buf, + sizeof(buf), 0, &from.sa, &fromlen); } - if (count == -1 && try_again(SOCKERRNO)) + if (read_len == 0) { + /* UDP is connectionless, so result code of 0 is a 0-length UDP + * packet, and not an indication the connection is closed like on + * tcp */ continue; - else if (count <= 0) + } else if (read_len < 0) { + if (try_again(SOCKERRNO)) + continue; + handle_error(channel, i, now); + #ifdef HAVE_RECVFROM - else if (!same_address(&from.sa, &server->addr)) + } else if (!same_address(&from.sa, &server->addr)) { /* The address the response comes from does not match the address we * sent the request to. Someone may be attempting to perform a cache * poisoning attack. */ - break; + continue; #endif - else - process_answer(channel, buf, (int)count, i, 0, now); - } while (count > 0); + + } else { + process_answer(channel, buf, (int)read_len, i, 0, now); + } + } while (read_len >= 0); } } @@ -979,6 +988,22 @@ static int setsocknonblock(ares_socket_t sockfd, /* operate on this */ #endif } +#if defined(IPV6_V6ONLY) && defined(WIN32) +/* It makes support for IPv4-mapped IPv6 addresses. + * Linux kernel, NetBSD, FreeBSD and Darwin: default is off; + * Windows Vista and later: default is on; + * DragonFly BSD: acts like off, and dummy setting; + * OpenBSD and earlier Windows: unsupported. + * Linux: controlled by /proc/sys/net/ipv6/bindv6only. + */ +static void set_ipv6_v6only(ares_socket_t sockfd, int on) +{ + (void)setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&on, sizeof(on)); +} +#else +#define set_ipv6_v6only(s,v) +#endif + static int configure_socket(ares_socket_t s, int family, ares_channel channel) { union { @@ -1041,6 +1066,7 @@ static int configure_socket(ares_socket_t s, int family, ares_channel channel) if (bind(s, &local.sa, sizeof(local.sa6)) < 0) return -1; } + set_ipv6_v6only(s, 0); } return 0; diff --git a/lib/c-ares-1.19.0/src/lib/ares_query.c b/lib/c-ares-1.19.1/src/lib/ares_query.c similarity index 84% rename from lib/c-ares-1.19.0/src/lib/ares_query.c rename to lib/c-ares-1.19.1/src/lib/ares_query.c index 508274db36c..42323bec553 100644 --- a/lib/c-ares-1.19.0/src/lib/ares_query.c +++ b/lib/c-ares-1.19.1/src/lib/ares_query.c @@ -33,32 +33,6 @@ struct qquery { static void qcallback(void *arg, int status, int timeouts, unsigned char *abuf, int alen); -static void rc4(rc4_key* key, unsigned char *buffer_ptr, int buffer_len) -{ - unsigned char x; - unsigned char y; - unsigned char* state; - unsigned char xorIndex; - int counter; - - x = key->x; - y = key->y; - - state = &key->state[0]; - for(counter = 0; counter < buffer_len; counter ++) - { - x = (unsigned char)((x + 1) % 256); - y = (unsigned char)((state[x] + y) % 256); - ARES_SWAP_BYTE(&state[x], &state[y]); - - xorIndex = (unsigned char)((state[x] + state[y]) % 256); - - buffer_ptr[counter] = (unsigned char)(buffer_ptr[counter]^state[xorIndex]); - } - key->x = x; - key->y = y; -} - static struct query* find_query_by_id(ares_channel channel, unsigned short id) { unsigned short qid; @@ -78,7 +52,6 @@ static struct query* find_query_by_id(ares_channel channel, unsigned short id) return NULL; } - /* a unique query id is generated using an rc4 key. Since the id may already be used by a running query (as infrequent as it may be), a lookup is performed per id generation. In practice this search should happen only @@ -89,19 +62,12 @@ static unsigned short generate_unique_id(ares_channel channel) unsigned short id; do { - id = ares__generate_new_id(&channel->id_key); + id = ares__generate_new_id(channel->rand_state); } while (find_query_by_id(channel, id)); return (unsigned short)id; } -unsigned short ares__generate_new_id(rc4_key* key) -{ - unsigned short r=0; - rc4(key, (unsigned char *)&r, sizeof(r)); - return r; -} - void ares_query(ares_channel channel, const char *name, int dnsclass, int type, ares_callback callback, void *arg) { diff --git a/lib/c-ares-1.19.1/src/lib/ares_rand.c b/lib/c-ares-1.19.1/src/lib/ares_rand.c new file mode 100644 index 00000000000..766c1e6ea9b --- /dev/null +++ b/lib/c-ares-1.19.1/src/lib/ares_rand.c @@ -0,0 +1,279 @@ +/* Copyright 1998 by the Massachusetts Institute of Technology. + * Copyright (C) 2007-2013 by Daniel Stenberg + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" + * without express or implied warranty. + */ + +#include "ares_setup.h" +#include "ares.h" +#include "ares_private.h" +#include "ares_nowarn.h" +#include + +typedef enum { + ARES_RAND_OS = 1, /* OS-provided such as RtlGenRandom or arc4random */ + ARES_RAND_FILE = 2, /* OS file-backed random number generator */ + ARES_RAND_RC4 = 3 /* Internal RC4 based PRNG */ +} ares_rand_backend; + +typedef struct ares_rand_rc4 +{ + unsigned char S[256]; + size_t i; + size_t j; +} ares_rand_rc4; + +struct ares_rand_state +{ + ares_rand_backend type; + union { + FILE *rand_file; + ares_rand_rc4 rc4; + } state; +}; + + +/* Define RtlGenRandom = SystemFunction036. This is in advapi32.dll. There is + * no need to dynamically load this, other software used widely does not. + * http://blogs.msdn.com/michael_howard/archive/2005/01/14/353379.aspx + * https://docs.microsoft.com/en-us/windows/win32/api/ntsecapi/nf-ntsecapi-rtlgenrandom + */ +#ifdef _WIN32 +BOOLEAN WINAPI SystemFunction036(PVOID RandomBuffer, ULONG RandomBufferLength); +# ifndef RtlGenRandom +# define RtlGenRandom(a,b) SystemFunction036(a,b) +# endif +#endif + + +#define ARES_RC4_KEY_LEN 32 /* 256 bits */ + +#ifdef _MSC_VER +typedef unsigned __int64 cares_u64; +#else +typedef unsigned long long cares_u64; +#endif + +static unsigned int ares_u32_from_ptr(void *addr) +{ + if (sizeof(void *) == 8) { + return (unsigned int)((((cares_u64)addr >> 32) & 0xFFFFFFFF) | ((cares_u64)addr & 0xFFFFFFFF)); + } + return (unsigned int)((size_t)addr & 0xFFFFFFFF); +} + + +/* initialize an rc4 key as the last possible fallback. */ +static void ares_rc4_generate_key(ares_rand_rc4 *rc4_state, unsigned char *key, size_t key_len) +{ + size_t i; + size_t len = 0; + unsigned int data; + struct timeval tv; + + if (key_len != ARES_RC4_KEY_LEN) + return; + + /* Randomness is hard to come by. Maybe the system randomizes heap and stack addresses. + * Maybe the current timestamp give us some randomness. + * Use rc4_state (heap), &i (stack), and ares__tvnow() + */ + data = ares_u32_from_ptr(rc4_state); + memcpy(key + len, &data, sizeof(data)); + len += sizeof(data); + + data = ares_u32_from_ptr(&i); + memcpy(key + len, &data, sizeof(data)); + len += sizeof(data); + + tv = ares__tvnow(); + data = (unsigned int)((tv.tv_sec | tv.tv_usec) & 0xFFFFFFFF); + memcpy(key + len, &data, sizeof(data)); + len += sizeof(data); + + srand(ares_u32_from_ptr(rc4_state) | ares_u32_from_ptr(&i) | (unsigned int)((tv.tv_sec | tv.tv_usec) & 0xFFFFFFFF)); + + for (i=len; iS); i++) { + rc4_state->S[i] = i & 0xFF; + } + + for(i = 0, j = 0; i < 256; i++) { + j = (j + rc4_state->S[i] + key[i % sizeof(key)]) % 256; + ARES_SWAP_BYTE(&rc4_state->S[i], &rc4_state->S[j]); + } + + rc4_state->i = 0; + rc4_state->j = 0; +} + +/* Just outputs the key schedule, no need to XOR with any data since we have none */ +static void ares_rc4_prng(ares_rand_rc4 *rc4_state, unsigned char *buf, size_t len) +{ + unsigned char *S = rc4_state->S; + size_t i = rc4_state->i; + size_t j = rc4_state->j; + size_t cnt; + + for (cnt=0; cnti = i; + rc4_state->j = j; +} + + +static int ares__init_rand_engine(ares_rand_state *state) +{ + memset(state, 0, sizeof(*state)); + +#if defined(HAVE_ARC4RANDOM_BUF) || defined(_WIN32) + state->type = ARES_RAND_OS; + return 1; +#elif defined(CARES_RANDOM_FILE) + state->type = ARES_RAND_FILE; + state->state.rand_file = fopen(CARES_RANDOM_FILE, "rb"); + if (state->state.rand_file) { + setvbuf(state->state.rand_file, NULL, _IONBF, 0); + return 1; + } + /* Fall-Thru on failure to RC4 */ +#endif + + state->type = ARES_RAND_RC4; + ares_rc4_init(&state->state.rc4); + + /* Currently cannot fail */ + return 1; +} + + +ares_rand_state *ares__init_rand_state() +{ + ares_rand_state *state = NULL; + + state = ares_malloc(sizeof(*state)); + if (!state) + return NULL; + + if (!ares__init_rand_engine(state)) { + ares_free(state); + return NULL; + } + + return state; +} + + +static void ares__clear_rand_state(ares_rand_state *state) +{ + if (!state) + return; + + switch (state->type) { + case ARES_RAND_OS: + break; + case ARES_RAND_FILE: + fclose(state->state.rand_file); + break; + case ARES_RAND_RC4: + break; + } +} + + +static void ares__reinit_rand(ares_rand_state *state) +{ + ares__clear_rand_state(state); + ares__init_rand_engine(state); +} + + +void ares__destroy_rand_state(ares_rand_state *state) +{ + if (!state) + return; + + ares__clear_rand_state(state); + ares_free(state); +} + + +static void ares__rand_bytes(ares_rand_state *state, unsigned char *buf, size_t len) +{ + + while (1) { + size_t bytes_read = 0; + + switch (state->type) { + case ARES_RAND_OS: +#ifdef _WIN32 + RtlGenRandom(buf, len); + return; +#elif defined(HAVE_ARC4RANDOM_BUF) + arc4random_buf(buf, len); + return; +#else + /* Shouldn't be possible to be here */ + break; +#endif + + case ARES_RAND_FILE: + while (1) { + size_t rv = fread(buf + bytes_read, 1, len - bytes_read, state->state.rand_file); + if (rv == 0) + break; /* critical error, will reinit rand state */ + + bytes_read += rv; + if (bytes_read == len) + return; + } + break; + + case ARES_RAND_RC4: + ares_rc4_prng(&state->state.rc4, buf, len); + return; + } + + /* If we didn't return before we got here, that means we had a critical rand + * failure and need to reinitialized */ + ares__reinit_rand(state); + } +} + +unsigned short ares__generate_new_id(ares_rand_state *state) +{ + unsigned short r=0; + + ares__rand_bytes(state, (unsigned char *)&r, sizeof(r)); + return r; +} + diff --git a/lib/c-ares-1.19.0/src/lib/ares_search.c b/lib/c-ares-1.19.1/src/lib/ares_search.c similarity index 100% rename from lib/c-ares-1.19.0/src/lib/ares_search.c rename to lib/c-ares-1.19.1/src/lib/ares_search.c diff --git a/lib/c-ares-1.19.0/src/lib/ares_send.c b/lib/c-ares-1.19.1/src/lib/ares_send.c similarity index 99% rename from lib/c-ares-1.19.0/src/lib/ares_send.c rename to lib/c-ares-1.19.1/src/lib/ares_send.c index 75ba9e4cc60..542cf45f11a 100644 --- a/lib/c-ares-1.19.0/src/lib/ares_send.c +++ b/lib/c-ares-1.19.1/src/lib/ares_send.c @@ -39,7 +39,11 @@ void ares_send(ares_channel channel, const unsigned char *qbuf, int qlen, callback(arg, ARES_EBADQUERY, 0, NULL, 0); return; } - + if (channel->nservers < 1) + { + callback(arg, ARES_ESERVFAIL, 0, NULL, 0); + return; + } /* Allocate space for query and allocated fields. */ query = ares_malloc(sizeof(struct query)); if (!query) @@ -54,12 +58,6 @@ void ares_send(ares_channel channel, const unsigned char *qbuf, int qlen, callback(arg, ARES_ENOMEM, 0, NULL, 0); return; } - if (channel->nservers < 1) - { - ares_free(query); - callback(arg, ARES_ESERVFAIL, 0, NULL, 0); - return; - } query->server_info = ares_malloc(channel->nservers * sizeof(query->server_info[0])); if (!query->server_info) diff --git a/lib/c-ares-1.19.0/src/lib/ares_setup.h b/lib/c-ares-1.19.1/src/lib/ares_setup.h similarity index 100% rename from lib/c-ares-1.19.0/src/lib/ares_setup.h rename to lib/c-ares-1.19.1/src/lib/ares_setup.h diff --git a/lib/c-ares-1.19.0/src/lib/ares_strcasecmp.c b/lib/c-ares-1.19.1/src/lib/ares_strcasecmp.c similarity index 100% rename from lib/c-ares-1.19.0/src/lib/ares_strcasecmp.c rename to lib/c-ares-1.19.1/src/lib/ares_strcasecmp.c diff --git a/lib/c-ares-1.19.0/src/lib/ares_strcasecmp.h b/lib/c-ares-1.19.1/src/lib/ares_strcasecmp.h similarity index 100% rename from lib/c-ares-1.19.0/src/lib/ares_strcasecmp.h rename to lib/c-ares-1.19.1/src/lib/ares_strcasecmp.h diff --git a/lib/c-ares-1.19.0/src/lib/ares_strdup.c b/lib/c-ares-1.19.1/src/lib/ares_strdup.c similarity index 100% rename from lib/c-ares-1.19.0/src/lib/ares_strdup.c rename to lib/c-ares-1.19.1/src/lib/ares_strdup.c diff --git a/lib/c-ares-1.19.0/src/lib/ares_strdup.h b/lib/c-ares-1.19.1/src/lib/ares_strdup.h similarity index 100% rename from lib/c-ares-1.19.0/src/lib/ares_strdup.h rename to lib/c-ares-1.19.1/src/lib/ares_strdup.h diff --git a/lib/c-ares-1.19.0/src/lib/ares_strerror.c b/lib/c-ares-1.19.1/src/lib/ares_strerror.c similarity index 100% rename from lib/c-ares-1.19.0/src/lib/ares_strerror.c rename to lib/c-ares-1.19.1/src/lib/ares_strerror.c diff --git a/lib/c-ares-1.19.0/src/lib/ares_strsplit.c b/lib/c-ares-1.19.1/src/lib/ares_strsplit.c similarity index 93% rename from lib/c-ares-1.19.0/src/lib/ares_strsplit.c rename to lib/c-ares-1.19.1/src/lib/ares_strsplit.c index 194375c8308..d3e90c4a8f6 100644 --- a/lib/c-ares-1.19.0/src/lib/ares_strsplit.c +++ b/lib/c-ares-1.19.1/src/lib/ares_strsplit.c @@ -18,7 +18,6 @@ #endif #include "ares_setup.h" -#include "ares_strsplit.h" #include "ares.h" #include "ares_private.h" @@ -55,7 +54,7 @@ char **ares__strsplit(const char *in, const char *delms, size_t *num_elm) { count++; p += i; } - } while(*p++ != 0); + } while (*p++ != 0); if (count == 0) return NULL; @@ -69,13 +68,8 @@ char **ares__strsplit(const char *in, const char *delms, size_t *num_elm) { i = strcspn(p, delms); if (i != 0) { for (k = 0; k < j; k++) { -#ifdef WIN32 - if (strnicmp(table[k], p, i) == 0 && table[k][i] == 0) - break; -#else if (strncasecmp(table[k], p, i) == 0 && table[k][i] == 0) break; -#endif } if (k == j) { /* copy unique strings only */ diff --git a/lib/c-ares-1.19.0/src/lib/ares_strsplit.h b/lib/c-ares-1.19.1/src/lib/ares_strsplit.h similarity index 100% rename from lib/c-ares-1.19.0/src/lib/ares_strsplit.h rename to lib/c-ares-1.19.1/src/lib/ares_strsplit.h diff --git a/lib/c-ares-1.19.0/src/lib/ares_timeout.c b/lib/c-ares-1.19.1/src/lib/ares_timeout.c similarity index 100% rename from lib/c-ares-1.19.0/src/lib/ares_timeout.c rename to lib/c-ares-1.19.1/src/lib/ares_timeout.c diff --git a/lib/c-ares-1.19.0/src/lib/ares_version.c b/lib/c-ares-1.19.1/src/lib/ares_version.c similarity index 100% rename from lib/c-ares-1.19.0/src/lib/ares_version.c rename to lib/c-ares-1.19.1/src/lib/ares_version.c diff --git a/lib/c-ares-1.19.0/src/lib/ares_writev.c b/lib/c-ares-1.19.1/src/lib/ares_writev.c similarity index 100% rename from lib/c-ares-1.19.0/src/lib/ares_writev.c rename to lib/c-ares-1.19.1/src/lib/ares_writev.c diff --git a/lib/c-ares-1.19.0/src/lib/ares_writev.h b/lib/c-ares-1.19.1/src/lib/ares_writev.h similarity index 100% rename from lib/c-ares-1.19.0/src/lib/ares_writev.h rename to lib/c-ares-1.19.1/src/lib/ares_writev.h diff --git a/lib/c-ares-1.19.0/src/lib/bitncmp.c b/lib/c-ares-1.19.1/src/lib/bitncmp.c similarity index 100% rename from lib/c-ares-1.19.0/src/lib/bitncmp.c rename to lib/c-ares-1.19.1/src/lib/bitncmp.c diff --git a/lib/c-ares-1.19.0/src/lib/bitncmp.h b/lib/c-ares-1.19.1/src/lib/bitncmp.h similarity index 100% rename from lib/c-ares-1.19.0/src/lib/bitncmp.h rename to lib/c-ares-1.19.1/src/lib/bitncmp.h diff --git a/lib/c-ares-1.19.0/src/lib/cares.rc b/lib/c-ares-1.19.1/src/lib/cares.rc similarity index 100% rename from lib/c-ares-1.19.0/src/lib/cares.rc rename to lib/c-ares-1.19.1/src/lib/cares.rc diff --git a/lib/c-ares-1.19.0/src/lib/config-dos.h b/lib/c-ares-1.19.1/src/lib/config-dos.h similarity index 100% rename from lib/c-ares-1.19.0/src/lib/config-dos.h rename to lib/c-ares-1.19.1/src/lib/config-dos.h diff --git a/lib/c-ares-1.19.0/src/lib/config-win32.h b/lib/c-ares-1.19.1/src/lib/config-win32.h similarity index 100% rename from lib/c-ares-1.19.0/src/lib/config-win32.h rename to lib/c-ares-1.19.1/src/lib/config-win32.h diff --git a/lib/c-ares-1.19.0/src/lib/inet_net_pton.c b/lib/c-ares-1.19.1/src/lib/inet_net_pton.c similarity index 73% rename from lib/c-ares-1.19.0/src/lib/inet_net_pton.c rename to lib/c-ares-1.19.1/src/lib/inet_net_pton.c index 840de506529..7130f0f1e22 100644 --- a/lib/c-ares-1.19.0/src/lib/inet_net_pton.c +++ b/lib/c-ares-1.19.1/src/lib/inet_net_pton.c @@ -1,19 +1,20 @@ /* - * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 2012 by Gilles Chehade * Copyright (c) 1996,1999 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * - * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT - * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. */ #include "ares_setup.h" @@ -35,9 +36,6 @@ const struct ares_in6_addr ares_in6addr_any = { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } }; - -#ifndef HAVE_INET_NET_PTON - /* * static int * inet_net_pton_ipv4(src, dst, size) @@ -60,7 +58,7 @@ const struct ares_in6_addr ares_in6addr_any = { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0, * Paul Vixie (ISC), June 1996 */ static int -inet_net_pton_ipv4(const char *src, unsigned char *dst, size_t size) +ares_inet_net_pton_ipv4(const char *src, unsigned char *dst, size_t size) { static const char xdigits[] = "0123456789abcdef"; static const char digits[] = "0123456789"; @@ -216,64 +214,16 @@ getbits(const char *src, int *bitsp) return (1); } -static int -getv4(const char *src, unsigned char *dst, int *bitsp) -{ - static const char digits[] = "0123456789"; - unsigned char *odst = dst; - int n; - unsigned int val; - char ch; - - val = 0; - n = 0; - while ((ch = *src++) != '\0') { - const char *pch; - - pch = strchr(digits, ch); - if (pch != NULL) { - if (n++ != 0 && val == 0) /* no leading zeros */ - return (0); - val *= 10; - val += aresx_sztoui(pch - digits); - if (val > 255) /* range */ - return (0); - continue; - } - if (ch == '.' || ch == '/') { - if (dst - odst > 3) /* too many octets? */ - return (0); - *dst++ = (unsigned char)val; - if (ch == '/') - return (getbits(src, bitsp)); - val = 0; - n = 0; - continue; - } - return (0); - } - if (n == 0) - return (0); - if (dst - odst > 3) /* too many octets? */ - return (0); - *dst = (unsigned char)val; - return 1; -} static int -inet_net_pton_ipv6(const char *src, unsigned char *dst, size_t size) +ares_inet_pton6(const char *src, unsigned char *dst) { static const char xdigits_l[] = "0123456789abcdef", - xdigits_u[] = "0123456789ABCDEF"; + xdigits_u[] = "0123456789ABCDEF"; unsigned char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp; const char *xdigits, *curtok; - int ch, saw_xdigit; + int ch, saw_xdigit, count_xdigit; unsigned int val; - int digits; - int bits; - size_t bytes; - int words; - int ipv4; memset((tp = tmp), '\0', NS_IN6ADDRSZ); endp = tp + NS_IN6ADDRSZ; @@ -283,22 +233,22 @@ inet_net_pton_ipv6(const char *src, unsigned char *dst, size_t size) if (*++src != ':') goto enoent; curtok = src; - saw_xdigit = 0; + saw_xdigit = count_xdigit = 0; val = 0; - digits = 0; - bits = -1; - ipv4 = 0; while ((ch = *src++) != '\0') { const char *pch; if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) pch = strchr((xdigits = xdigits_u), ch); if (pch != NULL) { + if (count_xdigit >= 4) + goto enoent; val <<= 4; - val |= aresx_sztoui(pch - xdigits); - if (++digits > 4) + val |= (unsigned int)(pch - xdigits); + if (val > 0xffff) goto enoent; saw_xdigit = 1; + count_xdigit++; continue; } if (ch == ':') { @@ -308,76 +258,99 @@ inet_net_pton_ipv6(const char *src, unsigned char *dst, size_t size) goto enoent; colonp = tp; continue; - } else if (*src == '\0') + } else if (*src == '\0') { goto enoent; + } if (tp + NS_INT16SZ > endp) - return (0); - *tp++ = (unsigned char)((val >> 8) & 0xff); - *tp++ = (unsigned char)(val & 0xff); + goto enoent; + *tp++ = (unsigned char) (val >> 8) & 0xff; + *tp++ = (unsigned char) val & 0xff; saw_xdigit = 0; - digits = 0; + count_xdigit = 0; val = 0; continue; } if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) && - getv4(curtok, tp, &bits) > 0) { + ares_inet_net_pton_ipv4(curtok, tp, NS_INADDRSZ) > 0) { tp += NS_INADDRSZ; saw_xdigit = 0; - ipv4 = 1; break; /* '\0' was seen by inet_pton4(). */ } - if (ch == '/' && getbits(src, &bits) > 0) - break; goto enoent; } if (saw_xdigit) { if (tp + NS_INT16SZ > endp) goto enoent; - *tp++ = (unsigned char)((val >> 8) & 0xff); - *tp++ = (unsigned char)(val & 0xff); + *tp++ = (unsigned char) (val >> 8) & 0xff; + *tp++ = (unsigned char) val & 0xff; } - if (bits == -1) - bits = 128; - - words = (bits + 15) / 16; - if (words < 2) - words = 2; - if (ipv4) - words = 8; - endp = tmp + 2 * words; - if (colonp != NULL) { /* * Since some memmove()'s erroneously fail to handle * overlapping regions, we'll do the shift by hand. */ - const ares_ssize_t n = tp - colonp; - ares_ssize_t i; + const int n = (int)(tp - colonp); + int i; if (tp == endp) goto enoent; for (i = 1; i <= n; i++) { - *(endp - i) = *(colonp + n - i); - *(colonp + n - i) = 0; + endp[- i] = colonp[n - i]; + colonp[n - i] = 0; } tp = endp; } if (tp != endp) goto enoent; - bytes = (bits + 7) / 8; - if (bytes > size) - goto emsgsize; - memcpy(dst, tmp, bytes); - return (bits); + memcpy(dst, tmp, NS_IN6ADDRSZ); + return (1); - enoent: +enoent: SET_ERRNO(ENOENT); return (-1); +} - emsgsize: - SET_ERRNO(EMSGSIZE); - return (-1); +static int +ares_inet_net_pton_ipv6(const char *src, unsigned char *dst, size_t size) +{ + struct ares_in6_addr in6; + int ret; + int bits; + size_t bytes; + char buf[INET6_ADDRSTRLEN + sizeof("/128")]; + char *sep; + + if (strlen(src) >= sizeof buf) { + SET_ERRNO(EMSGSIZE); + return (-1); + } + strncpy(buf, src, sizeof buf); + + sep = strchr(buf, '/'); + if (sep != NULL) + *sep++ = '\0'; + + ret = ares_inet_pton6(buf, (unsigned char *)&in6); + if (ret != 1) + return (-1); + + if (sep == NULL) + bits = 128; + else { + if (!getbits(sep, &bits)) { + SET_ERRNO(ENOENT); + return (-1); + } + } + + bytes = (bits + 7) / 8; + if (bytes > size) { + SET_ERRNO(EMSGSIZE); + return (-1); + } + memcpy(dst, &in6, bytes); + return (bits); } /* @@ -403,18 +376,15 @@ ares_inet_net_pton(int af, const char *src, void *dst, size_t size) { switch (af) { case AF_INET: - return (inet_net_pton_ipv4(src, dst, size)); + return (ares_inet_net_pton_ipv4(src, dst, size)); case AF_INET6: - return (inet_net_pton_ipv6(src, dst, size)); + return (ares_inet_net_pton_ipv6(src, dst, size)); default: SET_ERRNO(EAFNOSUPPORT); return (-1); } } -#endif /* HAVE_INET_NET_PTON */ - -#ifndef HAVE_INET_PTON int ares_inet_pton(int af, const char *src, void *dst) { int result; @@ -434,11 +404,3 @@ int ares_inet_pton(int af, const char *src, void *dst) return 0; return (result > -1 ? 1 : -1); } -#else /* HAVE_INET_PTON */ -int ares_inet_pton(int af, const char *src, void *dst) -{ - /* just relay this to the underlying function */ - return inet_pton(af, src, dst); -} - -#endif diff --git a/lib/c-ares-1.19.0/src/lib/inet_ntop.c b/lib/c-ares-1.19.1/src/lib/inet_ntop.c similarity index 100% rename from lib/c-ares-1.19.0/src/lib/inet_ntop.c rename to lib/c-ares-1.19.1/src/lib/inet_ntop.c diff --git a/lib/c-ares-1.19.0/src/lib/setup_once.h b/lib/c-ares-1.19.1/src/lib/setup_once.h similarity index 100% rename from lib/c-ares-1.19.0/src/lib/setup_once.h rename to lib/c-ares-1.19.1/src/lib/setup_once.h diff --git a/lib/c-ares-1.19.0/src/lib/windows_port.c b/lib/c-ares-1.19.1/src/lib/windows_port.c similarity index 100% rename from lib/c-ares-1.19.0/src/lib/windows_port.c rename to lib/c-ares-1.19.1/src/lib/windows_port.c diff --git a/lib/c-ares-1.19.0/src/tools/CMakeLists.txt b/lib/c-ares-1.19.1/src/tools/CMakeLists.txt similarity index 100% rename from lib/c-ares-1.19.0/src/tools/CMakeLists.txt rename to lib/c-ares-1.19.1/src/tools/CMakeLists.txt diff --git a/lib/c-ares-1.19.0/src/tools/Makefile.am b/lib/c-ares-1.19.1/src/tools/Makefile.am similarity index 100% rename from lib/c-ares-1.19.0/src/tools/Makefile.am rename to lib/c-ares-1.19.1/src/tools/Makefile.am diff --git a/lib/c-ares-1.19.0/src/tools/Makefile.in b/lib/c-ares-1.19.1/src/tools/Makefile.in similarity index 99% rename from lib/c-ares-1.19.0/src/tools/Makefile.in rename to lib/c-ares-1.19.1/src/tools/Makefile.in index 709061ec79e..9e64462d591 100644 --- a/lib/c-ares-1.19.0/src/tools/Makefile.in +++ b/lib/c-ares-1.19.1/src/tools/Makefile.in @@ -98,6 +98,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_ac_append_to_file.m4 \ $(top_srcdir)/m4/ax_am_macros_static.m4 \ $(top_srcdir)/m4/ax_check_gnu_make.m4 \ $(top_srcdir)/m4/ax_code_coverage.m4 \ + $(top_srcdir)/m4/ax_cxx_compile_stdcxx.m4 \ $(top_srcdir)/m4/ax_cxx_compile_stdcxx_11.m4 \ $(top_srcdir)/m4/ax_file_escapes.m4 \ $(top_srcdir)/m4/ax_require_defined.m4 \ diff --git a/lib/c-ares-1.19.0/src/tools/Makefile.inc b/lib/c-ares-1.19.1/src/tools/Makefile.inc similarity index 100% rename from lib/c-ares-1.19.0/src/tools/Makefile.inc rename to lib/c-ares-1.19.1/src/tools/Makefile.inc diff --git a/lib/c-ares-1.19.0/src/tools/acountry.c b/lib/c-ares-1.19.1/src/tools/acountry.c similarity index 100% rename from lib/c-ares-1.19.0/src/tools/acountry.c rename to lib/c-ares-1.19.1/src/tools/acountry.c diff --git a/lib/c-ares-1.19.0/src/tools/adig.c b/lib/c-ares-1.19.1/src/tools/adig.c similarity index 100% rename from lib/c-ares-1.19.0/src/tools/adig.c rename to lib/c-ares-1.19.1/src/tools/adig.c diff --git a/lib/c-ares-1.19.0/src/tools/ahost.c b/lib/c-ares-1.19.1/src/tools/ahost.c similarity index 100% rename from lib/c-ares-1.19.0/src/tools/ahost.c rename to lib/c-ares-1.19.1/src/tools/ahost.c diff --git a/lib/c-ares-1.19.0/src/tools/ares_getopt.c b/lib/c-ares-1.19.1/src/tools/ares_getopt.c similarity index 100% rename from lib/c-ares-1.19.0/src/tools/ares_getopt.c rename to lib/c-ares-1.19.1/src/tools/ares_getopt.c diff --git a/lib/c-ares-1.19.0/src/tools/ares_getopt.h b/lib/c-ares-1.19.1/src/tools/ares_getopt.h similarity index 100% rename from lib/c-ares-1.19.0/src/tools/ares_getopt.h rename to lib/c-ares-1.19.1/src/tools/ares_getopt.h diff --git a/lib/c-ares-1.19.0/test/CMakeLists.txt b/lib/c-ares-1.19.1/test/CMakeLists.txt similarity index 100% rename from lib/c-ares-1.19.0/test/CMakeLists.txt rename to lib/c-ares-1.19.1/test/CMakeLists.txt diff --git a/lib/c-ares-1.19.0/test/Makefile.am b/lib/c-ares-1.19.1/test/Makefile.am similarity index 100% rename from lib/c-ares-1.19.0/test/Makefile.am rename to lib/c-ares-1.19.1/test/Makefile.am diff --git a/lib/c-ares-1.19.0/test/Makefile.in b/lib/c-ares-1.19.1/test/Makefile.in similarity index 99% rename from lib/c-ares-1.19.0/test/Makefile.in rename to lib/c-ares-1.19.1/test/Makefile.in index 32af8d2a199..b4c9d24faba 100644 --- a/lib/c-ares-1.19.0/test/Makefile.in +++ b/lib/c-ares-1.19.1/test/Makefile.in @@ -15,7 +15,7 @@ @SET_MAKE@ # aminclude_static.am generated automatically by Autoconf -# from AX_AM_MACROS_STATIC on Tue Nov 8 13:43:42 CET 2022 +# from AX_AM_MACROS_STATIC on Mon May 22 13:36:05 CEST 2023 VPATH = @srcdir@ @@ -105,6 +105,7 @@ am__aclocal_m4_deps = $(top_srcdir)/../m4/ax_ac_append_to_file.m4 \ $(top_srcdir)/../m4/ax_check_user_namespace.m4 \ $(top_srcdir)/../m4/ax_check_uts_namespace.m4 \ $(top_srcdir)/../m4/ax_code_coverage.m4 \ + $(top_srcdir)/../m4/ax_cxx_compile_stdcxx.m4 \ $(top_srcdir)/../m4/ax_cxx_compile_stdcxx_11.m4 \ $(top_srcdir)/../m4/ax_file_escapes.m4 \ $(top_srcdir)/../m4/ax_pthread.m4 \ @@ -515,6 +516,7 @@ CODE_COVERAGE_CPPFLAGS = @CODE_COVERAGE_CPPFLAGS@ CODE_COVERAGE_CXXFLAGS = @CODE_COVERAGE_CXXFLAGS@ CODE_COVERAGE_ENABLED = @CODE_COVERAGE_ENABLED@ CODE_COVERAGE_LIBS = @CODE_COVERAGE_LIBS@ +CPP = @CPP@ # Note use of -isystem to force use of local gMock/gTest even if there's an installed version. CPPFLAGS = @CPPFLAGS@ -I$(ARES_BLD_DIR)/include \ @@ -580,6 +582,7 @@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PTHREAD_CC = @PTHREAD_CC@ PTHREAD_CFLAGS = @PTHREAD_CFLAGS@ +PTHREAD_CXX = @PTHREAD_CXX@ PTHREAD_LIBS = @PTHREAD_LIBS@ RANLIB = @RANLIB@ SED = @SED@ diff --git a/lib/c-ares-1.19.0/test/Makefile.inc b/lib/c-ares-1.19.1/test/Makefile.inc similarity index 100% rename from lib/c-ares-1.19.0/test/Makefile.inc rename to lib/c-ares-1.19.1/test/Makefile.inc diff --git a/lib/c-ares-1.19.0/test/Makefile.m32 b/lib/c-ares-1.19.1/test/Makefile.m32 similarity index 100% rename from lib/c-ares-1.19.0/test/Makefile.m32 rename to lib/c-ares-1.19.1/test/Makefile.m32 diff --git a/lib/c-ares-1.19.0/test/Makefile.msvc b/lib/c-ares-1.19.1/test/Makefile.msvc similarity index 100% rename from lib/c-ares-1.19.0/test/Makefile.msvc rename to lib/c-ares-1.19.1/test/Makefile.msvc diff --git a/lib/c-ares-1.19.0/test/README.md b/lib/c-ares-1.19.1/test/README.md similarity index 100% rename from lib/c-ares-1.19.0/test/README.md rename to lib/c-ares-1.19.1/test/README.md diff --git a/lib/c-ares-1.19.0/test/aclocal.m4 b/lib/c-ares-1.19.1/test/aclocal.m4 similarity index 99% rename from lib/c-ares-1.19.0/test/aclocal.m4 rename to lib/c-ares-1.19.1/test/aclocal.m4 index 3a57c5c2919..7b91744cfcd 100644 --- a/lib/c-ares-1.19.0/test/aclocal.m4 +++ b/lib/c-ares-1.19.1/test/aclocal.m4 @@ -1156,6 +1156,7 @@ m4_include([../m4/ax_check_gnu_make.m4]) m4_include([../m4/ax_check_user_namespace.m4]) m4_include([../m4/ax_check_uts_namespace.m4]) m4_include([../m4/ax_code_coverage.m4]) +m4_include([../m4/ax_cxx_compile_stdcxx.m4]) m4_include([../m4/ax_cxx_compile_stdcxx_11.m4]) m4_include([../m4/ax_file_escapes.m4]) m4_include([../m4/ax_pthread.m4]) diff --git a/lib/c-ares-1.19.0/aminclude_static.am b/lib/c-ares-1.19.1/test/aminclude_static.am similarity index 99% rename from lib/c-ares-1.19.0/aminclude_static.am rename to lib/c-ares-1.19.1/test/aminclude_static.am index aad78eb4b1e..33c6e9f2f34 100644 --- a/lib/c-ares-1.19.0/aminclude_static.am +++ b/lib/c-ares-1.19.1/test/aminclude_static.am @@ -1,6 +1,6 @@ # aminclude_static.am generated automatically by Autoconf -# from AX_AM_MACROS_STATIC on Sat Jan 28 22:07:59 CET 2023 +# from AX_AM_MACROS_STATIC on Mon May 22 13:36:05 CEST 2023 # Code coverage diff --git a/lib/c-ares-1.19.0/test/ares-fuzz.c b/lib/c-ares-1.19.1/test/ares-fuzz.c similarity index 100% rename from lib/c-ares-1.19.0/test/ares-fuzz.c rename to lib/c-ares-1.19.1/test/ares-fuzz.c diff --git a/lib/c-ares-1.19.0/test/ares-test-ai.h b/lib/c-ares-1.19.1/test/ares-test-ai.h similarity index 100% rename from lib/c-ares-1.19.0/test/ares-test-ai.h rename to lib/c-ares-1.19.1/test/ares-test-ai.h diff --git a/lib/c-ares-1.19.0/test/ares-test-fuzz-name.c b/lib/c-ares-1.19.1/test/ares-test-fuzz-name.c similarity index 100% rename from lib/c-ares-1.19.0/test/ares-test-fuzz-name.c rename to lib/c-ares-1.19.1/test/ares-test-fuzz-name.c diff --git a/lib/c-ares-1.19.0/test/ares-test-fuzz.c b/lib/c-ares-1.19.1/test/ares-test-fuzz.c similarity index 100% rename from lib/c-ares-1.19.0/test/ares-test-fuzz.c rename to lib/c-ares-1.19.1/test/ares-test-fuzz.c diff --git a/lib/c-ares-1.19.0/test/ares-test-init.cc b/lib/c-ares-1.19.1/test/ares-test-init.cc similarity index 100% rename from lib/c-ares-1.19.0/test/ares-test-init.cc rename to lib/c-ares-1.19.1/test/ares-test-init.cc diff --git a/lib/c-ares-1.19.0/test/ares-test-internal.cc b/lib/c-ares-1.19.1/test/ares-test-internal.cc similarity index 98% rename from lib/c-ares-1.19.0/test/ares-test-internal.cc rename to lib/c-ares-1.19.1/test/ares-test-internal.cc index 1cb7e427dcd..40cc82b86ec 100644 --- a/lib/c-ares-1.19.0/test/ares-test-internal.cc +++ b/lib/c-ares-1.19.1/test/ares-test-internal.cc @@ -123,6 +123,7 @@ TEST_F(LibraryTest, InetPtoN) { EXPECT_EQ(0, ares_inet_net_pton(AF_INET6, "12:34::ff/0", &a6, sizeof(a6))); EXPECT_EQ(16 * 8, ares_inet_net_pton(AF_INET6, "12:34::ffff:0.2", &a6, sizeof(a6))); EXPECT_EQ(16 * 8, ares_inet_net_pton(AF_INET6, "1234:1234:1234:1234:1234:1234:1234:1234", &a6, sizeof(a6))); + EXPECT_EQ(2, ares_inet_net_pton(AF_INET6, "0::00:00:00/2", &a6, sizeof(a6))); // Various malformed versions EXPECT_EQ(-1, ares_inet_net_pton(AF_INET, "", &a4, sizeof(a4))); @@ -160,11 +161,9 @@ TEST_F(LibraryTest, InetPtoN) { EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, ":1234:1234:1234:1234:1234:1234:1234:1234", &a6, sizeof(a6))); EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, ":1234:1234:1234:1234:1234:1234:1234:1234:", &a6, sizeof(a6))); EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "1234:1234:1234:1234:1234:1234:1234:1234:5678", &a6, sizeof(a6))); - // TODO(drysdale): check whether the next two tests should give -1. - EXPECT_EQ(0, ares_inet_net_pton(AF_INET6, "1234:1234:1234:1234:1234:1234:1234:1234:5678:5678", &a6, sizeof(a6))); - EXPECT_EQ(0, ares_inet_net_pton(AF_INET6, "1234:1234:1234:1234:1234:1234:1234:1234:5678:5678:5678", &a6, sizeof(a6))); + EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "1234:1234:1234:1234:1234:1234:1234:1234:5678:5678", &a6, sizeof(a6))); + EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "1234:1234:1234:1234:1234:1234:1234:1234:5678:5678:5678", &a6, sizeof(a6))); EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "12:34::ffff:257.2.3.4", &a6, sizeof(a6))); - EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "12:34::ffff:002.2.3.4", &a6, sizeof(a6))); EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "12:34::ffff:1.2.3.4.5.6", &a6, sizeof(a6))); EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "12:34::ffff:1.2.3.4.5", &a6, sizeof(a6))); EXPECT_EQ(-1, ares_inet_net_pton(AF_INET6, "12:34::ffff:1.2.3.z", &a6, sizeof(a6))); diff --git a/lib/c-ares-1.19.0/test/ares-test-live.cc b/lib/c-ares-1.19.1/test/ares-test-live.cc similarity index 100% rename from lib/c-ares-1.19.0/test/ares-test-live.cc rename to lib/c-ares-1.19.1/test/ares-test-live.cc diff --git a/lib/c-ares-1.19.0/test/ares-test-main.cc b/lib/c-ares-1.19.1/test/ares-test-main.cc similarity index 100% rename from lib/c-ares-1.19.0/test/ares-test-main.cc rename to lib/c-ares-1.19.1/test/ares-test-main.cc diff --git a/lib/c-ares-1.19.0/test/ares-test-misc.cc b/lib/c-ares-1.19.1/test/ares-test-misc.cc similarity index 99% rename from lib/c-ares-1.19.0/test/ares-test-misc.cc rename to lib/c-ares-1.19.1/test/ares-test-misc.cc index b11b04babc0..f85a3bf604a 100644 --- a/lib/c-ares-1.19.0/test/ares-test-misc.cc +++ b/lib/c-ares-1.19.1/test/ares-test-misc.cc @@ -298,7 +298,7 @@ TEST_F(DefaultChannelTest, SearchOnionDomain) { } TEST_F(DefaultChannelTest, SendFailure) { - unsigned char buf[2]; + unsigned char buf[2] = {}; SearchResult result; ares_send(channel_, buf, sizeof(buf), SearchCallback, &result); EXPECT_TRUE(result.done_); diff --git a/lib/c-ares-1.19.0/test/ares-test-mock-ai.cc b/lib/c-ares-1.19.1/test/ares-test-mock-ai.cc similarity index 100% rename from lib/c-ares-1.19.0/test/ares-test-mock-ai.cc rename to lib/c-ares-1.19.1/test/ares-test-mock-ai.cc diff --git a/lib/c-ares-1.19.0/test/ares-test-mock.cc b/lib/c-ares-1.19.1/test/ares-test-mock.cc similarity index 100% rename from lib/c-ares-1.19.0/test/ares-test-mock.cc rename to lib/c-ares-1.19.1/test/ares-test-mock.cc diff --git a/lib/c-ares-1.19.0/test/ares-test-ns.cc b/lib/c-ares-1.19.1/test/ares-test-ns.cc similarity index 100% rename from lib/c-ares-1.19.0/test/ares-test-ns.cc rename to lib/c-ares-1.19.1/test/ares-test-ns.cc diff --git a/lib/c-ares-1.19.0/test/ares-test-parse-a.cc b/lib/c-ares-1.19.1/test/ares-test-parse-a.cc similarity index 100% rename from lib/c-ares-1.19.0/test/ares-test-parse-a.cc rename to lib/c-ares-1.19.1/test/ares-test-parse-a.cc diff --git a/lib/c-ares-1.19.0/test/ares-test-parse-aaaa.cc b/lib/c-ares-1.19.1/test/ares-test-parse-aaaa.cc similarity index 100% rename from lib/c-ares-1.19.0/test/ares-test-parse-aaaa.cc rename to lib/c-ares-1.19.1/test/ares-test-parse-aaaa.cc diff --git a/lib/c-ares-1.19.0/test/ares-test-parse-caa.cc b/lib/c-ares-1.19.1/test/ares-test-parse-caa.cc similarity index 100% rename from lib/c-ares-1.19.0/test/ares-test-parse-caa.cc rename to lib/c-ares-1.19.1/test/ares-test-parse-caa.cc diff --git a/lib/c-ares-1.19.0/test/ares-test-parse-mx.cc b/lib/c-ares-1.19.1/test/ares-test-parse-mx.cc similarity index 100% rename from lib/c-ares-1.19.0/test/ares-test-parse-mx.cc rename to lib/c-ares-1.19.1/test/ares-test-parse-mx.cc diff --git a/lib/c-ares-1.19.0/test/ares-test-parse-naptr.cc b/lib/c-ares-1.19.1/test/ares-test-parse-naptr.cc similarity index 100% rename from lib/c-ares-1.19.0/test/ares-test-parse-naptr.cc rename to lib/c-ares-1.19.1/test/ares-test-parse-naptr.cc diff --git a/lib/c-ares-1.19.0/test/ares-test-parse-ns.cc b/lib/c-ares-1.19.1/test/ares-test-parse-ns.cc similarity index 100% rename from lib/c-ares-1.19.0/test/ares-test-parse-ns.cc rename to lib/c-ares-1.19.1/test/ares-test-parse-ns.cc diff --git a/lib/c-ares-1.19.0/test/ares-test-parse-ptr.cc b/lib/c-ares-1.19.1/test/ares-test-parse-ptr.cc similarity index 100% rename from lib/c-ares-1.19.0/test/ares-test-parse-ptr.cc rename to lib/c-ares-1.19.1/test/ares-test-parse-ptr.cc diff --git a/lib/c-ares-1.19.0/test/ares-test-parse-soa-any.cc b/lib/c-ares-1.19.1/test/ares-test-parse-soa-any.cc similarity index 100% rename from lib/c-ares-1.19.0/test/ares-test-parse-soa-any.cc rename to lib/c-ares-1.19.1/test/ares-test-parse-soa-any.cc diff --git a/lib/c-ares-1.19.0/test/ares-test-parse-soa.cc b/lib/c-ares-1.19.1/test/ares-test-parse-soa.cc similarity index 100% rename from lib/c-ares-1.19.0/test/ares-test-parse-soa.cc rename to lib/c-ares-1.19.1/test/ares-test-parse-soa.cc diff --git a/lib/c-ares-1.19.0/test/ares-test-parse-srv.cc b/lib/c-ares-1.19.1/test/ares-test-parse-srv.cc similarity index 100% rename from lib/c-ares-1.19.0/test/ares-test-parse-srv.cc rename to lib/c-ares-1.19.1/test/ares-test-parse-srv.cc diff --git a/lib/c-ares-1.19.0/test/ares-test-parse-txt.cc b/lib/c-ares-1.19.1/test/ares-test-parse-txt.cc similarity index 100% rename from lib/c-ares-1.19.0/test/ares-test-parse-txt.cc rename to lib/c-ares-1.19.1/test/ares-test-parse-txt.cc diff --git a/lib/c-ares-1.19.0/test/ares-test-parse-uri.cc b/lib/c-ares-1.19.1/test/ares-test-parse-uri.cc similarity index 100% rename from lib/c-ares-1.19.0/test/ares-test-parse-uri.cc rename to lib/c-ares-1.19.1/test/ares-test-parse-uri.cc diff --git a/lib/c-ares-1.19.0/test/ares-test-parse.cc b/lib/c-ares-1.19.1/test/ares-test-parse.cc similarity index 100% rename from lib/c-ares-1.19.0/test/ares-test-parse.cc rename to lib/c-ares-1.19.1/test/ares-test-parse.cc diff --git a/lib/c-ares-1.19.0/test/ares-test.cc b/lib/c-ares-1.19.1/test/ares-test.cc similarity index 100% rename from lib/c-ares-1.19.0/test/ares-test.cc rename to lib/c-ares-1.19.1/test/ares-test.cc diff --git a/lib/c-ares-1.19.0/test/ares-test.h b/lib/c-ares-1.19.1/test/ares-test.h similarity index 100% rename from lib/c-ares-1.19.0/test/ares-test.h rename to lib/c-ares-1.19.1/test/ares-test.h diff --git a/lib/c-ares-1.19.0/test/buildconf b/lib/c-ares-1.19.1/test/buildconf similarity index 100% rename from lib/c-ares-1.19.0/test/buildconf rename to lib/c-ares-1.19.1/test/buildconf diff --git a/lib/c-ares-1.19.0/test/compile b/lib/c-ares-1.19.1/test/compile similarity index 100% rename from lib/c-ares-1.19.0/test/compile rename to lib/c-ares-1.19.1/test/compile diff --git a/lib/c-ares-1.19.0/test/config.guess b/lib/c-ares-1.19.1/test/config.guess similarity index 100% rename from lib/c-ares-1.19.0/test/config.guess rename to lib/c-ares-1.19.1/test/config.guess diff --git a/lib/c-ares-1.19.0/test/config.h.in b/lib/c-ares-1.19.1/test/config.h.in similarity index 100% rename from lib/c-ares-1.19.0/test/config.h.in rename to lib/c-ares-1.19.1/test/config.h.in diff --git a/lib/c-ares-1.19.0/test/config.sub b/lib/c-ares-1.19.1/test/config.sub similarity index 100% rename from lib/c-ares-1.19.0/test/config.sub rename to lib/c-ares-1.19.1/test/config.sub diff --git a/lib/c-ares-1.19.0/test/configure b/lib/c-ares-1.19.1/test/configure similarity index 95% rename from lib/c-ares-1.19.0/test/configure rename to lib/c-ares-1.19.1/test/configure index 5ad0fb01cb3..b268a43efd9 100755 --- a/lib/c-ares-1.19.0/test/configure +++ b/lib/c-ares-1.19.1/test/configure @@ -676,8 +676,10 @@ CODE_COVERAGE_ENABLED_FALSE CODE_COVERAGE_ENABLED_TRUE PTHREAD_CFLAGS PTHREAD_LIBS +PTHREAD_CXX PTHREAD_CC ax_pthread_config +CPP LIBTOOL_DEPS CXXCPP LT_SYS_LIBRARY_PATH @@ -832,7 +834,8 @@ CCC CC CFLAGS LT_SYS_LIBRARY_PATH -CXXCPP' +CXXCPP +CPP' # Initialize some variables set by options. @@ -1499,6 +1502,7 @@ Some influential environment variables: LT_SYS_LIBRARY_PATH User-defined run-time library search path. CXXCPP C++ preprocessor + CPP C preprocessor Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. @@ -1886,6 +1890,44 @@ fi } # ac_fn_cxx_try_link +# ac_fn_c_try_cpp LINENO +# ---------------------- +# Try to preprocess conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_cpp () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +printf "%s\n" "$ac_try_echo"; } >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } > conftest.i && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + } +then : + ac_retval=0 +else $as_nop + printf "%s\n" "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_cpp + # ac_fn_c_try_run LINENO # ---------------------- # Try to run conftest.$ac_ext, and return whether this succeeded. Assumes that @@ -4120,11 +4162,11 @@ if test x$ac_prog_cxx_stdcxx = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CXX option to enable C++11 features" >&5 printf %s "checking for $CXX option to enable C++11 features... " >&6; } -if test ${ac_cv_prog_cxx_11+y} +if test ${ac_cv_prog_cxx_cxx11+y} then : printf %s "(cached) " >&6 else $as_nop - ac_cv_prog_cxx_11=no + ac_cv_prog_cxx_cxx11=no ac_save_CXX=$CXX cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -4166,11 +4208,11 @@ if test x$ac_prog_cxx_stdcxx = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CXX option to enable C++98 features" >&5 printf %s "checking for $CXX option to enable C++98 features... " >&6; } -if test ${ac_cv_prog_cxx_98+y} +if test ${ac_cv_prog_cxx_cxx98+y} then : printf %s "(cached) " >&6 else $as_nop - ac_cv_prog_cxx_98=no + ac_cv_prog_cxx_cxx98=no ac_save_CXX=$CXX cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -4409,144 +4451,323 @@ fi - ax_cxx_compile_cxx11_required=true + ax_cxx_compile_alternatives="11 0x" ax_cxx_compile_cxx11_required=true ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu ac_success=no - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CXX supports C++11 features by default" >&5 -printf %s "checking whether $CXX supports C++11 features by default... " >&6; } -if test ${ax_cv_cxx_compile_cxx11+y} + + + + + + if test x$ac_success = xno; then + for alternative in ${ax_cxx_compile_alternatives}; do + for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}"; do + cachevar=`printf "%s\n" "ax_cv_cxx_compile_cxx11_$switch" | $as_tr_sh` + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CXX supports C++11 features with $switch" >&5 +printf %s "checking whether $CXX supports C++11 features with $switch... " >&6; } +if eval test \${$cachevar+y} then : printf %s "(cached) " >&6 else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext + ac_save_CXX="$CXX" + CXX="$CXX $switch" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ - template + +// If the compiler admits that it is not ready for C++11, why torture it? +// Hopefully, this will speed up the test. + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +// MSVC always sets __cplusplus to 199711L in older versions; newer versions +// only set it correctly if /Zc:__cplusplus is specified as well as a +// /std:c++NN switch: +// https://devblogs.microsoft.com/cppblog/msvc-now-correctly-reports-__cplusplus/ +#elif __cplusplus < 201103L && !defined _MSC_VER + +#error "This is not a C++11 compiler" + +#else + +namespace cxx11 +{ + + namespace test_static_assert + { + + template struct check { static_assert(sizeof(int) <= sizeof(T), "not big enough"); }; - struct Base { - virtual void f() {} + } + + namespace test_final_override + { + + struct Base + { + virtual ~Base() {} + virtual void f() {} }; - struct Child : public Base { - virtual void f() override {} + + struct Derived : public Base + { + virtual ~Derived() override {} + virtual void f() override {} }; - typedef check> right_angle_brackets; + } + + namespace test_double_right_angle_brackets + { + + template < typename T > + struct check {}; - int a; - decltype(a) b; + typedef check single_type; + typedef check> double_type; + typedef check>> triple_type; + typedef check>>> quadruple_type; - typedef check check_type; - check_type c; - check_type&& cr = static_cast(c); + } - auto d = a; - auto l = [](){}; + namespace test_decltype + { - // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae - // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function because of this - namespace test_template_alias_sfinae { - struct foo {}; + int + f() + { + int a = 1; + decltype(a) b = 2; + return a + b; + } - template - using member = typename T::member_type; + } - template - void func(...) {} + namespace test_type_deduction + { - template - void func(member*) {} + template < typename T1, typename T2 > + struct is_same + { + static const bool value = false; + }; - void test(); + template < typename T > + struct is_same + { + static const bool value = true; + }; - void test() { - func(0); - } + template < typename T1, typename T2 > + auto + add(T1 a1, T2 a2) -> decltype(a1 + a2) + { + return a1 + a2; } -_ACEOF -if ac_fn_cxx_try_compile "$LINENO" -then : - ax_cv_cxx_compile_cxx11=yes -else $as_nop - ax_cv_cxx_compile_cxx11=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_cxx_compile_cxx11" >&5 -printf "%s\n" "$ax_cv_cxx_compile_cxx11" >&6; } - if test x$ax_cv_cxx_compile_cxx11 = xyes; then - ac_success=yes - fi + int + test(const int c, volatile int v) + { + static_assert(is_same::value == true, ""); + static_assert(is_same::value == false, ""); + static_assert(is_same::value == false, ""); + auto ac = c; + auto av = v; + auto sumi = ac + av + 'x'; + auto sumf = ac + av + 1.0; + static_assert(is_same::value == true, ""); + static_assert(is_same::value == true, ""); + static_assert(is_same::value == true, ""); + static_assert(is_same::value == false, ""); + static_assert(is_same::value == true, ""); + return (sumf > 0.0) ? sumi : add(c, v); + } + } + namespace test_noexcept + { - if test x$ac_success = xno; then - for switch in -std=c++11 -std=c++0x; do - cachevar=`printf "%s\n" "ax_cv_cxx_compile_cxx11_$switch" | $as_tr_sh` - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CXX supports C++11 features with $switch" >&5 -printf %s "checking whether $CXX supports C++11 features with $switch... " >&6; } -if eval test \${$cachevar+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_save_CXXFLAGS="$CXXFLAGS" - CXXFLAGS="$CXXFLAGS $switch" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ + int f() { return 0; } + int g() noexcept { return 0; } - template - struct check + static_assert(noexcept(f()) == false, ""); + static_assert(noexcept(g()) == true, ""); + + } + + namespace test_constexpr + { + + template < typename CharT > + unsigned long constexpr + strlen_c_r(const CharT *const s, const unsigned long acc) noexcept { - static_assert(sizeof(int) <= sizeof(T), "not big enough"); + return *s ? strlen_c_r(s + 1, acc + 1) : acc; + } + + template < typename CharT > + unsigned long constexpr + strlen_c(const CharT *const s) noexcept + { + return strlen_c_r(s, 0UL); + } + + static_assert(strlen_c("") == 0UL, ""); + static_assert(strlen_c("1") == 1UL, ""); + static_assert(strlen_c("example") == 7UL, ""); + static_assert(strlen_c("another\0example") == 7UL, ""); + + } + + namespace test_rvalue_references + { + + template < int N > + struct answer + { + static constexpr int value = N; }; - struct Base { - virtual void f() {} + answer<1> f(int&) { return answer<1>(); } + answer<2> f(const int&) { return answer<2>(); } + answer<3> f(int&&) { return answer<3>(); } + + void + test() + { + int i = 0; + const int c = 0; + static_assert(decltype(f(i))::value == 1, ""); + static_assert(decltype(f(c))::value == 2, ""); + static_assert(decltype(f(0))::value == 3, ""); + } + + } + + namespace test_uniform_initialization + { + + struct test + { + static const int zero {}; + static const int one {1}; }; - struct Child : public Base { - virtual void f() override {} + + static_assert(test::zero == 0, ""); + static_assert(test::one == 1, ""); + + } + + namespace test_lambdas + { + + void + test1() + { + auto lambda1 = [](){}; + auto lambda2 = lambda1; + lambda1(); + lambda2(); + } + + int + test2() + { + auto a = [](int i, int j){ return i + j; }(1, 2); + auto b = []() -> int { return '0'; }(); + auto c = [=](){ return a + b; }(); + auto d = [&](){ return c; }(); + auto e = [a, &b](int x) mutable { + const auto identity = [](int y){ return y; }; + for (auto i = 0; i < a; ++i) + a += b--; + return x + identity(a + b); + }(0); + return a + b + c + d + e; + } + + int + test3() + { + const auto nullary = [](){ return 0; }; + const auto unary = [](int x){ return x; }; + using nullary_t = decltype(nullary); + using unary_t = decltype(unary); + const auto higher1st = [](nullary_t f){ return f(); }; + const auto higher2nd = [unary](nullary_t f1){ + return [unary, f1](unary_t f2){ return f2(unary(f1())); }; + }; + return higher1st(nullary) + higher2nd(nullary)(unary); + } + + } + + namespace test_variadic_templates + { + + template + struct sum; + + template + struct sum + { + static constexpr auto value = N0 + sum::value; }; - typedef check> right_angle_brackets; + template <> + struct sum<> + { + static constexpr auto value = 0; + }; - int a; - decltype(a) b; + static_assert(sum<>::value == 0, ""); + static_assert(sum<1>::value == 1, ""); + static_assert(sum<23>::value == 23, ""); + static_assert(sum<1, 2>::value == 3, ""); + static_assert(sum<5, 5, 11>::value == 21, ""); + static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, ""); - typedef check check_type; - check_type c; - check_type&& cr = static_cast(c); + } - auto d = a; - auto l = [](){}; + // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae + // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function + // because of this. + namespace test_template_alias_sfinae + { - // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae - // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function because of this - namespace test_template_alias_sfinae { - struct foo {}; + struct foo {}; - template - using member = typename T::member_type; + template + using member = typename T::member_type; - template - void func(...) {} + template + void func(...) {} - template - void func(member*) {} + template + void func(member*) {} + + void test(); + + void test() { func(0); } + + } + +} // namespace cxx11 + +#endif // __cplusplus >= 201103L - void test(); - void test() { - func(0); - } - } _ACEOF if ac_fn_cxx_try_compile "$LINENO" @@ -4556,14 +4777,21 @@ else $as_nop eval $cachevar=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - CXXFLAGS="$ac_save_CXXFLAGS" + CXX="$ac_save_CXX" fi eval ac_res=\$$cachevar { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } - if eval test x\$$cachevar = xyes; then - CXXFLAGS="$CXXFLAGS $switch" - ac_success=yes + if eval test x\$$cachevar = xyes; then + CXX="$CXX $switch" + if test -n "$CXXCPP" ; then + CXXCPP="$CXXCPP $switch" + fi + ac_success=yes + break + fi + done + if test x$ac_success = xyes; then break fi done @@ -4578,21 +4806,19 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu if test x$ac_success = xno; then as_fn_error $? "*** A compiler with support for C++11 language features is required." "$LINENO" 5 fi - else - if test x$ac_success = xno; then - HAVE_CXX11=0 - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: No compiler with C++11 support was found" >&5 + fi + if test x$ac_success = xno; then + HAVE_CXX11=0 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: No compiler with C++11 support was found" >&5 printf "%s\n" "$as_me: No compiler with C++11 support was found" >&6;} - else - HAVE_CXX11=1 + else + HAVE_CXX11=1 printf "%s\n" "#define HAVE_CXX11 1" >>confdefs.h - fi - - fi + case `pwd` in *\ * | *\ *) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5 @@ -17051,6 +17277,141 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 +printf %s "checking how to run the C preprocessor... " >&6; } +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if test ${ac_cv_prog_CPP+y} +then : + printf %s "(cached) " >&6 +else $as_nop + # Double quotes because $CC needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" cpp /lib/cpp + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO" +then : + +else $as_nop + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO" +then : + # Broken: success on invalid input. +continue +else $as_nop + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok +then : + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 +printf "%s\n" "$CPP" >&6; } +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO" +then : + +else $as_nop + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO" +then : + # Broken: success on invalid input. +continue +else $as_nop + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok +then : + +else $as_nop + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details" "$LINENO" 5; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + ac_ext=c @@ -17062,19 +17423,28 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu ax_pthread_ok=no # We used to check for pthread.h first, but this fails if pthread.h -# requires special compiler flags (e.g. on True64 or Sequent). +# requires special compiler flags (e.g. on Tru64 or Sequent). # It gets checked for in the link test anyway. # First of all, check if the user has set any of the PTHREAD_LIBS, # etcetera environment variables, and if threads linking works using # them: -if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then - save_CFLAGS="$CFLAGS" +if test "x$PTHREAD_CFLAGS$PTHREAD_LIBS" != "x"; then + ax_pthread_save_CC="$CC" + ax_pthread_save_CFLAGS="$CFLAGS" + ax_pthread_save_LIBS="$LIBS" + if test "x$PTHREAD_CC" != "x" +then : + CC="$PTHREAD_CC" +fi + if test "x$PTHREAD_CXX" != "x" +then : + CXX="$PTHREAD_CXX" +fi CFLAGS="$CFLAGS $PTHREAD_CFLAGS" - save_LIBS="$LIBS" LIBS="$PTHREAD_LIBS $LIBS" - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS" >&5 -printf %s "checking for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS... " >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pthread_join using $CC $PTHREAD_CFLAGS $PTHREAD_LIBS" >&5 +printf %s "checking for pthread_join using $CC $PTHREAD_CFLAGS $PTHREAD_LIBS... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -17098,12 +17468,13 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_pthread_ok" >&5 printf "%s\n" "$ax_pthread_ok" >&6; } - if test x"$ax_pthread_ok" = xno; then + if test "x$ax_pthread_ok" = "xno"; then PTHREAD_LIBS="" PTHREAD_CFLAGS="" fi - LIBS="$save_LIBS" - CFLAGS="$save_CFLAGS" + CC="$ax_pthread_save_CC" + CFLAGS="$ax_pthread_save_CFLAGS" + LIBS="$ax_pthread_save_LIBS" fi # We must check for the threads library under a number of different @@ -17111,12 +17482,14 @@ fi # (e.g. DEC) have both -lpthread and -lpthreads, where one of the # libraries is broken (non-POSIX). -# Create a list of thread flags to try. Items starting with a "-" are -# C compiler flags, and other items are library names, except for "none" -# which indicates that we try without any flags at all, and "pthread-config" -# which is a program returning the flags for the Pth emulation library. +# Create a list of thread flags to try. Items with a "," contain both +# C compiler flags (before ",") and linker flags (after ","). Other items +# starting with a "-" are C compiler flags, and remaining items are +# library names, except for "none" which indicates that we try without +# any flags at all, and "pthread-config" which is a program returning +# the flags for the Pth emulation library. -ax_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" +ax_pthread_flags="pthreads none -Kthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" # The ordering *is* (sometimes) important. Some notes on the # individual items follow: @@ -17125,83 +17498,178 @@ ax_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mt # none: in case threads are in libc; should be tried before -Kthread and # other compiler flags to prevent continual compiler warnings # -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) -# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) -# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) -# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads) -# -pthreads: Solaris/gcc -# -mthreads: Mingw32/gcc, Lynx/gcc +# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads), Tru64 +# (Note: HP C rejects this with "bad form for `-t' option") +# -pthreads: Solaris/gcc (Note: HP C also rejects) # -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it -# doesn't hurt to check since this sometimes defines pthreads too; -# also defines -D_REENTRANT) -# ... -mt is also the pthreads flag for HP/aCC +# doesn't hurt to check since this sometimes defines pthreads and +# -D_REENTRANT too), HP C (must be checked before -lpthread, which +# is present but should not be used directly; and before -mthreads, +# because the compiler interprets this as "-mt" + "-hreads") +# -mthreads: Mingw32/gcc, Lynx/gcc # pthread: Linux, etcetera # --thread-safe: KAI C++ # pthread-config: use pthread-config program (for GNU Pth library) -case ${host_os} in +case $host_os in + + freebsd*) + + # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) + # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) + + ax_pthread_flags="-kthread lthread $ax_pthread_flags" + ;; + + hpux*) + + # From the cc(1) man page: "[-mt] Sets various -D flags to enable + # multi-threading and also sets -lpthread." + + ax_pthread_flags="-mt -pthread pthread $ax_pthread_flags" + ;; + + openedition*) + + # IBM z/OS requires a feature-test macro to be defined in order to + # enable POSIX threads at all, so give the user a hint if this is + # not set. (We don't define these ourselves, as they can affect + # other portions of the system API in unpredictable ways.) + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +# if !defined(_OPEN_THREADS) && !defined(_UNIX03_THREADS) + AX_PTHREAD_ZOS_MISSING +# endif + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "AX_PTHREAD_ZOS_MISSING" >/dev/null 2>&1 +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: IBM z/OS requires -D_OPEN_THREADS or -D_UNIX03_THREADS to enable pthreads support." >&5 +printf "%s\n" "$as_me: WARNING: IBM z/OS requires -D_OPEN_THREADS or -D_UNIX03_THREADS to enable pthreads support." >&2;} +fi +rm -rf conftest* + + ;; + solaris*) # On Solaris (at least, for some versions), libc contains stubbed # (non-functional) versions of the pthreads routines, so link-based - # tests will erroneously succeed. (We need to link with -pthreads/-mt/ - # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather - # a function called by this macro, so we could check for that, but - # who knows whether they'll stub that too in a future libc.) So, - # we'll just look for -pthreads and -lpthread first: - - ax_pthread_flags="-pthreads pthread -mt -pthread $ax_pthread_flags" - ;; + # tests will erroneously succeed. (N.B.: The stubs are missing + # pthread_cleanup_push, or rather a function called by this macro, + # so we could check for that, but who knows whether they'll stub + # that too in a future libc.) So we'll check first for the + # standard Solaris way of linking pthreads (-mt -lpthread). - darwin*) - ax_pthread_flags="-pthread $ax_pthread_flags" + ax_pthread_flags="-mt,-lpthread pthread $ax_pthread_flags" ;; esac -# Clang doesn't consider unrecognized options an error unless we specify -# -Werror. We throw in some extra Clang-specific options to ensure that -# this doesn't happen for GCC, which also accepts -Werror. +# Are we compiling with Clang? -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if compiler needs -Werror to reject unknown flags" >&5 -printf %s "checking if compiler needs -Werror to reject unknown flags... " >&6; } -save_CFLAGS="$CFLAGS" -ax_pthread_extra_flags="-Werror" -CFLAGS="$CFLAGS $ax_pthread_extra_flags -Wunknown-warning-option -Wsizeof-array-argument" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC is Clang" >&5 +printf %s "checking whether $CC is Clang... " >&6; } +if test ${ax_cv_PTHREAD_CLANG+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ax_cv_PTHREAD_CLANG=no + # Note that Autoconf sets GCC=yes for Clang as well as GCC + if test "x$GCC" = "xyes"; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -int foo(void); -int -main (void) -{ -foo() - ; - return 0; -} +/* Note: Clang 2.7 lacks __clang_[a-z]+__ */ +# if defined(__clang__) && defined(__llvm__) + AX_PTHREAD_CC_IS_CLANG +# endif + _ACEOF -if ac_fn_c_try_compile "$LINENO" +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "AX_PTHREAD_CC_IS_CLANG" >/dev/null 2>&1 then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf "%s\n" "yes" >&6; } + ax_cv_PTHREAD_CLANG=yes +fi +rm -rf conftest* + + fi + +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_PTHREAD_CLANG" >&5 +printf "%s\n" "$ax_cv_PTHREAD_CLANG" >&6; } +ax_pthread_clang="$ax_cv_PTHREAD_CLANG" + + +# GCC generally uses -pthread, or -pthreads on some platforms (e.g. SPARC) + +# Note that for GCC and Clang -pthread generally implies -lpthread, +# except when -nostdlib is passed. +# This is problematic using libtool to build C++ shared libraries with pthread: +# [1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=25460 +# [2] https://bugzilla.redhat.com/show_bug.cgi?id=661333 +# [3] https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=468555 +# To solve this, first try -pthread together with -lpthread for GCC + +if test "x$GCC" = "xyes" +then : + ax_pthread_flags="-pthread,-lpthread -pthread -pthreads $ax_pthread_flags" +fi + +# Clang takes -pthread (never supported any other flag), but we'll try with -lpthread first + +if test "x$ax_pthread_clang" = "xyes" +then : + ax_pthread_flags="-pthread,-lpthread -pthread" +fi + + +# The presence of a feature test macro requesting re-entrant function +# definitions is, on some systems, a strong hint that pthreads support is +# correctly enabled + +case $host_os in + darwin* | hpux* | linux* | osf* | solaris*) + ax_pthread_check_macro="_REENTRANT" + ;; + + aix*) + ax_pthread_check_macro="_THREAD_SAFE" + ;; + + *) + ax_pthread_check_macro="--" + ;; +esac +if test "x$ax_pthread_check_macro" = "x--" +then : + ax_pthread_check_cond=0 else $as_nop - ax_pthread_extra_flags= - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } + ax_pthread_check_cond="!defined($ax_pthread_check_macro)" fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -CFLAGS="$save_CFLAGS" -if test x"$ax_pthread_ok" = xno; then -for flag in $ax_pthread_flags; do - case $flag in +if test "x$ax_pthread_ok" = "xno"; then +for ax_pthread_try_flag in $ax_pthread_flags; do + + case $ax_pthread_try_flag in none) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether pthreads work without any flags" >&5 printf %s "checking whether pthreads work without any flags... " >&6; } ;; + *,*) + PTHREAD_CFLAGS=`echo $ax_pthread_try_flag | sed "s/^\(.*\),\(.*\)$/\1/"` + PTHREAD_LIBS=`echo $ax_pthread_try_flag | sed "s/^\(.*\),\(.*\)$/\2/"` + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether pthreads work with \"$PTHREAD_CFLAGS\" and \"$PTHREAD_LIBS\"" >&5 +printf %s "checking whether pthreads work with \"$PTHREAD_CFLAGS\" and \"$PTHREAD_LIBS\"... " >&6; } + ;; + -*) - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether pthreads work with $flag" >&5 -printf %s "checking whether pthreads work with $flag... " >&6; } - PTHREAD_CFLAGS="$flag" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether pthreads work with $ax_pthread_try_flag" >&5 +printf %s "checking whether pthreads work with $ax_pthread_try_flag... " >&6; } + PTHREAD_CFLAGS="$ax_pthread_try_flag" ;; pthread-config) @@ -17248,22 +17716,25 @@ printf "%s\n" "no" >&6; } fi - if test x"$ax_pthread_config" = xno; then continue; fi + if test "x$ax_pthread_config" = "xno" +then : + continue +fi PTHREAD_CFLAGS="`pthread-config --cflags`" PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" ;; *) - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for the pthreads library -l$flag" >&5 -printf %s "checking for the pthreads library -l$flag... " >&6; } - PTHREAD_LIBS="-l$flag" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for the pthreads library -l$ax_pthread_try_flag" >&5 +printf %s "checking for the pthreads library -l$ax_pthread_try_flag... " >&6; } + PTHREAD_LIBS="-l$ax_pthread_try_flag" ;; esac - save_LIBS="$LIBS" - save_CFLAGS="$CFLAGS" + ax_pthread_save_CFLAGS="$CFLAGS" + ax_pthread_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" LIBS="$PTHREAD_LIBS $LIBS" - CFLAGS="$CFLAGS $PTHREAD_CFLAGS $ax_pthread_extra_flags" # Check for various functions. We must include pthread.h, # since some functions may be macros. (On the Sequent, we @@ -17274,10 +17745,20 @@ printf %s "checking for the pthreads library -l$flag... " >&6; } # pthread_cleanup_push because it is one of the few pthread # functions on Solaris that doesn't have a non-functional libc stub. # We try pthread_create on general principles. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include - static void routine(void *a) { a = 0; } +# if $ax_pthread_check_cond +# error "$ax_pthread_check_macro must be defined" +# endif + static void *some_global = NULL; + static void routine(void *a) + { + /* To avoid any unused-parameter or + unused-but-set-parameter warning. */ + some_global = a; + } static void *start_routine(void *a) { return a; } int main (void) @@ -17299,78 +17780,195 @@ fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - LIBS="$save_LIBS" - CFLAGS="$save_CFLAGS" + CFLAGS="$ax_pthread_save_CFLAGS" + LIBS="$ax_pthread_save_LIBS" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_pthread_ok" >&5 printf "%s\n" "$ax_pthread_ok" >&6; } - if test "x$ax_pthread_ok" = xyes; then - break; - fi + if test "x$ax_pthread_ok" = "xyes" +then : + break +fi PTHREAD_LIBS="" PTHREAD_CFLAGS="" done fi + +# Clang needs special handling, because older versions handle the -pthread +# option in a rather... idiosyncratic way + +if test "x$ax_pthread_clang" = "xyes"; then + + # Clang takes -pthread; it has never supported any other flag + + # (Note 1: This will need to be revisited if a system that Clang + # supports has POSIX threads in a separate library. This tends not + # to be the way of modern systems, but it's conceivable.) + + # (Note 2: On some systems, notably Darwin, -pthread is not needed + # to get POSIX threads support; the API is always present and + # active. We could reasonably leave PTHREAD_CFLAGS empty. But + # -pthread does define _REENTRANT, and while the Darwin headers + # ignore this macro, third-party headers might not.) + + # However, older versions of Clang make a point of warning the user + # that, in an invocation where only linking and no compilation is + # taking place, the -pthread option has no effect ("argument unused + # during compilation"). They expect -pthread to be passed in only + # when source code is being compiled. + # + # Problem is, this is at odds with the way Automake and most other + # C build frameworks function, which is that the same flags used in + # compilation (CFLAGS) are also used in linking. Many systems + # supported by AX_PTHREAD require exactly this for POSIX threads + # support, and in fact it is often not straightforward to specify a + # flag that is used only in the compilation phase and not in + # linking. Such a scenario is extremely rare in practice. + # + # Even though use of the -pthread flag in linking would only print + # a warning, this can be a nuisance for well-run software projects + # that build with -Werror. So if the active version of Clang has + # this misfeature, we search for an option to squash it. + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether Clang needs flag to prevent \"argument unused\" warning when linking with -pthread" >&5 +printf %s "checking whether Clang needs flag to prevent \"argument unused\" warning when linking with -pthread... " >&6; } +if test ${ax_cv_PTHREAD_CLANG_NO_WARN_FLAG+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ax_cv_PTHREAD_CLANG_NO_WARN_FLAG=unknown + # Create an alternate version of $ac_link that compiles and + # links in two steps (.c -> .o, .o -> exe) instead of one + # (.c -> exe), because the warning occurs only in the second + # step + ax_pthread_save_ac_link="$ac_link" + ax_pthread_sed='s/conftest\.\$ac_ext/conftest.$ac_objext/g' + ax_pthread_link_step=`printf "%s\n" "$ac_link" | sed "$ax_pthread_sed"` + ax_pthread_2step_ac_link="($ac_compile) && (echo ==== >&5) && ($ax_pthread_link_step)" + ax_pthread_save_CFLAGS="$CFLAGS" + for ax_pthread_try in '' -Qunused-arguments -Wno-unused-command-line-argument unknown; do + if test "x$ax_pthread_try" = "xunknown" +then : + break +fi + CFLAGS="-Werror -Wunknown-warning-option $ax_pthread_try -pthread $ax_pthread_save_CFLAGS" + ac_link="$ax_pthread_save_ac_link" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int main(void){return 0;} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_link="$ax_pthread_2step_ac_link" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int main(void){return 0;} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + break +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext + done + ac_link="$ax_pthread_save_ac_link" + CFLAGS="$ax_pthread_save_CFLAGS" + if test "x$ax_pthread_try" = "x" +then : + ax_pthread_try=no +fi + ax_cv_PTHREAD_CLANG_NO_WARN_FLAG="$ax_pthread_try" + +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" >&5 +printf "%s\n" "$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" >&6; } + + case "$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" in + no | unknown) ;; + *) PTHREAD_CFLAGS="$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG $PTHREAD_CFLAGS" ;; + esac + +fi # $ax_pthread_clang = yes + + + # Various other checks: -if test "x$ax_pthread_ok" = xyes; then - save_LIBS="$LIBS" - LIBS="$PTHREAD_LIBS $LIBS" - save_CFLAGS="$CFLAGS" +if test "x$ax_pthread_ok" = "xyes"; then + ax_pthread_save_CFLAGS="$CFLAGS" + ax_pthread_save_LIBS="$LIBS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + LIBS="$PTHREAD_LIBS $LIBS" # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for joinable pthread attribute" >&5 printf %s "checking for joinable pthread attribute... " >&6; } - attr_name=unknown - for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +if test ${ax_cv_PTHREAD_JOINABLE_ATTR+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ax_cv_PTHREAD_JOINABLE_ATTR=unknown + for ax_pthread_attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { -int attr = $attr; return attr /* ; */ +int attr = $ax_pthread_attr; return attr /* ; */ ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : - attr_name=$attr; break + ax_cv_PTHREAD_JOINABLE_ATTR=$ax_pthread_attr; break fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - done - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $attr_name" >&5 -printf "%s\n" "$attr_name" >&6; } - if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then + done -printf "%s\n" "#define PTHREAD_CREATE_JOINABLE $attr_name" >>confdefs.h +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_PTHREAD_JOINABLE_ATTR" >&5 +printf "%s\n" "$ax_cv_PTHREAD_JOINABLE_ATTR" >&6; } + if test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xunknown" && \ + test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xPTHREAD_CREATE_JOINABLE" && \ + test "x$ax_pthread_joinable_attr_defined" != "xyes" +then : - fi +printf "%s\n" "#define PTHREAD_CREATE_JOINABLE $ax_cv_PTHREAD_JOINABLE_ATTR" >>confdefs.h - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if more special flags are required for pthreads" >&5 -printf %s "checking if more special flags are required for pthreads... " >&6; } - flag=no - case ${host_os} in - aix* | freebsd* | darwin*) flag="-D_THREAD_SAFE";; - osf* | hpux*) flag="-D_REENTRANT";; - solaris*) - if test "$GCC" = "yes"; then - flag="-D_REENTRANT" - else - # TODO: What about Clang on Solaris? - flag="-mt -D_REENTRANT" - fi - ;; - esac - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $flag" >&5 -printf "%s\n" "$flag" >&6; } - if test "x$flag" != xno; then - PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" - fi + ax_pthread_joinable_attr_defined=yes + +fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether more special flags are required for pthreads" >&5 +printf %s "checking whether more special flags are required for pthreads... " >&6; } +if test ${ax_cv_PTHREAD_SPECIAL_FLAGS+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ax_cv_PTHREAD_SPECIAL_FLAGS=no + case $host_os in + solaris*) + ax_cv_PTHREAD_SPECIAL_FLAGS="-D_POSIX_PTHREAD_SEMANTICS" + ;; + esac + +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_PTHREAD_SPECIAL_FLAGS" >&5 +printf "%s\n" "$ax_cv_PTHREAD_SPECIAL_FLAGS" >&6; } + if test "x$ax_cv_PTHREAD_SPECIAL_FLAGS" != "xno" && \ + test "x$ax_pthread_special_flags_added" != "xyes" +then : + PTHREAD_CFLAGS="$ax_cv_PTHREAD_SPECIAL_FLAGS $PTHREAD_CFLAGS" + ax_pthread_special_flags_added=yes +fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for PTHREAD_PRIO_INHERIT" >&5 printf %s "checking for PTHREAD_PRIO_INHERIT... " >&6; } @@ -17378,14 +17976,14 @@ if test ${ax_cv_PTHREAD_PRIO_INHERIT+y} then : printf %s "(cached) " >&6 else $as_nop - - cat confdefs.h - <<_ACEOF >conftest.$ac_ext + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { int i = PTHREAD_PRIO_INHERIT; + return i; ; return 0; } @@ -17402,31 +18000,44 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam \ fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ax_cv_PTHREAD_PRIO_INHERIT" >&5 printf "%s\n" "$ax_cv_PTHREAD_PRIO_INHERIT" >&6; } - if test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes" + if test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes" && \ + test "x$ax_pthread_prio_inherit_defined" != "xyes" then : printf "%s\n" "#define HAVE_PTHREAD_PRIO_INHERIT 1" >>confdefs.h + ax_pthread_prio_inherit_defined=yes + fi - LIBS="$save_LIBS" - CFLAGS="$save_CFLAGS" + CFLAGS="$ax_pthread_save_CFLAGS" + LIBS="$ax_pthread_save_LIBS" # More AIX lossage: compile with *_r variant - if test "x$GCC" != xyes; then + if test "x$GCC" != "xyes"; then case $host_os in aix*) case "x/$CC" in #( x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6) : #handle absolute path differently from PATH based program lookup - case "x$CC" in #( + case "x$CC" in #( x/*) : - if as_fn_executable_p ${CC}_r + + if as_fn_executable_p ${CC}_r then : PTHREAD_CC="${CC}_r" -fi ;; #( +fi + if test "x${CXX}" != "x" +then : + if as_fn_executable_p ${CXX}_r +then : + PTHREAD_CXX="${CXX}_r" +fi +fi + ;; #( *) : - for ac_prog in ${CC}_r + + for ac_prog in ${CC}_r do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 @@ -17473,8 +18084,62 @@ fi test -n "$PTHREAD_CC" && break done test -n "$PTHREAD_CC" || PTHREAD_CC="$CC" - ;; -esac ;; #( + + if test "x${CXX}" != "x" +then : + for ac_prog in ${CXX}_r +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_PTHREAD_CXX+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if test -n "$PTHREAD_CXX"; then + ac_cv_prog_PTHREAD_CXX="$PTHREAD_CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_PTHREAD_CXX="$ac_prog" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +PTHREAD_CXX=$ac_cv_prog_PTHREAD_CXX +if test -n "$PTHREAD_CXX"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PTHREAD_CXX" >&5 +printf "%s\n" "$PTHREAD_CXX" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + + test -n "$PTHREAD_CXX" && break +done +test -n "$PTHREAD_CXX" || PTHREAD_CXX="$CXX" + +fi + + ;; +esac + ;; #( *) : ;; esac @@ -17484,13 +18149,15 @@ esac fi test -n "$PTHREAD_CC" || PTHREAD_CC="$CC" +test -n "$PTHREAD_CXX" || PTHREAD_CXX="$CXX" + # Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: -if test x"$ax_pthread_ok" = xyes; then +if test "x$ax_pthread_ok" = "xyes"; then printf "%s\n" "#define HAVE_PTHREAD 1" >>confdefs.h diff --git a/lib/c-ares-1.19.0/test/configure.ac b/lib/c-ares-1.19.1/test/configure.ac similarity index 100% rename from lib/c-ares-1.19.0/test/configure.ac rename to lib/c-ares-1.19.1/test/configure.ac diff --git a/lib/c-ares-1.19.0/test/depcomp b/lib/c-ares-1.19.1/test/depcomp similarity index 100% rename from lib/c-ares-1.19.0/test/depcomp rename to lib/c-ares-1.19.1/test/depcomp diff --git a/lib/c-ares-1.19.0/test/dns-dump.cc b/lib/c-ares-1.19.1/test/dns-dump.cc similarity index 100% rename from lib/c-ares-1.19.0/test/dns-dump.cc rename to lib/c-ares-1.19.1/test/dns-dump.cc diff --git a/lib/c-ares-1.19.0/test/dns-proto-test.cc b/lib/c-ares-1.19.1/test/dns-proto-test.cc similarity index 100% rename from lib/c-ares-1.19.0/test/dns-proto-test.cc rename to lib/c-ares-1.19.1/test/dns-proto-test.cc diff --git a/lib/c-ares-1.19.0/test/dns-proto.cc b/lib/c-ares-1.19.1/test/dns-proto.cc similarity index 100% rename from lib/c-ares-1.19.0/test/dns-proto.cc rename to lib/c-ares-1.19.1/test/dns-proto.cc diff --git a/lib/c-ares-1.19.0/test/dns-proto.h b/lib/c-ares-1.19.1/test/dns-proto.h similarity index 100% rename from lib/c-ares-1.19.0/test/dns-proto.h rename to lib/c-ares-1.19.1/test/dns-proto.h diff --git a/lib/c-ares-1.19.0/test/fuzzcheck.sh b/lib/c-ares-1.19.1/test/fuzzcheck.sh similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzcheck.sh rename to lib/c-ares-1.19.1/test/fuzzcheck.sh diff --git a/lib/c-ares-1.19.0/test/fuzzinput/004a216d3cff18b0c5c6b68b807f1529 b/lib/c-ares-1.19.1/test/fuzzinput/004a216d3cff18b0c5c6b68b807f1529 similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/004a216d3cff18b0c5c6b68b807f1529 rename to lib/c-ares-1.19.1/test/fuzzinput/004a216d3cff18b0c5c6b68b807f1529 diff --git a/lib/c-ares-1.19.0/test/fuzzinput/00539467ca159b36aea95e61f9729115 b/lib/c-ares-1.19.1/test/fuzzinput/00539467ca159b36aea95e61f9729115 similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/00539467ca159b36aea95e61f9729115 rename to lib/c-ares-1.19.1/test/fuzzinput/00539467ca159b36aea95e61f9729115 diff --git a/lib/c-ares-1.19.0/test/fuzzinput/00e846db8f43f2f507cd1666ed5a753e b/lib/c-ares-1.19.1/test/fuzzinput/00e846db8f43f2f507cd1666ed5a753e similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/00e846db8f43f2f507cd1666ed5a753e rename to lib/c-ares-1.19.1/test/fuzzinput/00e846db8f43f2f507cd1666ed5a753e diff --git a/lib/c-ares-1.19.0/test/fuzzinput/0177b7566f08c013699eaea9a77abeb3 b/lib/c-ares-1.19.1/test/fuzzinput/0177b7566f08c013699eaea9a77abeb3 similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/0177b7566f08c013699eaea9a77abeb3 rename to lib/c-ares-1.19.1/test/fuzzinput/0177b7566f08c013699eaea9a77abeb3 diff --git a/lib/c-ares-1.19.0/test/fuzzinput/020a4fa317715bfdb236ed13751e6b65 b/lib/c-ares-1.19.1/test/fuzzinput/020a4fa317715bfdb236ed13751e6b65 similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/020a4fa317715bfdb236ed13751e6b65 rename to lib/c-ares-1.19.1/test/fuzzinput/020a4fa317715bfdb236ed13751e6b65 diff --git a/lib/c-ares-1.19.0/test/fuzzinput/0310f2e81bea31f4fe3f330872a877dd b/lib/c-ares-1.19.1/test/fuzzinput/0310f2e81bea31f4fe3f330872a877dd similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/0310f2e81bea31f4fe3f330872a877dd rename to lib/c-ares-1.19.1/test/fuzzinput/0310f2e81bea31f4fe3f330872a877dd diff --git a/lib/c-ares-1.19.0/test/fuzzinput/0449be67df1730b2d0887d412a9b7cc4 b/lib/c-ares-1.19.1/test/fuzzinput/0449be67df1730b2d0887d412a9b7cc4 similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/0449be67df1730b2d0887d412a9b7cc4 rename to lib/c-ares-1.19.1/test/fuzzinput/0449be67df1730b2d0887d412a9b7cc4 diff --git a/lib/c-ares-1.19.0/test/fuzzinput/0449dd14f7aa94bf0d716bfe09b287a8 b/lib/c-ares-1.19.1/test/fuzzinput/0449dd14f7aa94bf0d716bfe09b287a8 similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/0449dd14f7aa94bf0d716bfe09b287a8 rename to lib/c-ares-1.19.1/test/fuzzinput/0449dd14f7aa94bf0d716bfe09b287a8 diff --git a/lib/c-ares-1.19.0/test/fuzzinput/04c93cdf7208979aa4df80a3a0d5a2d8 b/lib/c-ares-1.19.1/test/fuzzinput/04c93cdf7208979aa4df80a3a0d5a2d8 similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/04c93cdf7208979aa4df80a3a0d5a2d8 rename to lib/c-ares-1.19.1/test/fuzzinput/04c93cdf7208979aa4df80a3a0d5a2d8 diff --git a/lib/c-ares-1.19.0/test/fuzzinput/0567e7171e08e75f3f91c4ca74c17adc b/lib/c-ares-1.19.1/test/fuzzinput/0567e7171e08e75f3f91c4ca74c17adc similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/0567e7171e08e75f3f91c4ca74c17adc rename to lib/c-ares-1.19.1/test/fuzzinput/0567e7171e08e75f3f91c4ca74c17adc diff --git a/lib/c-ares-1.19.0/test/fuzzinput/05ba948578a397e9cbc6a7b3e78622fa b/lib/c-ares-1.19.1/test/fuzzinput/05ba948578a397e9cbc6a7b3e78622fa similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/05ba948578a397e9cbc6a7b3e78622fa rename to lib/c-ares-1.19.1/test/fuzzinput/05ba948578a397e9cbc6a7b3e78622fa diff --git a/lib/c-ares-1.19.0/test/fuzzinput/060afe5ed25f3e2e86167e545f27edca b/lib/c-ares-1.19.1/test/fuzzinput/060afe5ed25f3e2e86167e545f27edca similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/060afe5ed25f3e2e86167e545f27edca rename to lib/c-ares-1.19.1/test/fuzzinput/060afe5ed25f3e2e86167e545f27edca diff --git a/lib/c-ares-1.19.0/test/fuzzinput/06d47d3681493f1b1d41236f460d896f b/lib/c-ares-1.19.1/test/fuzzinput/06d47d3681493f1b1d41236f460d896f similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/06d47d3681493f1b1d41236f460d896f rename to lib/c-ares-1.19.1/test/fuzzinput/06d47d3681493f1b1d41236f460d896f diff --git a/lib/c-ares-1.19.0/test/fuzzinput/0724a810b0e131c2fddb6de9003b9064 b/lib/c-ares-1.19.1/test/fuzzinput/0724a810b0e131c2fddb6de9003b9064 similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/0724a810b0e131c2fddb6de9003b9064 rename to lib/c-ares-1.19.1/test/fuzzinput/0724a810b0e131c2fddb6de9003b9064 diff --git a/lib/c-ares-1.19.0/test/fuzzinput/0b5279148826f5b962bcf1896bdb4ede b/lib/c-ares-1.19.1/test/fuzzinput/0b5279148826f5b962bcf1896bdb4ede similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/0b5279148826f5b962bcf1896bdb4ede rename to lib/c-ares-1.19.1/test/fuzzinput/0b5279148826f5b962bcf1896bdb4ede diff --git a/lib/c-ares-1.19.0/test/fuzzinput/114048c0f6b10bdc67ce9166405d195e b/lib/c-ares-1.19.1/test/fuzzinput/114048c0f6b10bdc67ce9166405d195e similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/114048c0f6b10bdc67ce9166405d195e rename to lib/c-ares-1.19.1/test/fuzzinput/114048c0f6b10bdc67ce9166405d195e diff --git a/lib/c-ares-1.19.0/test/fuzzinput/11b8464a0ef8735d202955c34c36b0c7 b/lib/c-ares-1.19.1/test/fuzzinput/11b8464a0ef8735d202955c34c36b0c7 similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/11b8464a0ef8735d202955c34c36b0c7 rename to lib/c-ares-1.19.1/test/fuzzinput/11b8464a0ef8735d202955c34c36b0c7 diff --git a/lib/c-ares-1.19.0/test/fuzzinput/11cb626f1668c7b41954ce7d768fe528 b/lib/c-ares-1.19.1/test/fuzzinput/11cb626f1668c7b41954ce7d768fe528 similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/11cb626f1668c7b41954ce7d768fe528 rename to lib/c-ares-1.19.1/test/fuzzinput/11cb626f1668c7b41954ce7d768fe528 diff --git a/lib/c-ares-1.19.0/test/fuzzinput/14b133bf18125b75a1976fa63a1df6b7 b/lib/c-ares-1.19.1/test/fuzzinput/14b133bf18125b75a1976fa63a1df6b7 similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/14b133bf18125b75a1976fa63a1df6b7 rename to lib/c-ares-1.19.1/test/fuzzinput/14b133bf18125b75a1976fa63a1df6b7 diff --git a/lib/c-ares-1.19.0/test/fuzzinput/153c6b3afa8faa03c8bc28f936a6d4cf b/lib/c-ares-1.19.1/test/fuzzinput/153c6b3afa8faa03c8bc28f936a6d4cf similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/153c6b3afa8faa03c8bc28f936a6d4cf rename to lib/c-ares-1.19.1/test/fuzzinput/153c6b3afa8faa03c8bc28f936a6d4cf diff --git a/lib/c-ares-1.19.0/test/fuzzinput/182cad2a342ed7317b7c21a5d17020d1 b/lib/c-ares-1.19.1/test/fuzzinput/182cad2a342ed7317b7c21a5d17020d1 similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/182cad2a342ed7317b7c21a5d17020d1 rename to lib/c-ares-1.19.1/test/fuzzinput/182cad2a342ed7317b7c21a5d17020d1 diff --git a/lib/c-ares-1.19.0/test/fuzzinput/1c61a61bb7057b52c5b15188345a5238 b/lib/c-ares-1.19.1/test/fuzzinput/1c61a61bb7057b52c5b15188345a5238 similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/1c61a61bb7057b52c5b15188345a5238 rename to lib/c-ares-1.19.1/test/fuzzinput/1c61a61bb7057b52c5b15188345a5238 diff --git a/lib/c-ares-1.19.0/test/fuzzinput/1dbe2cf62ed2e4fa1c3cb473f08710b5 b/lib/c-ares-1.19.1/test/fuzzinput/1dbe2cf62ed2e4fa1c3cb473f08710b5 similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/1dbe2cf62ed2e4fa1c3cb473f08710b5 rename to lib/c-ares-1.19.1/test/fuzzinput/1dbe2cf62ed2e4fa1c3cb473f08710b5 diff --git a/lib/c-ares-1.19.0/test/fuzzinput/21199be504fcfece5c7096ee0dbba507 b/lib/c-ares-1.19.1/test/fuzzinput/21199be504fcfece5c7096ee0dbba507 similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/21199be504fcfece5c7096ee0dbba507 rename to lib/c-ares-1.19.1/test/fuzzinput/21199be504fcfece5c7096ee0dbba507 diff --git a/lib/c-ares-1.19.0/test/fuzzinput/21891480074b5635dbbe7137bdcabccd b/lib/c-ares-1.19.1/test/fuzzinput/21891480074b5635dbbe7137bdcabccd similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/21891480074b5635dbbe7137bdcabccd rename to lib/c-ares-1.19.1/test/fuzzinput/21891480074b5635dbbe7137bdcabccd diff --git a/lib/c-ares-1.19.0/test/fuzzinput/233aea42e15aa73e131eefabf16088c9 b/lib/c-ares-1.19.1/test/fuzzinput/233aea42e15aa73e131eefabf16088c9 similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/233aea42e15aa73e131eefabf16088c9 rename to lib/c-ares-1.19.1/test/fuzzinput/233aea42e15aa73e131eefabf16088c9 diff --git a/lib/c-ares-1.19.0/test/fuzzinput/24660d4e7ac7aa21d600ea7a3d198bbb b/lib/c-ares-1.19.1/test/fuzzinput/24660d4e7ac7aa21d600ea7a3d198bbb similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/24660d4e7ac7aa21d600ea7a3d198bbb rename to lib/c-ares-1.19.1/test/fuzzinput/24660d4e7ac7aa21d600ea7a3d198bbb diff --git a/lib/c-ares-1.19.0/test/fuzzinput/25589deb55c08429345f289d1c9b0254 b/lib/c-ares-1.19.1/test/fuzzinput/25589deb55c08429345f289d1c9b0254 similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/25589deb55c08429345f289d1c9b0254 rename to lib/c-ares-1.19.1/test/fuzzinput/25589deb55c08429345f289d1c9b0254 diff --git a/lib/c-ares-1.19.0/test/fuzzinput/2573bd823e4da11f727a17f8e1f35c26 b/lib/c-ares-1.19.1/test/fuzzinput/2573bd823e4da11f727a17f8e1f35c26 similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/2573bd823e4da11f727a17f8e1f35c26 rename to lib/c-ares-1.19.1/test/fuzzinput/2573bd823e4da11f727a17f8e1f35c26 diff --git a/lib/c-ares-1.19.0/test/fuzzinput/276f12da56866273e76059ad0e7be97e b/lib/c-ares-1.19.1/test/fuzzinput/276f12da56866273e76059ad0e7be97e similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/276f12da56866273e76059ad0e7be97e rename to lib/c-ares-1.19.1/test/fuzzinput/276f12da56866273e76059ad0e7be97e diff --git a/lib/c-ares-1.19.0/test/fuzzinput/29198a2e380cb19babec9e02116d213e b/lib/c-ares-1.19.1/test/fuzzinput/29198a2e380cb19babec9e02116d213e similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/29198a2e380cb19babec9e02116d213e rename to lib/c-ares-1.19.1/test/fuzzinput/29198a2e380cb19babec9e02116d213e diff --git a/lib/c-ares-1.19.0/test/fuzzinput/2c94ba9434b1a1b9396fc5364f101363 b/lib/c-ares-1.19.1/test/fuzzinput/2c94ba9434b1a1b9396fc5364f101363 similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/2c94ba9434b1a1b9396fc5364f101363 rename to lib/c-ares-1.19.1/test/fuzzinput/2c94ba9434b1a1b9396fc5364f101363 diff --git a/lib/c-ares-1.19.0/test/fuzzinput/2d578c357dc2f5e02dc55cddb30641d1 b/lib/c-ares-1.19.1/test/fuzzinput/2d578c357dc2f5e02dc55cddb30641d1 similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/2d578c357dc2f5e02dc55cddb30641d1 rename to lib/c-ares-1.19.1/test/fuzzinput/2d578c357dc2f5e02dc55cddb30641d1 diff --git a/lib/c-ares-1.19.0/test/fuzzinput/2dff6cc5a223e67fde9e5e79af456992 b/lib/c-ares-1.19.1/test/fuzzinput/2dff6cc5a223e67fde9e5e79af456992 similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/2dff6cc5a223e67fde9e5e79af456992 rename to lib/c-ares-1.19.1/test/fuzzinput/2dff6cc5a223e67fde9e5e79af456992 diff --git a/lib/c-ares-1.19.0/test/fuzzinput/2f103b1f9477f2d8934bd84328d51c75 b/lib/c-ares-1.19.1/test/fuzzinput/2f103b1f9477f2d8934bd84328d51c75 similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/2f103b1f9477f2d8934bd84328d51c75 rename to lib/c-ares-1.19.1/test/fuzzinput/2f103b1f9477f2d8934bd84328d51c75 diff --git a/lib/c-ares-1.19.0/test/fuzzinput/31cd3a8413de13d9624adbb1613784bf b/lib/c-ares-1.19.1/test/fuzzinput/31cd3a8413de13d9624adbb1613784bf similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/31cd3a8413de13d9624adbb1613784bf rename to lib/c-ares-1.19.1/test/fuzzinput/31cd3a8413de13d9624adbb1613784bf diff --git a/lib/c-ares-1.19.0/test/fuzzinput/36415bdf1d180098fe6234b4186e69f3 b/lib/c-ares-1.19.1/test/fuzzinput/36415bdf1d180098fe6234b4186e69f3 similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/36415bdf1d180098fe6234b4186e69f3 rename to lib/c-ares-1.19.1/test/fuzzinput/36415bdf1d180098fe6234b4186e69f3 diff --git a/lib/c-ares-1.19.0/test/fuzzinput/3a04a80f0242e8dff0cd732e7c4767da b/lib/c-ares-1.19.1/test/fuzzinput/3a04a80f0242e8dff0cd732e7c4767da similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/3a04a80f0242e8dff0cd732e7c4767da rename to lib/c-ares-1.19.1/test/fuzzinput/3a04a80f0242e8dff0cd732e7c4767da diff --git a/lib/c-ares-1.19.0/test/fuzzinput/44d0f973b7b0fb3e4a07770c943dcd5a b/lib/c-ares-1.19.1/test/fuzzinput/44d0f973b7b0fb3e4a07770c943dcd5a similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/44d0f973b7b0fb3e4a07770c943dcd5a rename to lib/c-ares-1.19.1/test/fuzzinput/44d0f973b7b0fb3e4a07770c943dcd5a diff --git a/lib/c-ares-1.19.0/test/fuzzinput/50bc00daa0ddcd6cfb2b5d9f62c81f47 b/lib/c-ares-1.19.1/test/fuzzinput/50bc00daa0ddcd6cfb2b5d9f62c81f47 similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/50bc00daa0ddcd6cfb2b5d9f62c81f47 rename to lib/c-ares-1.19.1/test/fuzzinput/50bc00daa0ddcd6cfb2b5d9f62c81f47 diff --git a/lib/c-ares-1.19.0/test/fuzzinput/51ed2d1fb77b3078b54e94e85606b7df b/lib/c-ares-1.19.1/test/fuzzinput/51ed2d1fb77b3078b54e94e85606b7df similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/51ed2d1fb77b3078b54e94e85606b7df rename to lib/c-ares-1.19.1/test/fuzzinput/51ed2d1fb77b3078b54e94e85606b7df diff --git a/lib/c-ares-1.19.0/test/fuzzinput/5c5e0e899cf2e7d053a9e45fb76f6e5a b/lib/c-ares-1.19.1/test/fuzzinput/5c5e0e899cf2e7d053a9e45fb76f6e5a similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/5c5e0e899cf2e7d053a9e45fb76f6e5a rename to lib/c-ares-1.19.1/test/fuzzinput/5c5e0e899cf2e7d053a9e45fb76f6e5a diff --git a/lib/c-ares-1.19.0/test/fuzzinput/70152ed033f139443fbfb1b858bb3b1b b/lib/c-ares-1.19.1/test/fuzzinput/70152ed033f139443fbfb1b858bb3b1b similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/70152ed033f139443fbfb1b858bb3b1b rename to lib/c-ares-1.19.1/test/fuzzinput/70152ed033f139443fbfb1b858bb3b1b diff --git a/lib/c-ares-1.19.0/test/fuzzinput/7030ca2b24e5a7f9dd8f62096a48eb33 b/lib/c-ares-1.19.1/test/fuzzinput/7030ca2b24e5a7f9dd8f62096a48eb33 similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/7030ca2b24e5a7f9dd8f62096a48eb33 rename to lib/c-ares-1.19.1/test/fuzzinput/7030ca2b24e5a7f9dd8f62096a48eb33 diff --git a/lib/c-ares-1.19.0/test/fuzzinput/71eec1a0ef2d25bb9e2ef17f23be7e9e b/lib/c-ares-1.19.1/test/fuzzinput/71eec1a0ef2d25bb9e2ef17f23be7e9e similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/71eec1a0ef2d25bb9e2ef17f23be7e9e rename to lib/c-ares-1.19.1/test/fuzzinput/71eec1a0ef2d25bb9e2ef17f23be7e9e diff --git a/lib/c-ares-1.19.0/test/fuzzinput/7a6b0177210ea4ef40b254daf99393c5 b/lib/c-ares-1.19.1/test/fuzzinput/7a6b0177210ea4ef40b254daf99393c5 similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/7a6b0177210ea4ef40b254daf99393c5 rename to lib/c-ares-1.19.1/test/fuzzinput/7a6b0177210ea4ef40b254daf99393c5 diff --git a/lib/c-ares-1.19.0/test/fuzzinput/7f1567733711ffb61839621af0cbfa33 b/lib/c-ares-1.19.1/test/fuzzinput/7f1567733711ffb61839621af0cbfa33 similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/7f1567733711ffb61839621af0cbfa33 rename to lib/c-ares-1.19.1/test/fuzzinput/7f1567733711ffb61839621af0cbfa33 diff --git a/lib/c-ares-1.19.0/test/fuzzinput/850c6d57c5bb7be8205fc2438d14d7e5 b/lib/c-ares-1.19.1/test/fuzzinput/850c6d57c5bb7be8205fc2438d14d7e5 similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/850c6d57c5bb7be8205fc2438d14d7e5 rename to lib/c-ares-1.19.1/test/fuzzinput/850c6d57c5bb7be8205fc2438d14d7e5 diff --git a/lib/c-ares-1.19.0/test/fuzzinput/a5c8cd2784a5792b9e91c2d7895b3b34 b/lib/c-ares-1.19.1/test/fuzzinput/a5c8cd2784a5792b9e91c2d7895b3b34 similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/a5c8cd2784a5792b9e91c2d7895b3b34 rename to lib/c-ares-1.19.1/test/fuzzinput/a5c8cd2784a5792b9e91c2d7895b3b34 diff --git a/lib/c-ares-1.19.0/test/fuzzinput/a9135cdc7151d023300ff194bad90af9 b/lib/c-ares-1.19.1/test/fuzzinput/a9135cdc7151d023300ff194bad90af9 similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/a9135cdc7151d023300ff194bad90af9 rename to lib/c-ares-1.19.1/test/fuzzinput/a9135cdc7151d023300ff194bad90af9 diff --git a/lib/c-ares-1.19.0/test/fuzzinput/af2597e8ac7dec1e8b4a47518312912a b/lib/c-ares-1.19.1/test/fuzzinput/af2597e8ac7dec1e8b4a47518312912a similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/af2597e8ac7dec1e8b4a47518312912a rename to lib/c-ares-1.19.1/test/fuzzinput/af2597e8ac7dec1e8b4a47518312912a diff --git a/lib/c-ares-1.19.0/test/fuzzinput/answer_a b/lib/c-ares-1.19.1/test/fuzzinput/answer_a similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/answer_a rename to lib/c-ares-1.19.1/test/fuzzinput/answer_a diff --git a/lib/c-ares-1.19.0/test/fuzzinput/answer_aaaa b/lib/c-ares-1.19.1/test/fuzzinput/answer_aaaa similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/answer_aaaa rename to lib/c-ares-1.19.1/test/fuzzinput/answer_aaaa diff --git a/lib/c-ares-1.19.0/test/fuzzinput/b3f53ef826b831bb09dd25c7f5960249 b/lib/c-ares-1.19.1/test/fuzzinput/b3f53ef826b831bb09dd25c7f5960249 similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/b3f53ef826b831bb09dd25c7f5960249 rename to lib/c-ares-1.19.1/test/fuzzinput/b3f53ef826b831bb09dd25c7f5960249 diff --git a/lib/c-ares-1.19.0/test/fuzzinput/cda0f8751f5c4993974c2b549d29bcc8 b/lib/c-ares-1.19.1/test/fuzzinput/cda0f8751f5c4993974c2b549d29bcc8 similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/cda0f8751f5c4993974c2b549d29bcc8 rename to lib/c-ares-1.19.1/test/fuzzinput/cda0f8751f5c4993974c2b549d29bcc8 diff --git a/lib/c-ares-1.19.0/test/fuzzinput/ce6c26c0e469339873d0e7f616ab0945 b/lib/c-ares-1.19.1/test/fuzzinput/ce6c26c0e469339873d0e7f616ab0945 similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/ce6c26c0e469339873d0e7f616ab0945 rename to lib/c-ares-1.19.1/test/fuzzinput/ce6c26c0e469339873d0e7f616ab0945 diff --git a/lib/c-ares-1.19.0/test/fuzzinput/clusterfuzz-5637790584012800 b/lib/c-ares-1.19.1/test/fuzzinput/clusterfuzz-5637790584012800 similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/clusterfuzz-5637790584012800 rename to lib/c-ares-1.19.1/test/fuzzinput/clusterfuzz-5637790584012800 diff --git a/lib/c-ares-1.19.0/test/fuzzinput/clusterfuzz-5650695891451904 b/lib/c-ares-1.19.1/test/fuzzinput/clusterfuzz-5650695891451904 similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/clusterfuzz-5650695891451904 rename to lib/c-ares-1.19.1/test/fuzzinput/clusterfuzz-5650695891451904 diff --git a/lib/c-ares-1.19.0/test/fuzzinput/clusterfuzz-5651369832218624 b/lib/c-ares-1.19.1/test/fuzzinput/clusterfuzz-5651369832218624 similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/clusterfuzz-5651369832218624 rename to lib/c-ares-1.19.1/test/fuzzinput/clusterfuzz-5651369832218624 diff --git a/lib/c-ares-1.19.0/test/fuzzinput/clusterfuzz-5674462260756480 b/lib/c-ares-1.19.1/test/fuzzinput/clusterfuzz-5674462260756480 similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/clusterfuzz-5674462260756480 rename to lib/c-ares-1.19.1/test/fuzzinput/clusterfuzz-5674462260756480 diff --git a/lib/c-ares-1.19.0/test/fuzzinput/clusterfuzz-5680630672654336 b/lib/c-ares-1.19.1/test/fuzzinput/clusterfuzz-5680630672654336 similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/clusterfuzz-5680630672654336 rename to lib/c-ares-1.19.1/test/fuzzinput/clusterfuzz-5680630672654336 diff --git a/lib/c-ares-1.19.0/test/fuzzinput/clusterfuzz-5683497160671232 b/lib/c-ares-1.19.1/test/fuzzinput/clusterfuzz-5683497160671232 similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/clusterfuzz-5683497160671232 rename to lib/c-ares-1.19.1/test/fuzzinput/clusterfuzz-5683497160671232 diff --git a/lib/c-ares-1.19.0/test/fuzzinput/clusterfuzz-5687310655422464 b/lib/c-ares-1.19.1/test/fuzzinput/clusterfuzz-5687310655422464 similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/clusterfuzz-5687310655422464 rename to lib/c-ares-1.19.1/test/fuzzinput/clusterfuzz-5687310655422464 diff --git a/lib/c-ares-1.19.0/test/fuzzinput/clusterfuzz-5695341573177344 b/lib/c-ares-1.19.1/test/fuzzinput/clusterfuzz-5695341573177344 similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/clusterfuzz-5695341573177344 rename to lib/c-ares-1.19.1/test/fuzzinput/clusterfuzz-5695341573177344 diff --git a/lib/c-ares-1.19.0/test/fuzzinput/clusterfuzz-5697835103682560 b/lib/c-ares-1.19.1/test/fuzzinput/clusterfuzz-5697835103682560 similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/clusterfuzz-5697835103682560 rename to lib/c-ares-1.19.1/test/fuzzinput/clusterfuzz-5697835103682560 diff --git a/lib/c-ares-1.19.0/test/fuzzinput/clusterfuzz-5728518081609728 b/lib/c-ares-1.19.1/test/fuzzinput/clusterfuzz-5728518081609728 similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/clusterfuzz-5728518081609728 rename to lib/c-ares-1.19.1/test/fuzzinput/clusterfuzz-5728518081609728 diff --git a/lib/c-ares-1.19.0/test/fuzzinput/clusterfuzz-5732960017317888 b/lib/c-ares-1.19.1/test/fuzzinput/clusterfuzz-5732960017317888 similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/clusterfuzz-5732960017317888 rename to lib/c-ares-1.19.1/test/fuzzinput/clusterfuzz-5732960017317888 diff --git a/lib/c-ares-1.19.0/test/fuzzinput/e4dd7e7c2dd4ed7c2e17a6af5d04f9c9 b/lib/c-ares-1.19.1/test/fuzzinput/e4dd7e7c2dd4ed7c2e17a6af5d04f9c9 similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/e4dd7e7c2dd4ed7c2e17a6af5d04f9c9 rename to lib/c-ares-1.19.1/test/fuzzinput/e4dd7e7c2dd4ed7c2e17a6af5d04f9c9 diff --git a/lib/c-ares-1.19.0/test/fuzzinput/ed50ed8ee36230a5a69746ad830437e5 b/lib/c-ares-1.19.1/test/fuzzinput/ed50ed8ee36230a5a69746ad830437e5 similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/ed50ed8ee36230a5a69746ad830437e5 rename to lib/c-ares-1.19.1/test/fuzzinput/ed50ed8ee36230a5a69746ad830437e5 diff --git a/lib/c-ares-1.19.0/test/fuzzinput/f1b900d50806021953321c3b604ee497 b/lib/c-ares-1.19.1/test/fuzzinput/f1b900d50806021953321c3b604ee497 similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/f1b900d50806021953321c3b604ee497 rename to lib/c-ares-1.19.1/test/fuzzinput/f1b900d50806021953321c3b604ee497 diff --git a/lib/c-ares-1.19.0/test/fuzzinput/f6606f624be8c628328cea01d2cd07a9 b/lib/c-ares-1.19.1/test/fuzzinput/f6606f624be8c628328cea01d2cd07a9 similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/f6606f624be8c628328cea01d2cd07a9 rename to lib/c-ares-1.19.1/test/fuzzinput/f6606f624be8c628328cea01d2cd07a9 diff --git a/lib/c-ares-1.19.0/test/fuzzinput/f89f6c8176b564a7dd646f14305573ce b/lib/c-ares-1.19.1/test/fuzzinput/f89f6c8176b564a7dd646f14305573ce similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/f89f6c8176b564a7dd646f14305573ce rename to lib/c-ares-1.19.1/test/fuzzinput/f89f6c8176b564a7dd646f14305573ce diff --git a/lib/c-ares-1.19.0/test/fuzzinput/f9ad508d2dbd08d3aaaabc7d1174677d b/lib/c-ares-1.19.1/test/fuzzinput/f9ad508d2dbd08d3aaaabc7d1174677d similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/f9ad508d2dbd08d3aaaabc7d1174677d rename to lib/c-ares-1.19.1/test/fuzzinput/f9ad508d2dbd08d3aaaabc7d1174677d diff --git a/lib/c-ares-1.19.0/test/fuzzinput/multi-indir b/lib/c-ares-1.19.1/test/fuzzinput/multi-indir similarity index 100% rename from lib/c-ares-1.19.0/test/fuzzinput/multi-indir rename to lib/c-ares-1.19.1/test/fuzzinput/multi-indir diff --git a/lib/c-ares-1.19.0/test/fuzznames/name01 b/lib/c-ares-1.19.1/test/fuzznames/name01 similarity index 100% rename from lib/c-ares-1.19.0/test/fuzznames/name01 rename to lib/c-ares-1.19.1/test/fuzznames/name01 diff --git a/lib/c-ares-1.19.0/test/fuzznames/name02 b/lib/c-ares-1.19.1/test/fuzznames/name02 similarity index 100% rename from lib/c-ares-1.19.0/test/fuzznames/name02 rename to lib/c-ares-1.19.1/test/fuzznames/name02 diff --git a/lib/c-ares-1.19.0/test/fuzznames/name03 b/lib/c-ares-1.19.1/test/fuzznames/name03 similarity index 100% rename from lib/c-ares-1.19.0/test/fuzznames/name03 rename to lib/c-ares-1.19.1/test/fuzznames/name03 diff --git a/lib/c-ares-1.19.0/test/fuzznames/name04 b/lib/c-ares-1.19.1/test/fuzznames/name04 similarity index 100% rename from lib/c-ares-1.19.0/test/fuzznames/name04 rename to lib/c-ares-1.19.1/test/fuzznames/name04 diff --git a/lib/c-ares-1.19.0/test/fuzznames/name05 b/lib/c-ares-1.19.1/test/fuzznames/name05 similarity index 100% rename from lib/c-ares-1.19.0/test/fuzznames/name05 rename to lib/c-ares-1.19.1/test/fuzznames/name05 diff --git a/lib/c-ares-1.19.0/test/fuzznames/name06 b/lib/c-ares-1.19.1/test/fuzznames/name06 similarity index 100% rename from lib/c-ares-1.19.0/test/fuzznames/name06 rename to lib/c-ares-1.19.1/test/fuzznames/name06 diff --git a/lib/c-ares-1.19.0/test/fuzznames/name07 b/lib/c-ares-1.19.1/test/fuzznames/name07 similarity index 100% rename from lib/c-ares-1.19.0/test/fuzznames/name07 rename to lib/c-ares-1.19.1/test/fuzznames/name07 diff --git a/lib/c-ares-1.19.0/test/fuzznames/name08 b/lib/c-ares-1.19.1/test/fuzznames/name08 similarity index 100% rename from lib/c-ares-1.19.0/test/fuzznames/name08 rename to lib/c-ares-1.19.1/test/fuzznames/name08 diff --git a/lib/c-ares-1.19.0/test/fuzznames/name09 b/lib/c-ares-1.19.1/test/fuzznames/name09 similarity index 100% rename from lib/c-ares-1.19.0/test/fuzznames/name09 rename to lib/c-ares-1.19.1/test/fuzznames/name09 diff --git a/lib/c-ares-1.19.0/test/gmock-1.11.0/gmock-gtest-all.cc b/lib/c-ares-1.19.1/test/gmock-1.11.0/gmock-gtest-all.cc similarity index 100% rename from lib/c-ares-1.19.0/test/gmock-1.11.0/gmock-gtest-all.cc rename to lib/c-ares-1.19.1/test/gmock-1.11.0/gmock-gtest-all.cc diff --git a/lib/c-ares-1.19.0/test/gmock-1.11.0/gmock/gmock.h b/lib/c-ares-1.19.1/test/gmock-1.11.0/gmock/gmock.h similarity index 100% rename from lib/c-ares-1.19.0/test/gmock-1.11.0/gmock/gmock.h rename to lib/c-ares-1.19.1/test/gmock-1.11.0/gmock/gmock.h diff --git a/lib/c-ares-1.19.0/test/gmock-1.11.0/gtest/gtest.h b/lib/c-ares-1.19.1/test/gmock-1.11.0/gtest/gtest.h similarity index 100% rename from lib/c-ares-1.19.0/test/gmock-1.11.0/gtest/gtest.h rename to lib/c-ares-1.19.1/test/gmock-1.11.0/gtest/gtest.h diff --git a/lib/c-ares-1.19.0/test/install-sh b/lib/c-ares-1.19.1/test/install-sh similarity index 100% rename from lib/c-ares-1.19.0/test/install-sh rename to lib/c-ares-1.19.1/test/install-sh diff --git a/lib/c-ares-1.19.0/test/ltmain.sh b/lib/c-ares-1.19.1/test/ltmain.sh similarity index 100% rename from lib/c-ares-1.19.0/test/ltmain.sh rename to lib/c-ares-1.19.1/test/ltmain.sh diff --git a/lib/c-ares-1.19.0/test/missing b/lib/c-ares-1.19.1/test/missing similarity index 100% rename from lib/c-ares-1.19.0/test/missing rename to lib/c-ares-1.19.1/test/missing diff --git a/lib/c-ares-1.19.0/test/test-driver b/lib/c-ares-1.19.1/test/test-driver similarity index 100% rename from lib/c-ares-1.19.0/test/test-driver rename to lib/c-ares-1.19.1/test/test-driver From b7954b8d643b1ea56e69466199ba7c968cdb6892 Mon Sep 17 00:00:00 2001 From: Hiroshi Hatake Date: Mon, 31 Jul 2023 15:54:37 +0900 Subject: [PATCH 177/315] core: Expand pthread stack size on macOS This is because the default size of pthread stack is 12K which size is half of the Linux one. Signed-off-by: Hiroshi Hatake --- include/fluent-bit/flb_coro.h | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/include/fluent-bit/flb_coro.h b/include/fluent-bit/flb_coro.h index 5381aab7cc3..8e14137b722 100644 --- a/include/fluent-bit/flb_coro.h +++ b/include/fluent-bit/flb_coro.h @@ -61,10 +61,20 @@ struct flb_coro { void *data; }; +#ifdef FLB_SYSTEM_MACOS +#ifdef __aarch64__ +#define STACK_FACTOR 1.5 /* Use 36KiB for coro stacks */ +#else +#define STACK_FACTOR 2 /* Use 24KiB for coro stacks */ +#endif +#else +#define STACK_FACTOR 1 +#endif + #ifdef FLB_CORO_STACK_SIZE #define FLB_CORO_STACK_SIZE_BYTE FLB_CORO_STACK_SIZE #else -#define FLB_CORO_STACK_SIZE_BYTE ((3 * PTHREAD_STACK_MIN) / 2) +#define FLB_CORO_STACK_SIZE_BYTE ((3 * STACK_FACTOR * PTHREAD_STACK_MIN) / 2) #endif #define FLB_CORO_DATA(coro) (((char *) coro) + sizeof(struct flb_coro)) From bc04aabf26a75d1e4ef0c9d6fa04187650f2977e Mon Sep 17 00:00:00 2001 From: Hiroshi Hatake Date: Fri, 11 Aug 2023 21:15:24 +0900 Subject: [PATCH 178/315] in_event_test: Add +1 for acceptable time elapse Signed-off-by: Hiroshi Hatake --- plugins/in_event_test/event_test.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/plugins/in_event_test/event_test.c b/plugins/in_event_test/event_test.c index 1de8b3ff681..557017fe22f 100644 --- a/plugins/in_event_test/event_test.c +++ b/plugins/in_event_test/event_test.c @@ -109,7 +109,9 @@ static int cb_collector_time(struct flb_input_instance *ins, now = time(NULL); diff = now - config->init_time; - if (diff > CALLBACK_TIME) { + /* For macOS, we sometimes get the +1 longer time elapse. + * To handle this, we simply add +1 as a delta for checking interval. */ + if (diff > (CALLBACK_TIME + 1)) { flb_plg_error(ins, "cb_collector_time difference failed: %i seconds", diff); set_unit_test_status(ctx, 0, STATUS_ERROR); flb_engine_exit(config); From 31f999a9a6467c45842d832eee4ab7178c08e8fb Mon Sep 17 00:00:00 2001 From: Phillip Whelan Date: Tue, 22 Aug 2023 18:07:25 -0400 Subject: [PATCH 179/315] yaml/v2: use stack based parser. (#7661) * yaml/v2: move to a stack based parser. Use a LIFO list (or stack) to save parser states. This allows code to be reused between inputs, outputs, filters, customs and processors. With this support for list-based properties for processors now works. Signed-off-by: Phillip Whelan * yaml/v2: remove unused STATE_PROCESSOR_MAP. Signed-off-by: Phillip Whelan * yaml/v2: use debug printing the structure/state event messages. Signed-off-by: Phillip Whelan * yaml/v2: fix assignment when adding multiple processors. Signed-off-by: Phillip Whelan * yaml/v2: move variable declarations out of switch case statements. Signed-off-by: Phillip Whelan * yaml/v2: wrap state_names behind state_str function. Signed-off-by: Phillip Whelan * processors: update fallback call in flb_processor_unit_set_property. Signed-off-by: Phillip Whelan * yaml/v2: remove unused variables and functions. Signed-off-by: Phillip Whelan * yaml/v2: move variable declaration out of case statement. Signed-off-by: Phillip Whelan * yaml/v2: rename all instances 'i' to idx and remove local declarations. Signed-off-by: Phillip Whelan * processors: fix memory leak in updated processor test. Signed-off-by: Phillip Whelan * yaml/v2: improve tests. Signed-off-by: Phillip Whelan * yaml/v2: add single parser file test. Signed-off-by: Phillip Whelan * yaml/v2: finish test for parsers_file for yaml. Signed-off-by: Phillip Whelan * yaml/v2: move to a stack based parser. Use a LIFO list (or stack) to save parser states. This allows code to be reused between inputs, outputs, filters, customs and processors. With this support for list-based properties for processors now works. Signed-off-by: Phillip Whelan * yaml/v2: remove unused STATE_PROCESSOR_MAP. Signed-off-by: Phillip Whelan * yaml/v2: windows fixes. Signed-off-by: Phillip Whelan * yaml/v2: add missing parsers.conf test file. Signed-off-by: Phillip Whelan * yaml/v2: free flb_config in parser test. Signed-off-by: Phillip Whelan * yaml/v2: minor section fixes. Signed-off-by: Phillip Whelan * yaml/v2: refactor state_name to use a switch case. Signed-off-by: Phillip Whelan * yaml/v2: remove single letter variables. Signed-off-by: Phillip Whelan * yaml/v2: check return values. Signed-off-by: Phillip Whelan * yaml/v2: rewrite allocation flags as macros. Signed-off-by: Phillip Whelan * yaml/v2: move all type definitions to the start. Signed-off-by: Phillip Whelan * yaml/v2: rename get_last_included_file to state_get_last. Signed-off-by: Phillip Whelan * yaml/v2: check return value of snprintf in read_glob. Signed-off-by: Phillip Whelan * yaml/v2: fix return value for error in state_push_witharr. Signed-off-by: Phillip Whelan * yaml/v2: remove comment. Signed-off-by: Phillip Whelan * yaml/v2: adhere to code standard. Signed-off-by: Phillip Whelan * yaml/v2: redefine HAS_KEY and HAS_KEYVALS as macros. Signed-off-by: Phillip Whelan * yaml/v2: erase redefinitions. Signed-off-by: Phillip Whelan * yaml/v2: release local variable 'file' and not 'cfg_file'. Signed-off-by: Phillip Whelan * yaml/v2: check list size when getting current state. Signed-off-by: Phillip Whelan * yaml/v2: move initialization out of declaration. Signed-off-by: Phillip Whelan * yaml/v2: check return value of get_current_state. Signed-off-by: Phillip Whelan * yaml/v2: check return value of flb_sds_printf when concatenating filename. Signed-off-by: Phillip Whelan * yaml/v2: syntax fixes. Signed-off-by: Phillip Whelan * yaml/v2: check everything in yaml_error_event. Signed-off-by: Phillip Whelan * yaml/v2: check return values. Signed-off-by: Phillip Whelan * yaml/v2: fix bugs introduced by code deduplication. Signed-off-by: Phillip Whelan * yaml/v2: check return values for state_get_last. Signed-off-by: Phillip Whelan * yaml/v2: fix 'e' undeclared error. Signed-off-by: Phillip Whelan * yaml/v2: rename kv to prop. Signed-off-by: Phillip Whelan * yaml/v2: add missing error handling. Signed-off-by: Phillip Whelan * yaml/v2: fix codig violations in comments. Signed-off-by: Phillip Whelan * yaml/v2: rename short variables. Signed-off-by: Phillip Whelan * yaml/v2: check return values and fix memory leaks. Signed-off-by: Phillip Whelan * yaml/v2: rename file to include_dir. Signed-off-by: Phillip Whelan * yaml/v2: add new line before if, break out else to next line. Signed-off-by: Phillip Whelan --------- Signed-off-by: Phillip Whelan --- include/fluent-bit/flb_processor.h | 2 +- src/config_format/flb_cf_yaml.c | 2116 +++++++++++------ src/config_format/flb_config_format.c | 5 + src/flb_processor.c | 112 +- tests/internal/config_format_yaml.c | 190 +- .../data/config_format/yaml/fluent-bit.yaml | 30 +- .../yaml/parsers/parsers-conf.yaml | 3 + .../config_format/yaml/parsers/parsers.conf | 6 + .../yaml/pipelines/slist/even.yaml | 7 + .../yaml/pipelines/slist/odd.yaml | 8 + tests/internal/processor.c | 12 +- 11 files changed, 1656 insertions(+), 835 deletions(-) create mode 100644 tests/internal/data/config_format/yaml/parsers/parsers-conf.yaml create mode 100644 tests/internal/data/config_format/yaml/parsers/parsers.conf create mode 100644 tests/internal/data/config_format/yaml/pipelines/slist/even.yaml create mode 100644 tests/internal/data/config_format/yaml/pipelines/slist/odd.yaml diff --git a/include/fluent-bit/flb_processor.h b/include/fluent-bit/flb_processor.h index 20d4a605e16..591604fbed4 100644 --- a/include/fluent-bit/flb_processor.h +++ b/include/fluent-bit/flb_processor.h @@ -207,7 +207,7 @@ struct flb_processor_unit *flb_processor_unit_create(struct flb_processor *proc, int event_type, char *unit_name); void flb_processor_unit_destroy(struct flb_processor_unit *pu); -int flb_processor_unit_set_property(struct flb_processor_unit *pu, const char *k, const char *v); +int flb_processor_unit_set_property(struct flb_processor_unit *pu, const char *k, struct cfl_variant *v); int flb_processors_load_from_config_format_group(struct flb_processor *proc, struct flb_cf_group *g); diff --git a/src/config_format/flb_cf_yaml.c b/src/config_format/flb_cf_yaml.c index 172d700d8e8..f8807704644 100644 --- a/src/config_format/flb_cf_yaml.c +++ b/src/config_format/flb_cf_yaml.c @@ -56,9 +56,48 @@ enum section { SECTION_INPUT, SECTION_FILTER, SECTION_OUTPUT, + SECTION_PROCESSOR, SECTION_OTHER, }; +static char *section_names[] = { + "env", + "include", + "service", + "pipeline", + "custom", + "input", + "filter", + "output", + "processor", + "other" +}; + +struct file_state { + /* file */ + flb_sds_t name; /* file name */ + flb_sds_t path; /* file root path */ + + /* parent file state */ + struct file_state *parent; +}; + +struct local_ctx { + int level; /* inclusion level */ + + struct cfl_list states; + + struct mk_list includes; + + int service_set; +}; + +/* yaml_* functions return 1 on success and 0 on failure. */ +enum status { + YAML_SUCCESS = 1, + YAML_FAILURE = 0 +}; + enum state { STATE_START, /* start state */ STATE_STREAM, /* start/end stream */ @@ -72,19 +111,14 @@ enum state { STATE_INCLUDE, /* 'includes' section */ STATE_OTHER, /* any other unknown section */ + STATE_CUSTOM, /* custom plugins */ STATE_PIPELINE, /* pipeline groups customs inputs, filters and outputs */ STATE_PLUGIN_INPUT, /* input plugins section */ STATE_PLUGIN_FILTER, /* filter plugins section */ STATE_PLUGIN_OUTPUT, /* output plugins section */ - STATE_CUSTOM, /* custom plugins */ - STATE_CUSTOM_SEQUENCE, - STATE_CUSTOM_KEY_VALUE_PAIR, - STATE_CUSTOM_KEY, - STATE_CUSTOM_VAL, - - STATE_PLUGIN_TYPE, + STATE_PLUGIN_START, STATE_PLUGIN_KEY, STATE_PLUGIN_VAL, STATE_PLUGIN_VAL_LIST, @@ -92,15 +126,8 @@ enum state { STATE_GROUP_KEY, STATE_GROUP_VAL, + STATE_INPUT_PROCESSORS, STATE_INPUT_PROCESSOR, - STATE_INPUT_PROCESSOR_LOGS_KEY, - STATE_INPUT_PROCESSOR_LOGS_VAL, - - STATE_INPUT_PROCESSOR_METRICS_KEY, - STATE_INPUT_PROCESSOR_METRICS_VAL, - - STATE_INPUT_PROCESSOR_TRACES_KEY, - STATE_INPUT_PROCESSOR_TRACES_VAL, /* environment variables */ STATE_ENV, @@ -109,71 +136,135 @@ enum state { STATE_STOP /* end state */ }; +/* parser state allocation flags */ +#define HAS_KEY (1 << 0) +#define HAS_KEYVALS (1 << 1) + struct parser_state { /* tokens state */ enum state state; + /* nesting level */ + int level; /* active section (if any) */ enum section section; - /* temporary key value pair */ - flb_sds_t key; - flb_sds_t val; - /* active section */ struct flb_cf_section *cf_section; - struct cfl_array *values; /* pointer to current values in a list. */ - /* active group */ struct flb_cf_group *cf_group; - /* active processor group: logs, metrics or traces */ - struct cfl_kvlist *cf_processor_kv; - struct cfl_array *cf_processor_type_array; - struct cfl_kvlist *cf_processor_type_list; + /* key value */ + flb_sds_t key; + /* section key/value list */ + struct cfl_kvlist *keyvals; + /* pointer to current values in a list. */ + struct cfl_array *values; + /* are we the owner of the values? */ + int allocation_flags; - /* file */ - flb_sds_t file; /* file name */ - flb_sds_t root_path; /* file root path */ + struct file_state *file; - /* caller file */ - flb_sds_t caller_file; /* caller file name */ - flb_sds_t caller_root_path; /* caller file root path */ + struct cfl_list _head; }; -struct local_ctx { - int level; /* inclusion level */ - - struct mk_list includes; - - int service_set; -}; +static struct parser_state *state_push(struct local_ctx *, enum state); +static struct parser_state *state_push_withvals(struct local_ctx *, + struct parser_state *, + enum state); +static struct parser_state *state_push_witharr(struct local_ctx *, + struct parser_state *, + enum state); +static struct parser_state *state_push_section(struct local_ctx *, enum state, + enum section); +static struct parser_state *state_push_key(struct local_ctx *, enum state, + const char *key); +static int state_create_section(struct flb_cf *, struct parser_state *, char *); +static int state_create_group(struct flb_cf *, struct parser_state *, char *); +static struct parser_state *state_pop(struct local_ctx *ctx); +static struct parser_state *state_create(struct file_state *parent, struct file_state *file); +static void state_destroy(struct parser_state *s); -/* yaml_* functions return 1 on success and 0 on failure. */ -enum status { - YAML_SUCCESS = 1, - YAML_FAILURE = 0 -}; static int read_config(struct flb_cf *cf, struct local_ctx *ctx, - char *caller_file, char *cfg_file); + struct file_state *parent, char *cfg_file); + +static char *state_str(enum state val) +{ + switch (val) { + case STATE_START: + return "start"; + case STATE_STREAM: + return "stream"; + case STATE_DOCUMENT: + return "document"; + case STATE_SECTION: + return "section"; + case STATE_SECTION_KEY: + return "section-key"; + case STATE_SECTION_VAL: + return "section-value"; + case STATE_SERVICE: + return "service"; + case STATE_INCLUDE: + return "include"; + case STATE_OTHER: + return "other"; + case STATE_CUSTOM: + return "custom"; + case STATE_PIPELINE: + return "pipeline"; + case STATE_PLUGIN_INPUT: + return "input"; + case STATE_PLUGIN_FILTER: + return "filter"; + case STATE_PLUGIN_OUTPUT: + return "output"; + case STATE_PLUGIN_START: + return "plugin-start"; + case STATE_PLUGIN_KEY: + return "plugin-key"; + case STATE_PLUGIN_VAL: + return "plugin-value"; + case STATE_PLUGIN_VAL_LIST: + return "plugin-values"; + case STATE_GROUP_KEY: + return "group-key"; + case STATE_GROUP_VAL: + return "group-val"; + case STATE_INPUT_PROCESSORS: + return "processors"; + case STATE_INPUT_PROCESSOR: + return "processor"; + case STATE_ENV: + return "env"; + case STATE_STOP: + return "stop"; + default: + return "unknown"; + } +} -static int add_section_type(struct flb_cf *cf, struct parser_state *s) +static int add_section_type(struct flb_cf *conf, struct parser_state *state) { - if (s->section == SECTION_INPUT) { - s->cf_section = flb_cf_section_create(cf, "INPUT", 0); + if (conf == NULL || state == NULL) { + return -1; } - else if (s->section == SECTION_FILTER) { - s->cf_section = flb_cf_section_create(cf, "FILTER", 0); + + if (state->section == SECTION_INPUT) { + state->cf_section = flb_cf_section_create(conf, "INPUT", 0); + } + else if (state->section == SECTION_FILTER) { + state->cf_section = flb_cf_section_create(conf, "FILTER", 0); } - else if (s->section == SECTION_OUTPUT) { - s->cf_section = flb_cf_section_create(cf, "OUTPUT", 0); + else if (state->section == SECTION_OUTPUT) { + state->cf_section = flb_cf_section_create(conf, "OUTPUT", 0); } - else if (s->section == SECTION_CUSTOM) { - s->cf_section = flb_cf_section_create(cf, "customs", 0); + else if (state->section == SECTION_CUSTOM) { + state->cf_section = flb_cf_section_create(conf, "customs", 0); } - if (!s->cf_section) { + if (!state->cf_section) { return -1; } @@ -211,164 +302,80 @@ static char *event_type_str(yaml_event_t *event) } } -static char *state_str(enum state val) +static char *state_get_last(struct local_ctx *ctx) { - char* ret; - switch(val) { - case STATE_START: - ret = "start"; - break; - case STATE_STREAM: - ret = "stream"; - break; - case STATE_DOCUMENT: - ret = "document"; - break; - case STATE_SECTION: - ret = "section"; - break; - case STATE_SECTION_KEY: - ret = "section-key"; - break; - case STATE_SECTION_VAL: - ret = "section-val"; - break; - case STATE_SERVICE: - ret = "service"; - break; - case STATE_INCLUDE: - ret = "include"; - break; - case STATE_OTHER: - ret = "other"; - break; - case STATE_PIPELINE: - ret = "pipeline"; - break; - case STATE_PLUGIN_INPUT: - ret = "plugin-input"; - break; - case STATE_PLUGIN_FILTER: - ret = "plugin-filter"; - break; - case STATE_PLUGIN_OUTPUT: - ret = "plugin-output"; - break; - case STATE_CUSTOM: - ret = "custom"; - break; - case STATE_CUSTOM_SEQUENCE: - ret = "custom-sequence"; - break; - case STATE_CUSTOM_KEY_VALUE_PAIR: - ret = "custom-key-value-pair"; - break; - case STATE_CUSTOM_KEY: - ret = "custom-key"; - break; - case STATE_CUSTOM_VAL: - ret = "custom-val"; - break; - case STATE_PLUGIN_TYPE: - ret = "plugin-type"; - break; - case STATE_PLUGIN_KEY: - ret = "plugin-key"; - break; - case STATE_PLUGIN_VAL: - ret = "plugin-val"; - break; - case STATE_PLUGIN_VAL_LIST: - ret = "plugin-val-list"; - break; - case STATE_GROUP_KEY: - ret = "group-key"; - break; - case STATE_GROUP_VAL: - ret = "group-val"; - break; - case STATE_INPUT_PROCESSOR: - ret = "input-processor"; - break; - case STATE_INPUT_PROCESSOR_LOGS_KEY: - ret = "input-processor-logs-key"; - break; - case STATE_INPUT_PROCESSOR_LOGS_VAL: - ret = "input-processor-logs-val"; - break; - case STATE_INPUT_PROCESSOR_METRICS_KEY: - ret = "input-processor-metrics-key"; - break; - case STATE_INPUT_PROCESSOR_METRICS_VAL: - ret = "input-processor-metrics-val"; - break; - case STATE_INPUT_PROCESSOR_TRACES_KEY: - ret = "input-processor-traces-key"; - break; - case STATE_INPUT_PROCESSOR_TRACES_VAL: - ret = "input-processor-traces-val"; - break; - case STATE_ENV: - ret = "env"; - break; - case STATE_STOP: - ret = "stop"; - break; + struct flb_slist_entry *entry; - default: - ret = "UNKNOWN"; + entry = mk_list_entry_last(&ctx->includes, struct flb_slist_entry, _head); + + if (entry == NULL) { + return NULL; } - return ret; + return entry->str; } -static char *get_last_included_file(struct local_ctx *ctx) +static void yaml_error_event(struct local_ctx *ctx, struct parser_state *state, + yaml_event_t *event) { - struct flb_slist_entry *e; + struct flb_slist_entry *entry; - e = mk_list_entry_last(&ctx->includes, struct flb_slist_entry, _head); - return e->str; -} + if (event == NULL) { + flb_error("[config] YAML error found but with no state or event"); + return; + } -static void yaml_error_event(struct local_ctx *ctx, struct parser_state *s, - yaml_event_t *event) -{ - struct flb_slist_entry *e; + if (state == NULL) { + flb_error("[config] YAML error found but with no state, line %zu, column %zu: " + "unexpected event '%s' (%d).", + event->start_mark.line + 1, event->start_mark.column, + event_type_str(event), event->type); + return; + } - e = mk_list_entry_last(&ctx->includes, struct flb_slist_entry, _head); + entry = mk_list_entry_last(&ctx->includes, struct flb_slist_entry, _head); + + if (entry == NULL) { + flb_error("[config] YAML error found (no file info), line %zu, column %zu: " + "unexpected event '%s' (%d) in state '%s' (%d).", + event->start_mark.line + 1, event->start_mark.column, + event_type_str(event), event->type, state_str(state->state), state->state); + return; + } flb_error("[config] YAML error found in file \"%s\", line %zu, column %zu: " "unexpected event '%s' (%d) in state '%s' (%d).", - e->str, event->start_mark.line + 1, event->start_mark.column, - event_type_str(event), event->type, state_str(s->state), s->state); + entry->str, event->start_mark.line + 1, event->start_mark.column, + event_type_str(event), event->type, state_str(state->state), state->state); } -static void yaml_error_definition(struct local_ctx *ctx, struct parser_state *s, +static void yaml_error_definition(struct local_ctx *ctx, struct parser_state *state, yaml_event_t *event, char *value) { flb_error("[config] YAML error found in file \"%s\", line %zu, column %zu: " "duplicated definition of '%s'", - s->file, event->start_mark.line + 1, event->start_mark.column, + state->file->name, event->start_mark.line + 1, event->start_mark.column, value); } -static void yaml_error_plugin_category(struct local_ctx *ctx, struct parser_state *s, +static void yaml_error_plugin_category(struct local_ctx *ctx, struct parser_state *state, yaml_event_t *event, char *value) { flb_error("[config] YAML error found in file \"%s\", line %zu, column %zu: " "the pipeline component '%s' is not valid. Try one of these values: " "customs, inputs, filters or outputs.", - s->file, event->start_mark.line + 1, event->start_mark.column, + state->file->name, event->start_mark.line + 1, event->start_mark.column, value); } static int is_file_included(struct local_ctx *ctx, const char *path) { struct mk_list *head; - struct flb_slist_entry *e; + struct flb_slist_entry *entry; mk_list_foreach(head, &ctx->includes) { - e = mk_list_entry(head, struct flb_slist_entry, _head); - if (strcmp(e->str, path) == 0) { + entry = mk_list_entry(head, struct flb_slist_entry, _head); + + if (strcmp(entry->str, path) == 0) { return FLB_TRUE; } } @@ -377,19 +384,23 @@ static int is_file_included(struct local_ctx *ctx, const char *path) } #ifndef _WIN32 -static int read_glob(struct flb_cf *cf, struct local_ctx *ctx, +static int read_glob(struct flb_cf *conf, struct local_ctx *ctx, struct parser_state *state, const char *path) { int ret = -1; glob_t glb; - char tmp[PATH_MAX]; + char tmp[PATH_MAX+1]; const char *glb_path; - size_t i; + size_t idx; int ret_glb = -1; - if (state->root_path && path[0] != '/') { - snprintf(tmp, PATH_MAX, "%s/%s", state->root_path, path); + if (state->file->path && path[0] != '/') { + ret = snprintf(tmp, PATH_MAX, "%s/%s", state->file->path, path); + + if (ret > PATH_MAX) { + return -1; + } glb_path = tmp; } else { @@ -397,6 +408,7 @@ static int read_glob(struct flb_cf *cf, struct local_ctx *ctx, } ret_glb = glob(glb_path, GLOB_NOSORT, NULL, &glb); + if (ret_glb != 0) { switch(ret_glb){ case GLOB_NOSPACE: @@ -414,9 +426,10 @@ static int read_glob(struct flb_cf *cf, struct local_ctx *ctx, return ret; } - for (i = 0; i < glb.gl_pathc; i++) { - ret = read_config(cf, ctx, state->file, glb.gl_pathv[i]); - if (ret < 0) { + for (idx = 0; idx < glb.gl_pathc; idx++) { + ret = read_config(conf, ctx, state->file, glb.gl_pathv[idx]); + + if (ret < 0) { break; } } @@ -425,14 +438,29 @@ static int read_glob(struct flb_cf *cf, struct local_ctx *ctx, return ret; } #else -static int read_glob(struct flb_cf *cf, struct parser_state *ctx, const char *path) +static char *dirname(char *path) +{ + char *ptr; + + + ptr = strrchr(path, '\\'); + + if (ptr == NULL) { + return path; + } + *ptr++='\0'; + return path; +} + +static int read_glob(struct flb_cf *conf, struct local_ctx *ctx, + struct parser_state *state, const char *path) { char *star, *p0, *p1; char pattern[MAX_PATH]; char buf[MAX_PATH]; int ret; struct stat st; - HANDLE h; + HANDLE hnd; WIN32_FIND_DATA data; if (strlen(path) > MAX_PATH - 1) { @@ -440,6 +468,7 @@ static int read_glob(struct flb_cf *cf, struct parser_state *ctx, const char *pa } star = strchr(path, '*'); + if (star == NULL) { return -1; } @@ -465,8 +494,9 @@ static int read_glob(struct flb_cf *cf, struct parser_state *ctx, const char *pa memcpy(pattern, path, (p1 - path)); pattern[p1 - path] = '\0'; - h = FindFirstFileA(pattern, &data); - if (h == INVALID_HANDLE_VALUE) { + hnd = FindFirstFileA(pattern, &data); + + if (hnd == INVALID_HANDLE_VALUE) { return 0; } @@ -488,200 +518,341 @@ static int read_glob(struct flb_cf *cf, struct parser_state *ctx, const char *pa if (FAILED(StringCchCatA(buf, MAX_PATH, data.cFileName))) { continue; } + if (FAILED(StringCchCatA(buf, MAX_PATH, p1))) { continue; } if (strchr(p1, '*')) { - read_glob(cf, ctx, buf); /* recursive */ + read_glob(conf, ctx, state, buf); /* recursive */ continue; } ret = stat(buf, &st); + if (ret == 0 && (st.st_mode & S_IFMT) == S_IFREG) { - if (read_config(cf, ctx, data.cFileName, buf) < 0) { + + if (read_config(conf, ctx, state, buf) < 0) { return -1; } } - } while (FindNextFileA(h, &data) != 0); + } while (FindNextFileA(hnd, &data) != 0); - FindClose(h); + FindClose(hnd); return 0; } #endif -static int consume_event(struct flb_cf *cf, struct local_ctx *ctx, - struct parser_state *s, yaml_event_t *event) +static void print_current_state(struct local_ctx *ctx, struct parser_state *state, + yaml_event_t *event) { - int len; - int ret; - char *value; - struct flb_kv *kv; - char *last_included = get_last_included_file(ctx); - - switch (s->state) { - case STATE_START: - switch (event->type) { - case YAML_STREAM_START_EVENT: - s->state = STATE_STREAM; - break; - default: - yaml_error_event(ctx, s, event); - return YAML_FAILURE; - } - break; + flb_error("%*s%s->%s", state->level*2, "", state_str(state->state), + event_type_str(event)); +} - case STATE_STREAM: - switch (event->type) { - case YAML_DOCUMENT_START_EVENT: - s->state = STATE_DOCUMENT; +static void print_current_properties(struct parser_state *state) +{ + struct cfl_list *head; + struct cfl_kvpair *prop; + struct cfl_variant *var; + int idx; + + flb_error("%*s[%s] PROPERTIES:", state->level*2, "", section_names[state->section]); + + cfl_list_foreach(head, &state->keyvals->list) { + prop = cfl_list_entry(head, struct cfl_kvpair, _head); + switch (prop->val->type) { + case CFL_VARIANT_STRING: + flb_error("%*s%s: %s", (state->level+2)*2, "", prop->key, prop->val->data.as_string); break; - case YAML_STREAM_END_EVENT: - s->state = STATE_STOP; /* all done */ + case CFL_VARIANT_ARRAY: + flb_error("%*s%s: [", (state->level+2)*2, "", prop->key); + for (idx = 0; idx < prop->val->data.as_array->entry_count; idx++) { + var = cfl_array_fetch_by_index(prop->val->data.as_array, idx); + flb_error("%*s%s", (state->level+3)*2, "", var->data.as_string); + } + flb_error("%*s]", (state->level+2)*2, ""); break; - default: - yaml_error_event(ctx, s, event); - return YAML_FAILURE; } - break; + } +} - case STATE_DOCUMENT: - switch (event->type) { - case YAML_MAPPING_START_EVENT: - s->state = STATE_SECTION; - break; - case YAML_DOCUMENT_END_EVENT: - s->state = STATE_STREAM; - break; - default: - yaml_error_event(ctx, s, event); +static struct parser_state *get_current_state(struct local_ctx *ctx) +{ + struct parser_state *state; + + if (cfl_list_size(&ctx->states) <= 0) { + return NULL; + } + state = cfl_list_entry_last(&ctx->states, struct parser_state, _head); + return state; +} + +static enum status state_copy_into_config_group(struct parser_state *state, struct flb_cf_group *cf_group) +{ + struct cfl_list *head; + struct cfl_kvpair *kvp; + struct cfl_variant *var; + struct cfl_variant *varr; + struct cfl_array *arr; + struct cfl_array *carr; + struct cfl_kvlist *copy; + int idx; + + if (cf_group == NULL) { + flb_error("no group for processor properties"); + return YAML_FAILURE; + } + + varr = cfl_kvlist_fetch(cf_group->properties, state->key); + + if (varr == NULL) { + arr = cfl_array_create(1); + + if (arr == NULL) { + flb_error("unable to allocate array"); return YAML_FAILURE; } - break; - /* - * 'customs' - * -------- - */ - case STATE_CUSTOM: - switch (event->type) { - case YAML_SEQUENCE_START_EVENT: - s->state = STATE_PLUGIN_TYPE; - break; + cfl_array_resizable(arr, CFL_TRUE); - case YAML_SEQUENCE_END_EVENT: - s->state = STATE_SECTION; - break; - default: - yaml_error_event(ctx, s, event); + if (cfl_kvlist_insert_array(cf_group->properties, state->key, arr) < 0) { + cfl_array_destroy(arr); + flb_error("unable to insert into array"); return YAML_FAILURE; } - break; + } + else { + arr = varr->data.as_array; + } - case STATE_CUSTOM_SEQUENCE: - switch (event->type) { - case YAML_SCALAR_EVENT: - value = (char *)event->data.scalar.value; - len = strlen(value); - if (len == 0) { - yaml_error_event(ctx, s, event); + copy = cfl_kvlist_create(); + + if (copy == NULL) { + cfl_array_destroy(arr); + flb_error("unable to allocate kvlist"); + return YAML_FAILURE; + } + + cfl_list_foreach(head, &state->keyvals->list) { + kvp = cfl_list_entry(head, struct cfl_kvpair, _head); + switch (kvp->val->type) { + case CFL_VARIANT_STRING: + + if (cfl_kvlist_insert_string(copy, kvp->key, kvp->val->data.as_string) < 0) { + flb_error("unable to allocate kvlist"); + cfl_kvlist_destroy(copy); return YAML_FAILURE; } + break; + case CFL_VARIANT_ARRAY: + carr = cfl_array_create(kvp->val->data.as_array->entry_count); - /* create the 'customs' section */ - s->cf_section = flb_cf_section_create(cf, "customs", 0); - if (!s->cf_section) { + if (carr) { + flb_error("unable to allocate array"); + cfl_kvlist_destroy(copy); return YAML_FAILURE; } + for (idx = 0; idx < kvp->val->data.as_array->entry_count; idx++) { + var = cfl_array_fetch_by_index(kvp->val->data.as_array, idx); - /* value is the 'custom plugin name', create a section instance */ - if (flb_cf_section_property_add(cf, s->cf_section->properties, - "name", 4, - value, len) < 0) { - return YAML_FAILURE; + if (var == NULL) { + cfl_array_destroy(arr); + flb_error("unable to fetch from array by index"); + return YAML_FAILURE; + } + switch (var->type) { + case CFL_VARIANT_STRING: + + if (cfl_array_append_string(carr, var->data.as_string) < 0) { + flb_error("unable to append string"); + cfl_kvlist_destroy(copy); + cfl_array_destroy(carr); + return YAML_FAILURE; + } + break; + default: + cfl_array_destroy(arr); + flb_error("unable to copy value for property"); + cfl_kvlist_destroy(copy); + cfl_array_destroy(carr); + return YAML_FAILURE; + } } - /* next state are key value pairs for the custom plugin*/ - s->state = STATE_CUSTOM_KEY_VALUE_PAIR; - break; - case YAML_MAPPING_START_EVENT: - break; - case YAML_MAPPING_END_EVENT: - break; - case YAML_SEQUENCE_END_EVENT: - s->state = STATE_SECTION; - break; - default: - yaml_error_event(ctx, s, event); - return YAML_FAILURE; - } - break; - case STATE_CUSTOM_KEY_VALUE_PAIR: - switch(event->type) { - case YAML_MAPPING_START_EVENT: - s->state = STATE_CUSTOM_KEY; - break; - case YAML_MAPPING_END_EVENT: - s->state = STATE_CUSTOM; - break; - case YAML_SEQUENCE_END_EVENT: + if (cfl_kvlist_insert_array(copy, kvp->key, carr) < 0) { + cfl_array_destroy(arr); + flb_error("unabelt to insert into array"); + flb_error("unable to insert array into kvlist"); + } break; - default: - yaml_error_event(ctx, s, event); + flb_error("unknown value type for properties: %d", kvp->val->type); + cfl_kvlist_destroy(copy); return YAML_FAILURE; } - break; + } - case STATE_CUSTOM_KEY: - switch(event->type) { - case YAML_SCALAR_EVENT: - s->state = STATE_CUSTOM_VAL; - value = (char *) event->data.scalar.value; - s->key = flb_sds_create(value); + if (cfl_array_append_kvlist(arr, copy) < 0) { + flb_error("unable to insert array into kvlist"); + cfl_kvlist_destroy(copy); + return YAML_FAILURE; + } + return YAML_SUCCESS; +} + +static enum status state_copy_into_properties(struct parser_state *state, struct flb_cf *conf, struct cfl_kvlist *properties) +{ + struct cfl_list *head; + struct cfl_kvpair *kvp; + struct cfl_variant *var; + struct cfl_array *arr; + int idx; + + cfl_list_foreach(head, &state->keyvals->list) { + kvp = cfl_list_entry(head, struct cfl_kvpair, _head); + switch (kvp->val->type) { + case CFL_VARIANT_STRING: + var = flb_cf_section_property_add(conf, + properties, + kvp->key, + cfl_sds_len(kvp->key), + kvp->val->data.as_string, + cfl_sds_len(kvp->val->data.as_string)); + + if (var == NULL) { + flb_error("unable to add variant value property"); + return YAML_FAILURE; + } break; - case YAML_MAPPING_START_EVENT: - s->state = STATE_CUSTOM; + case CFL_VARIANT_ARRAY: + arr = flb_cf_section_property_add_list(conf, properties, + kvp->key, cfl_sds_len(kvp->key)); + + if (arr == NULL) { + flb_error("unable to add property list"); + return YAML_FAILURE; + } + for (idx = 0; idx < kvp->val->data.as_array->entry_count; idx++) { + var = cfl_array_fetch_by_index(kvp->val->data.as_array, idx); + + if (var == NULL) { + flb_error("unable to retrieve from array by index"); + return YAML_FAILURE; + } + switch (var->type) { + case CFL_VARIANT_STRING: + + if (cfl_array_append_string(arr, var->data.as_string) < 0) { + flb_error("unable to append string to array"); + return YAML_FAILURE; + } + break; + default: + flb_error("unable to copy value for property"); + return YAML_FAILURE; + } + } break; - case YAML_MAPPING_END_EVENT: - s->state = STATE_CUSTOM_SEQUENCE; + default: + flb_error("unknown value type for properties: %d", kvp->val->type); + return YAML_FAILURE; + } + } + return YAML_SUCCESS; +} + +static int consume_event(struct flb_cf *conf, struct local_ctx *ctx, + yaml_event_t *event) +{ + struct parser_state *state; + enum status status; + int ret; + char *value; + struct flb_kv *keyval; + char *last_included; + + last_included = state_get_last(ctx); + + if (last_included == NULL) { + last_included = "**unknown**"; + } + + state = get_current_state(ctx); + + if (state == NULL) { + flb_error("unable to parse yaml: no state"); + return YAML_FAILURE; + } + print_current_state(ctx, state, event); + + switch (state->state) { + case STATE_START: + switch (event->type) { + case YAML_STREAM_START_EVENT: + state = state_push(ctx, STATE_STREAM); + + if (state == NULL) { + flb_error("unable to allocate state"); + return YAML_FAILURE; + } + break; + case YAML_NO_EVENT: + state->state = STATE_STOP; break; default: - yaml_error_event(ctx, s, event); + yaml_error_event(ctx, state, event); return YAML_FAILURE; } break; - case STATE_CUSTOM_VAL: - switch(event->type) { - case YAML_SCALAR_EVENT: - s->state = STATE_CUSTOM_KEY; - value = (char *) event->data.scalar.value; - s->val = flb_sds_create(value); + case STATE_STREAM: + switch (event->type) { + case YAML_DOCUMENT_START_EVENT: + state = state_push(ctx, STATE_DOCUMENT); - /* register key/value pair as a property */ - flb_cf_section_property_add(cf, s->cf_section->properties, - s->key, flb_sds_len(s->key), - s->val, flb_sds_len(s->val)); - flb_sds_destroy(s->key); - flb_sds_destroy(s->val); + if (state == NULL) { + flb_error("unable to allocate state"); + return YAML_FAILURE; + } break; - case YAML_MAPPING_START_EVENT: /* start a new group */ - s->state = STATE_GROUP_KEY; - s->cf_group = flb_cf_group_create(cf, s->cf_section, - s->key, flb_sds_len(s->key)); - flb_sds_destroy(s->key); - if (!s->cf_group) { + case YAML_STREAM_END_EVENT: + state = state_pop(ctx); + + if (state == NULL) { + flb_error("no state left"); + return YAML_FAILURE; + } + break; + default: + yaml_error_event(ctx, state, event); + return YAML_FAILURE; + } + break; + + case STATE_DOCUMENT: + switch (event->type) { + case YAML_MAPPING_START_EVENT: + state = state_push(ctx, STATE_SECTION); + + if (state == NULL) { + flb_error("unable to allocate state"); return YAML_FAILURE; } break; + case YAML_DOCUMENT_END_EVENT: + state = state_pop(ctx); + if (state == NULL) { + flb_error("no state left"); + return YAML_FAILURE; + } + break; default: - yaml_error_event(ctx, s, event); + yaml_error_event(ctx, state, event); return YAML_FAILURE; } break; - /* end of 'customs' */ /* * 'includes' @@ -692,19 +863,31 @@ static int consume_event(struct flb_cf *cf, struct local_ctx *ctx, case YAML_SEQUENCE_START_EVENT: break; case YAML_SEQUENCE_END_EVENT: - s->state = STATE_SECTION; + state = state_pop(ctx); + + if (state == NULL) { + flb_error("no state left"); + return YAML_FAILURE; + } + + if (state->state != STATE_SECTION) { + yaml_error_event(ctx, state, event); + return YAML_FAILURE; + } break; case YAML_SCALAR_EVENT: value = (char *) event->data.scalar.value; - flb_debug("[config yaml] including: %s", value); + flb_error("[config yaml] including: %s", value); + if (strchr(value, '*') != NULL) { - ret = read_glob(cf, ctx, s, value); + ret = read_glob(conf, ctx, state, value); } else { - ret = read_config(cf, ctx, s->file, value); + ret = read_config(conf, ctx, state->file, value); } + if (ret == -1) { - flb_error("[config] including file '%s' at %s:%zu", + flb_error("[config] including file '%s' at %s:%zu", value, last_included, event->start_mark.line + 1); return YAML_FAILURE; @@ -712,95 +895,174 @@ static int consume_event(struct flb_cf *cf, struct local_ctx *ctx, ctx->level++; break; default: - yaml_error_event(ctx, s, event); + yaml_error_event(ctx, state, event); return YAML_FAILURE; } break; /* end of 'includes' */ + /* + * 'customs' + * -------- + */ + case STATE_CUSTOM: + switch (event->type) { + case YAML_SEQUENCE_START_EVENT: + break; + case YAML_MAPPING_START_EVENT: + state = state_push_withvals(ctx, state, STATE_PLUGIN_START); + if (state == NULL) { + flb_error("unable to allocate state"); + return YAML_FAILURE; + } + if (add_section_type(conf, state) == -1) { + flb_error("unable to add section type"); + return YAML_FAILURE; + } + break; + case YAML_SEQUENCE_END_EVENT: + state = state_pop(ctx); + + if (state == NULL) { + flb_error("no state left"); + return YAML_FAILURE; + } + break; + default: + yaml_error_event(ctx, state, event); + return YAML_FAILURE; + } + break; + /* end of 'customs' */ + case STATE_PIPELINE: switch (event->type) { case YAML_SCALAR_EVENT: value = (char *)event->data.scalar.value; + if (strcasecmp(value, "inputs") == 0) { - s->state = STATE_PLUGIN_INPUT; - s->section = SECTION_INPUT; + state = state_push_section(ctx, STATE_PLUGIN_INPUT, SECTION_INPUT); } else if (strcasecmp(value, "filters") == 0) { - s->state = STATE_PLUGIN_FILTER; - s->section = SECTION_FILTER; + state = state_push_section(ctx, STATE_PLUGIN_FILTER, SECTION_FILTER); } else if (strcasecmp(value, "outputs") == 0) { - s->state = STATE_PLUGIN_OUTPUT; - s->section = SECTION_OUTPUT; + state = state_push_section(ctx, STATE_PLUGIN_OUTPUT, SECTION_OUTPUT); } else { - yaml_error_plugin_category(ctx, s, event, value); + yaml_error_plugin_category(ctx, state, event, value); + return YAML_FAILURE; + } + + if (state == NULL) { + flb_error("unable to allocate state"); return YAML_FAILURE; } break; case YAML_MAPPING_START_EVENT: break; case YAML_MAPPING_END_EVENT: - s->state = STATE_SECTION; + state_pop(ctx); + + if (state == NULL) { + flb_error("no state left"); + return YAML_FAILURE; + } break; default: - yaml_error_event(ctx, s, event); + yaml_error_event(ctx, state, event); return YAML_FAILURE; } break; case STATE_SECTION: - s->section = SECTION_OTHER; switch (event->type) { case YAML_SCALAR_EVENT: value = (char *)event->data.scalar.value; + if (strcasecmp(value, "env") == 0) { - s->state = STATE_ENV; - s->section = SECTION_ENV; + state = state_push_section(ctx, STATE_ENV, SECTION_ENV); + if (state == NULL) { + flb_error("unable to allocate state"); + return YAML_FAILURE; + } } else if (strcasecmp(value, "pipeline") == 0) { - s->state = STATE_PIPELINE; - s->section = SECTION_PIPELINE; + state = state_push_section(ctx, STATE_PIPELINE, SECTION_PIPELINE); + if (state == NULL) { + flb_error("unable to allocate state"); + return YAML_FAILURE; + } } else if (strcasecmp(value, "service") == 0) { + if (ctx->service_set) { - yaml_error_definition(ctx, s, event, value); + yaml_error_definition(ctx, state, event, value); + return YAML_FAILURE; + } + + state = state_push_section(ctx, STATE_SERVICE, SECTION_SERVICE); + + if (state == NULL) { + flb_error("unable to allocate state"); return YAML_FAILURE; } - s->state = STATE_SERVICE; - s->section = SECTION_SERVICE; - s->cf_section = flb_cf_section_create(cf, value, 0); - if (!s->cf_section) { + + if (state_create_section(conf, state, value) == -1) { + flb_error("unable to allocate section: %s", value); return YAML_FAILURE; } ctx->service_set = 1; } else if (strcasecmp(value, "customs") == 0) { - s->state = STATE_CUSTOM; - s->section = SECTION_CUSTOM; + state = state_push_section(ctx, STATE_CUSTOM, SECTION_CUSTOM); + + if (state == NULL) { + flb_error("unable to allocate state"); + return YAML_FAILURE; + } } else if (strcasecmp(value, "includes") == 0) { - s->state = STATE_INCLUDE; - s->section = SECTION_INCLUDE; + state = state_push_section(ctx, STATE_INCLUDE, SECTION_INCLUDE); + + if (state == NULL) { + flb_error("unable to allocate state"); + return YAML_FAILURE; + } } else { /* any other main section definition (e.g: similar to STATE_SERVICE) */ - s->state = STATE_OTHER; - s->cf_section = flb_cf_section_create(cf, value, 0); - if (!s->cf_section) { + state = state_push(ctx, STATE_OTHER); + + if (state == NULL) { + flb_error("unable to allocate state"); + return YAML_FAILURE; + } + + if (state_create_section(conf, state, value) == -1) { + flb_error("unable to allocate section: %s", value); return YAML_FAILURE; } } break; case YAML_MAPPING_END_EVENT: - s->state = STATE_DOCUMENT; + state = state_pop(ctx); + + if (state == NULL) { + flb_error("no state left"); + return YAML_FAILURE; + } break; case YAML_DOCUMENT_END_EVENT: - s->state = STATE_STREAM; + state = state_pop(ctx); + + if (state == NULL) { + flb_error("no state left"); + return YAML_FAILURE; + } break; default: - yaml_error_event(ctx, s, event); + yaml_error_event(ctx, state, event); return YAML_FAILURE; } break; @@ -811,13 +1073,28 @@ static int consume_event(struct flb_cf *cf, struct local_ctx *ctx, case STATE_OTHER: switch(event->type) { case YAML_MAPPING_START_EVENT: - s->state = STATE_SECTION_KEY; + state = state_push(ctx, STATE_SECTION_KEY); + + if (state == NULL) { + flb_error("unable to allocate state"); + return YAML_FAILURE; + } break; case YAML_MAPPING_END_EVENT: - s->state = STATE_SECTION; + state = state_pop(ctx); + + if (state == NULL) { + flb_error("no state left"); + return YAML_FAILURE; + } + + if (state->state != STATE_SECTION) { + yaml_error_event(ctx, state, event); + return YAML_FAILURE; + } break; default: - yaml_error_event(ctx, s, event); + yaml_error_event(ctx, state, event); return YAML_FAILURE; } break; @@ -825,15 +1102,35 @@ static int consume_event(struct flb_cf *cf, struct local_ctx *ctx, case STATE_SECTION_KEY: switch(event->type) { case YAML_SCALAR_EVENT: - s->state = STATE_SECTION_VAL; value = (char *) event->data.scalar.value; - s->key = flb_sds_create(value); + state = state_push_key(ctx, STATE_SECTION_VAL, value); + + if (state == NULL) { + flb_error("unable to allocate state"); + return YAML_FAILURE; + } break; case YAML_MAPPING_END_EVENT: - s->state = STATE_SECTION; + state = state_pop(ctx); + switch (state->state) { + case STATE_SERVICE: + case STATE_ENV: + case STATE_OTHER: + break; + default: + printf("BAD STATE FOR SECTION KEY POP=%s\n", state_str(state->state)); + yaml_error_event(ctx, state, event); + return YAML_FAILURE; + } + state = state_pop(ctx); + + if (state == NULL) { + flb_error("no state left"); + return YAML_FAILURE; + } break; default: - yaml_error_event(ctx, s, event); + yaml_error_event(ctx, state, event); return YAML_FAILURE; } break; @@ -841,35 +1138,49 @@ static int consume_event(struct flb_cf *cf, struct local_ctx *ctx, case STATE_SECTION_VAL: switch(event->type) { case YAML_SCALAR_EVENT: - s->state = STATE_SECTION_KEY; value = (char *) event->data.scalar.value; - s->val = flb_sds_create(value); /* Check if the incoming k/v pair set a config environment variable */ - if (s->section == SECTION_ENV) { - kv = flb_cf_env_property_add(cf, - s->key, flb_sds_len(s->key), - s->val, flb_sds_len(s->val)); - if (kv == NULL) { + if (state->section == SECTION_ENV) { + keyval = flb_cf_env_property_add(conf, + state->key, flb_sds_len(state->key), + value, strlen(value)); + + if (keyval == NULL) { + flb_error("unable to add key value"); return YAML_FAILURE; } } else { + /* register key/value pair as a property */ - if (s->cf_section == NULL) { + if (state->cf_section == NULL) { + flb_error("no section to register key value to"); return YAML_FAILURE; } - if (flb_cf_section_property_add(cf, s->cf_section->properties, - s->key, flb_sds_len(s->key), - s->val, flb_sds_len(s->val)) < 0) { + + if (flb_cf_section_property_add(conf, state->cf_section->properties, + state->key, flb_sds_len(state->key), + value, strlen(value)) < 0) { + flb_error("unable to add property"); return YAML_FAILURE; } } - flb_sds_destroy(s->key); - flb_sds_destroy(s->val); + + state = state_pop(ctx); + + if (state == NULL) { + flb_error("no state left"); + return YAML_FAILURE; + } + + if (state->state != STATE_SECTION_KEY) { + yaml_error_event(ctx, state, event); + return YAML_FAILURE; + } break; default: - yaml_error_event(ctx, s, event); + yaml_error_event(ctx, state, event); return YAML_FAILURE; } break; @@ -880,57 +1191,127 @@ static int consume_event(struct flb_cf *cf, struct local_ctx *ctx, case STATE_PLUGIN_OUTPUT: switch(event->type) { case YAML_SEQUENCE_START_EVENT: - s->state = STATE_PLUGIN_TYPE; break; case YAML_SEQUENCE_END_EVENT: - break; - case YAML_SCALAR_EVENT: - s->state = STATE_SECTION; + state = state_pop(ctx); + + if (state == NULL) { + flb_error("no state left"); + return YAML_FAILURE; + } break; case YAML_MAPPING_START_EVENT: - s->state = STATE_PLUGIN_TYPE; + state = state_push_withvals(ctx, state, STATE_PLUGIN_START); + + if (state == NULL) { + flb_error("unable to allocate state"); + return YAML_FAILURE; + } + + if (add_section_type(conf, state) == -1) { + flb_error("unable to add section type"); + return YAML_FAILURE; + } + break; + case YAML_SCALAR_EVENT: + state = state_pop(ctx); + + if (state == NULL) { + flb_error("no state left"); + return YAML_FAILURE; + } + + if (state->state != STATE_SECTION) { + yaml_error_event(ctx, state, event); + return YAML_FAILURE; + } break; case YAML_MAPPING_END_EVENT: - s->state = STATE_SECTION_KEY; + state = state_pop(ctx); + + if (state == NULL) { + flb_error("no state left"); + return YAML_FAILURE; + } + + if (state->state != STATE_SECTION_KEY) { + yaml_error_event(ctx, state, event); + return YAML_FAILURE; + } break; default: - yaml_error_event(ctx, s, event); + yaml_error_event(ctx, state, event); return YAML_FAILURE; } break; - case STATE_PLUGIN_TYPE: + case STATE_PLUGIN_START: switch(event->type) { case YAML_SCALAR_EVENT: - /* register the section by type */ - ret = add_section_type(cf, s); - if (ret == -1) { + /* Here is where we process all the plugin properties for customs, pipelines + * and processors. + */ + state = state_push_key(ctx, STATE_PLUGIN_VAL, (char *) event->data.scalar.value); + + if (state == NULL) { + flb_error("unable to allocate state"); return YAML_FAILURE; } - - /* the next state is the keys of the properties of the plugin. */ - s->state = STATE_PLUGIN_KEY; break; - case YAML_MAPPING_START_EVENT: - ret = add_section_type(cf, s); - if (ret == -1) { + case YAML_MAPPING_END_EVENT: + print_current_properties(state); + + if (state->section == SECTION_PROCESSOR) { + status = state_copy_into_config_group(state, state->cf_group); + + if (status != YAML_SUCCESS) { + return status; + } + } + else { + status = state_copy_into_properties(state, conf, state->cf_section->properties); + + if (status != YAML_SUCCESS) { + return status; + } + } + + state = state_pop(ctx); + + if (state == NULL) { + flb_error("no state left"); return YAML_FAILURE; } - s->state = STATE_PLUGIN_KEY; break; - case YAML_MAPPING_END_EVENT: + case YAML_SEQUENCE_START_EVENT: /* start a new group */ + + if (strcmp(state->key, "processors") == 0) { + yaml_error_event(ctx, state, event); + return YAML_FAILURE; + } + + if (state->key == NULL) { + flb_error("no key"); + return YAML_FAILURE; + } + + state = state_push_witharr(ctx, state, STATE_PLUGIN_VAL_LIST); + + if (state == NULL) { + flb_error("unable to allocate state"); + return YAML_FAILURE; + } break; case YAML_SEQUENCE_END_EVENT: - if (s->section == SECTION_CUSTOM) { - /* 'customs' is a top level. So we get back to 'section'. */ - s->state = STATE_SECTION; - } - else { - s->state = STATE_PIPELINE; + state = state_pop(ctx); + + if (state == NULL) { + flb_error("no state left"); + return YAML_FAILURE; } break; default: - yaml_error_event(ctx, s, event); + yaml_error_event(ctx, state, event); return YAML_FAILURE; } break; @@ -938,336 +1319,324 @@ static int consume_event(struct flb_cf *cf, struct local_ctx *ctx, case STATE_PLUGIN_KEY: switch(event->type) { case YAML_SCALAR_EVENT: - s->state = STATE_PLUGIN_VAL; - value = (char *) event->data.scalar.value; - s->key = flb_sds_create(value); + /* Here is where we process all the plugin properties for customs, pipelines + * and processors. + */ + state = state_push_key(ctx, STATE_PLUGIN_VAL, (char *) event->data.scalar.value); + + if (state == NULL) { + flb_error("unable to allocate state"); + return YAML_FAILURE; + } break; case YAML_MAPPING_START_EVENT: - s->state = STATE_PLUGIN_TYPE; + state = state_pop(ctx); + + if (state == NULL) { + flb_error("no state left"); + return YAML_FAILURE; + } + + if (state->state != STATE_PLUGIN_START) { + yaml_error_event(ctx, state, event); + return YAML_FAILURE; + } break; case YAML_MAPPING_END_EVENT: - s->state = STATE_PLUGIN_TYPE; + state = state_pop(ctx); + + if (state == NULL) { + flb_error("no state left"); + return YAML_FAILURE; + } + + if (state->state != STATE_PLUGIN_START) { + yaml_error_event(ctx, state, event); + return YAML_FAILURE; + } break; case YAML_SEQUENCE_END_EVENT: + state = state_pop(ctx); + + if (state == NULL) { + flb_error("no state left"); + return YAML_FAILURE; + } break; default: - yaml_error_event(ctx, s, event); + yaml_error_event(ctx, state, event); return YAML_FAILURE; } break; - case STATE_INPUT_PROCESSOR: + case STATE_PLUGIN_VAL: switch(event->type) { - case YAML_MAPPING_START_EVENT: - break; - case YAML_MAPPING_END_EVENT: - s->state = STATE_PLUGIN_KEY; - break; - case YAML_SCALAR_EVENT: - /* remove 'processors' key, not longer needed */ - if (s->key) { - flb_sds_destroy(s->key); - s->key = NULL; - } - /* Check if we are entering a 'logs', 'metrics' or 'traces' section */ - value = (char *) event->data.scalar.value; - if (strcasecmp(value, "logs") == 0) { - /* logs state */ - s->state = STATE_INPUT_PROCESSOR_LOGS_KEY; + case YAML_SCALAR_EVENT: - /* create the array for definitions found under 'log' */ - s->cf_processor_type_array = cfl_array_create(1); - cfl_array_resizable(s->cf_processor_type_array, CFL_TRUE); + /* register key/value pair as a property */ + if (cfl_kvlist_insert_string(state->keyvals, state->key, (char *)event->data.scalar.value) < 0) { + flb_error("unable to insert string"); + return YAML_FAILURE; + } - cfl_kvlist_insert_array(s->cf_group->properties, "logs", s->cf_processor_type_array); - } - else if (strcasecmp(value, "metrics") == 0) { - /* metrics state */ - s->state = STATE_INPUT_PROCESSOR_METRICS_KEY; + state = state_pop(ctx); - /* create the array for definitions found under 'log' */ - s->cf_processor_type_array = cfl_array_create(1); - cfl_array_resizable(s->cf_processor_type_array, CFL_TRUE); + if (state == NULL) { + flb_error("no state left"); + return YAML_FAILURE; + } + break; + case YAML_SEQUENCE_START_EVENT: /* start a new group */ + state = state_push_witharr(ctx, state, STATE_PLUGIN_VAL_LIST); - cfl_kvlist_insert_array(s->cf_group->properties, "metrics", s->cf_processor_type_array); - } - else if (strcasecmp(value, "traces") == 0) { - /* metrics state */ - s->state = STATE_INPUT_PROCESSOR_TRACES_KEY; + if (state == NULL) { + flb_error("unable to allocate state"); + return YAML_FAILURE; + } + break; + case YAML_MAPPING_START_EVENT: - /* create the array for definitions found under 'log' */ - s->cf_processor_type_array = cfl_array_create(1); - cfl_array_resizable(s->cf_processor_type_array, CFL_TRUE); + if (strcmp(state->key, "processors") == 0) { + state = state_push(ctx, STATE_INPUT_PROCESSORS); - cfl_kvlist_insert_array(s->cf_group->properties, "traces", s->cf_processor_type_array); + if (state == NULL) { + flb_error("unable to allocate state"); + return YAML_FAILURE; } - else { - flb_error("[config] unknown processor '%s'", value); - yaml_error_event(ctx, s, event); + + if (state_create_group(conf, state, "processors") == YAML_FAILURE) { return YAML_FAILURE; } break; - default: - yaml_error_event(ctx, s, event); + } + + state = state_push(ctx, STATE_GROUP_KEY); + + if (state == NULL) { + flb_error("unable to allocate state"); return YAML_FAILURE; - }; - break; - case STATE_INPUT_PROCESSOR_LOGS_KEY: - switch(event->type) { - case YAML_SEQUENCE_START_EVENT: - break; - case YAML_SEQUENCE_END_EVENT: - s->state = STATE_INPUT_PROCESSOR; - break; - case YAML_MAPPING_START_EVENT: - s->cf_processor_type_list = cfl_kvlist_create(); - cfl_array_append_kvlist(s->cf_processor_type_array, s->cf_processor_type_list); - break; - case YAML_MAPPING_END_EVENT: - break; - case YAML_SCALAR_EVENT: - /* Check if we are entering a 'logs', 'metrics' or 'traces' section */ - value = (char *) event->data.scalar.value; - s->key = flb_sds_create(value); - s->state = STATE_INPUT_PROCESSOR_LOGS_VAL; - break; - default: - yaml_error_event(ctx, s, event); + } + /* create group */ + state->values = flb_cf_section_property_add_list(conf, + state->cf_section->properties, + state->key, flb_sds_len(state->key)); + + if (state->values == NULL) { + flb_error("no values"); return YAML_FAILURE; - }; - break; + } - case STATE_INPUT_PROCESSOR_LOGS_VAL: - switch(event->type) { - case YAML_SEQUENCE_START_EVENT: - s->state = STATE_INPUT_PROCESSOR_LOGS_KEY; - break; - case YAML_SEQUENCE_END_EVENT: - break; - case YAML_MAPPING_START_EVENT: - break; - case YAML_MAPPING_END_EVENT: - break; - case YAML_SCALAR_EVENT: - value = (char *) event->data.scalar.value; - if (!s->cf_processor_type_list || !s->key || !value) { - s->state = STATE_INPUT_PROCESSOR; - break; - } - cfl_kvlist_insert_string(s->cf_processor_type_list, s->key, value); - flb_sds_destroy(s->key); - s->key = NULL; - s->state = STATE_INPUT_PROCESSOR_LOGS_KEY; - break; - default: - yaml_error_event(ctx, s, event); + state->cf_group = flb_cf_group_create(conf, state->cf_section, state->key, strlen(state->key)); + + if (state->cf_group == NULL) { + flb_error("unable to create group"); return YAML_FAILURE; - }; - break; + } + break; + case YAML_SEQUENCE_END_EVENT: /* end of group */ + state = state_pop(ctx); - case STATE_INPUT_PROCESSOR_METRICS_KEY: - switch(event->type) { - case YAML_SEQUENCE_START_EVENT: - break; - case YAML_SEQUENCE_END_EVENT: - s->state = STATE_INPUT_PROCESSOR; - break; - case YAML_MAPPING_START_EVENT: - s->cf_processor_type_list = cfl_kvlist_create(); - cfl_array_append_kvlist(s->cf_processor_type_array, s->cf_processor_type_list); - break; - case YAML_MAPPING_END_EVENT: - break; - case YAML_SCALAR_EVENT: - value = (char *) event->data.scalar.value; - s->key = flb_sds_create(value); - s->state = STATE_INPUT_PROCESSOR_METRICS_VAL; - break; - default: - yaml_error_event(ctx, s, event); + if (state == NULL) { + flb_error("no state left"); return YAML_FAILURE; - }; + } + + if (state->state != STATE_PLUGIN_KEY) { + yaml_error_event(ctx, state, event); + return YAML_FAILURE; + } + + state = state_pop(ctx); + + if (state == NULL) { + flb_error("no state left"); + return YAML_FAILURE; + } + + if (state->state != STATE_PLUGIN_KEY) { + yaml_error_event(ctx, state, event); + return YAML_FAILURE; + } + break; + case YAML_MAPPING_END_EVENT: + state = state_pop(ctx); + + if (state == NULL) { + flb_error("no state left"); + return YAML_FAILURE; + } + break; + default: + yaml_error_event(ctx, state, event); + return YAML_FAILURE; + } break; - case STATE_INPUT_PROCESSOR_METRICS_VAL: + case STATE_PLUGIN_VAL_LIST: switch(event->type) { - case YAML_SEQUENCE_START_EVENT: - s->state = STATE_INPUT_PROCESSOR_METRICS_KEY; - break; - case YAML_SEQUENCE_END_EVENT: - break; - case YAML_MAPPING_START_EVENT: - break; - case YAML_MAPPING_END_EVENT: - break; - case YAML_SCALAR_EVENT: - value = (char *) event->data.scalar.value; - cfl_kvlist_insert_string(s->cf_processor_type_list, s->key, value); - flb_sds_destroy(s->key); - s->key = NULL; - s->val = NULL; - s->state = STATE_INPUT_PROCESSOR_METRICS_KEY; - break; - default: - yaml_error_event(ctx, s, event); + case YAML_SCALAR_EVENT: + + if (state->values == NULL) { + flb_error("unable to add values to list"); return YAML_FAILURE; - }; + } + + if (cfl_array_append_string(state->values, (char *)event->data.scalar.value) < 0) { + flb_error("unable to add values to list"); + return YAML_FAILURE; + } + break; + case YAML_SEQUENCE_END_EVENT: + + /* register key/value pair as a property */ + if (cfl_kvlist_insert_array(state->keyvals, state->key, state->values) < 0) { + flb_error("unable to insert key values"); + return YAML_FAILURE; + } + + state = state_pop(ctx); + + if (state == NULL) { + flb_error("no state left"); + return YAML_FAILURE; + } + + state = state_pop(ctx); + + if (state == NULL) { + flb_error("no state left"); + return YAML_FAILURE; + } + break; + default: + yaml_error_event(ctx, state, event); + return YAML_FAILURE; + } break; - case STATE_INPUT_PROCESSOR_TRACES_KEY: + case STATE_INPUT_PROCESSORS: switch(event->type) { - case YAML_SEQUENCE_START_EVENT: - break; - case YAML_SEQUENCE_END_EVENT: - s->state = STATE_INPUT_PROCESSOR; - break; case YAML_MAPPING_START_EVENT: - s->cf_processor_type_list = cfl_kvlist_create(); - cfl_array_append_kvlist(s->cf_processor_type_array, s->cf_processor_type_list); break; case YAML_MAPPING_END_EVENT: + + state = state_pop(ctx); + + if (state == NULL) { + flb_error("no state left"); + return YAML_FAILURE; + } + + state = state_pop(ctx); + + if (state == NULL) { + flb_error("no state left"); + return YAML_FAILURE; + } break; case YAML_SCALAR_EVENT: + + /* Check if we are entering a 'logs', 'metrics' or 'traces' section */ value = (char *) event->data.scalar.value; - s->key = flb_sds_create(value); - s->state = STATE_INPUT_PROCESSOR_TRACES_VAL; + + if (strcasecmp(value, "logs") == 0) { + /* logs state */ + state = state_push_key(ctx, STATE_INPUT_PROCESSOR, "logs"); + } + else if (strcasecmp(value, "metrics") == 0) { + /* metrics state */ + state = state_push_key(ctx, STATE_INPUT_PROCESSOR, "metrics"); + } + else if (strcasecmp(value, "traces") == 0) { + /* metrics state */ + state = state_push_key(ctx, STATE_INPUT_PROCESSOR, "traces"); + } + else { + flb_error("[config] unknown processor '%s'", value); + yaml_error_event(ctx, state, event); + return YAML_FAILURE; + } + + if (state == NULL) { + flb_error("unable to allocate state"); + return YAML_FAILURE; + } break; default: - yaml_error_event(ctx, s, event); + yaml_error_event(ctx, state, event); return YAML_FAILURE; }; break; - case STATE_INPUT_PROCESSOR_TRACES_VAL: + case STATE_INPUT_PROCESSOR: switch(event->type) { case YAML_SEQUENCE_START_EVENT: - s->state = STATE_INPUT_PROCESSOR_TRACES_KEY; break; case YAML_SEQUENCE_END_EVENT: + + state = state_pop(ctx); + + if (state == NULL) { + flb_error("no state left"); + return YAML_FAILURE; + } break; case YAML_MAPPING_START_EVENT: + + state = state_push_withvals(ctx, state, STATE_PLUGIN_START); + + if (state == NULL) { + flb_error("unable to allocate state"); + return YAML_FAILURE; + } + state->section = SECTION_PROCESSOR; break; case YAML_MAPPING_END_EVENT: - break; - case YAML_SCALAR_EVENT: - value = (char *) event->data.scalar.value; - cfl_kvlist_insert_string(s->cf_processor_type_list, s->key, value); - flb_sds_destroy(s->key); - s->key = NULL; - s->val = NULL; - s->state = STATE_INPUT_PROCESSOR_TRACES_KEY; + return YAML_FAILURE; break; default: - yaml_error_event(ctx, s, event); + yaml_error_event(ctx, state, event); return YAML_FAILURE; }; break; - case STATE_PLUGIN_VAL: + + /* groups: a group is a sub-section and here we handle the key/value pairs. */ + case STATE_GROUP_KEY: switch(event->type) { case YAML_SCALAR_EVENT: - s->state = STATE_PLUGIN_KEY; + /* grab current value (key) */ value = (char *) event->data.scalar.value; - s->val = flb_sds_create(value); - /* register key/value pair as a property */ - if (flb_cf_section_property_add(cf, s->cf_section->properties, - s->key, flb_sds_len(s->key), - s->val, flb_sds_len(s->val)) < 0) { - return YAML_FAILURE; - } - if (cfl_kvlist_count(s->cf_section->properties) <= 0) { - return YAML_FAILURE; - } - flb_sds_destroy(s->key); - flb_sds_destroy(s->val); - s->key = NULL; - s->val = NULL; - break; - case YAML_SEQUENCE_START_EVENT: /* start a new group */ - if (strcmp(s->key, "processors") == 0) { - yaml_error_event(ctx, s, event); - return YAML_FAILURE; - } - s->state = STATE_GROUP_KEY; - s->cf_group = flb_cf_group_create(cf, s->cf_section, - s->key, flb_sds_len(s->key)); - flb_sds_destroy(s->key); - if (!s->cf_group) { + state = state_push_key(ctx, STATE_GROUP_VAL, value); + + if (state == NULL) { + flb_error("unable to allocate state"); return YAML_FAILURE; } break; - case YAML_SEQUENCE_END_EVENT: /* end of group */ - s->state = STATE_PLUGIN_KEY; - break; case YAML_MAPPING_START_EVENT: - /* create group */ - s->cf_group = flb_cf_group_create(cf, s->cf_section, s->key, strlen(s->key)); - - /* Special handling for input processor */ - if (strcmp(s->key, "processors") == 0) { - s->state = STATE_INPUT_PROCESSOR; - break; - } - - s->state = STATE_GROUP_KEY; - s->values = flb_cf_section_property_add_list(cf, - s->cf_section->properties, - s->key, flb_sds_len(s->key)); - if (s->values == NULL) { - return YAML_FAILURE; - } - flb_sds_destroy(s->key); - s->key = NULL; break; case YAML_MAPPING_END_EVENT: - s->state = STATE_PLUGIN_KEY; - break; - default: - yaml_error_event(ctx, s, event); - return YAML_FAILURE; - } - break; - case STATE_PLUGIN_VAL_LIST: - switch(event->type) { - case YAML_SCALAR_EVENT: - if (s->values == NULL) { + state = state_pop(ctx); + + if (state == NULL) { + flb_error("no state left"); return YAML_FAILURE; } - cfl_array_append_string(s->values, (char *)event->data.scalar.value); - break; - case YAML_SEQUENCE_END_EVENT: - s->values = NULL; - s->state = STATE_PLUGIN_KEY; - break; - default: - yaml_error_event(ctx, s, event); - return YAML_FAILURE; - } - break; - /* groups: a group is a sub-section and here we handle the key/value pairs */ - case STATE_GROUP_KEY: - switch(event->type) { - case YAML_SCALAR_EVENT: - /* next state */ - s->state = STATE_GROUP_VAL; + /* This is also the end of the plugin values mapping. + * So we pop an additional state off the stack. + */ + state = state_pop(ctx); - /* grab current value (key) */ - value = (char *) event->data.scalar.value; - s->key = flb_sds_create(value); - break; - case YAML_MAPPING_START_EVENT: - break; - case YAML_MAPPING_END_EVENT: - s->state = STATE_PLUGIN_KEY; - break; - case YAML_SEQUENCE_END_EVENT: - s->state = STATE_PLUGIN_KEY; - s->cf_group = NULL; + if (state == NULL) { + flb_error("no state left"); + return YAML_FAILURE; + } break; default: - yaml_error_event(ctx, s, event); + yaml_error_event(ctx, state, event); return YAML_FAILURE; } break; @@ -1275,22 +1644,25 @@ static int consume_event(struct flb_cf *cf, struct local_ctx *ctx, case STATE_GROUP_VAL: switch(event->type) { case YAML_SCALAR_EVENT: - s->state = STATE_GROUP_KEY; value = (char *) event->data.scalar.value; - s->val = flb_sds_create(value); /* add the kv pair to the active group properties */ - flb_cf_section_property_add(cf, s->cf_group->properties, - s->key, flb_sds_len(s->key), - s->val, flb_sds_len(s->val)); - flb_sds_destroy(s->key); - flb_sds_destroy(s->val); - s->key = NULL; - s->val = NULL; + if (flb_cf_section_property_add(conf, state->cf_group->properties, + state->key, flb_sds_len(state->key), + value, strlen(value)) == NULL) { + flb_error("unable to add property"); + return YAML_FAILURE; + } + state = state_pop(ctx); + + if (state == NULL) { + flb_error("no state left"); + return YAML_FAILURE; + } break; default: - yaml_error_event(ctx, s, event); + yaml_error_event(ctx, state, event); return YAML_FAILURE; } break; @@ -1302,151 +1674,333 @@ static int consume_event(struct flb_cf *cf, struct local_ctx *ctx, return YAML_SUCCESS; } -static char *get_real_path(char *file, char *path, size_t size) +static struct parser_state *state_start(struct local_ctx *ctx, struct file_state *file) { - int len; - char *p; - char *end; + struct parser_state *state; -#ifdef _MSC_VER - p = _fullpath(path, file, size); -#else - p = realpath(file, path); -#endif + state = state_create(NULL, file); - if (!p) { - len = strlen(file); - if (len > size) { - return NULL; - } - memcpy(path, file, len); - path[len] = '\0'; + if (state != NULL) { + cfl_list_add(&state->_head, &ctx->states); } - /* lookup path ending and truncate */ -#ifdef _MSC_VER - end = strrchr(path, '\\'); -#else - end = strrchr(path, '/'); -#endif + return state; +} - if (end) { - end++; - *end = '\0'; +static struct parser_state *state_push(struct local_ctx *ctx, enum state state_num) +{ + struct parser_state *last = NULL; + struct parser_state *state; + + if (cfl_list_size(&ctx->states) <= 0) { + return NULL; } - return path; + last = cfl_list_entry_last(&ctx->states, struct parser_state, _head); + + if (last == NULL) { + return NULL; + } + + state = state_create(last->file, last->file); + + if (state == NULL) { + return NULL; + } + state->section = last->section; + state->keyvals = last->keyvals; + state->cf_section = last->cf_section; + state->cf_group = last->cf_group; + state->values = last->values; + state->file = last->file; + state->state = state_num; + state->level = last->level + 1; + state->key = last->key; + + cfl_list_add(&state->_head, &ctx->states); + return state; } -static void state_destroy(struct parser_state *s) +static struct parser_state *state_push_section(struct local_ctx *ctx, + enum state state_num, + enum section section) { - if (s->caller_file) { - flb_sds_destroy(s->caller_file); + struct parser_state *state; + + state = state_push(ctx, state_num); + + if (state == NULL) { + return NULL; } - if (s->caller_root_path) { - flb_sds_destroy(s->caller_root_path); + state->section = section; + + return state; +} + +static struct parser_state *state_push_key(struct local_ctx *ctx, + enum state state_num, + const char *key) +{ + struct parser_state *state; + flb_sds_t skey; + + if (key == NULL) { + return NULL; } - if (s->file) { - flb_sds_destroy(s->file); + skey = flb_sds_create(key); + + if (skey == NULL) { + return NULL; } - if (s->root_path) { - flb_sds_destroy(s->root_path); + state = state_push(ctx, state_num); + + if (state == NULL) { + flb_sds_destroy(skey); + return NULL; } - flb_free(s); + + state->key = skey; + state->allocation_flags |= HAS_KEY; + return state; } -static struct parser_state *state_create(char *caller_file, char *file) +static struct parser_state *state_push_withvals(struct local_ctx *ctx, + struct parser_state *parent, + enum state state_num) { - int ret; - char *p; - char file_path[PATH_MAX + 1] = {0}; - char caller_path[PATH_MAX + 1] = {0}; - struct parser_state *s; - struct stat st; + struct parser_state *state; + struct cfl_kvlist *kvlist; + + kvlist = cfl_kvlist_create(); - if (!file) { + if (kvlist == NULL) { return NULL; } - /* allocate context */ - s = flb_calloc(1, sizeof(struct parser_state)); - if (!s) { - flb_errno(); + state = state_push(ctx, state_num); + + if (state == NULL) { + cfl_kvlist_destroy(kvlist); return NULL; } - /* resolve real path for caller file and target file */ -#ifndef FLB_HAVE_STATIC_CONF - if (caller_file) { - p = get_real_path(caller_file, caller_path, PATH_MAX + 1); - if (!p) { - state_destroy(s); - return NULL; - } - s->caller_file = flb_sds_create(caller_file); - s->caller_root_path = flb_sds_create(caller_path); + state->keyvals = kvlist; + state->allocation_flags |= HAS_KEYVALS; + + return state; +} + +static struct parser_state *state_push_witharr(struct local_ctx *ctx, + struct parser_state *parent, + enum state state_num) +{ + struct parser_state *state; + + parent->values = cfl_array_create(4); + + if (parent->values == NULL) { + flb_error("parent has no values"); + return NULL; } - else { - s->caller_file = flb_sds_create(s->file); - s->caller_root_path = flb_sds_create(s->root_path); + + cfl_array_resizable(parent->values, CFL_TRUE); + + state = state_push(ctx, state_num); + + return state; +} + +static int state_create_section(struct flb_cf *conf, struct parser_state *state, char *name) +{ + + if (state == NULL || conf == NULL || name == NULL) { + return -1; + } + + state->cf_section = flb_cf_section_create(conf, name, 0); + + if (state->cf_section == NULL) { + return -1; + } + + return 0; +} + +static int state_create_group(struct flb_cf *conf, struct parser_state *state, char *name) +{ + if (state == NULL || conf == NULL || name == NULL) { + return -1; + } + + state->cf_group = flb_cf_group_create(conf, state->cf_section, + "processors", strlen("processors")); + + if (state->cf_group == NULL) { + return -1; + } + + return YAML_SUCCESS; +} + +static struct parser_state *state_pop(struct local_ctx *ctx) +{ + struct parser_state *last; + + if (ctx == NULL) { + return NULL; + } + + if (cfl_list_size(&ctx->states) <= 0) { + return NULL; + } + + last = cfl_list_entry_last(&ctx->states, struct parser_state, _head); + cfl_list_del(&last->_head); + + if (last->allocation_flags & HAS_KEY) { + flb_sds_destroy(last->key); } - /* check if the file exists */ - ret = stat(file, &st); - if (ret == 0) { - p = get_real_path(file, file_path, PATH_MAX + 1); - s->file = flb_sds_create(file); - s->root_path = flb_sds_create(file_path); + if (last->allocation_flags & HAS_KEYVALS) { + cfl_kvlist_destroy(last->keyvals); } - else if (errno == ENOENT && caller_file && s->caller_root_path != NULL) { - snprintf(file_path, PATH_MAX, "%s/%s", s->caller_root_path, file); - s->file = flb_sds_create(file_path); + + state_destroy(last); + + if (cfl_list_size(&ctx->states) <= 0) { + return NULL; + } + + return cfl_list_entry_last(&ctx->states, struct parser_state, _head); +} + +static void state_destroy(struct parser_state *s) +{ + flb_free(s); +} + +static struct parser_state *state_create(struct file_state *parent, struct file_state *file) +{ + struct parser_state *state; + + /* allocate context */ + state = flb_calloc(1, sizeof(struct parser_state)); + + if (!state) { + flb_errno(); + return NULL; } + + state->file = file; +#ifndef FLB_HAVE_STATIC_CONF + + if (parent) { + state->file->parent = parent; + } + +#else + + s->file->name = flb_sds_create("***static***"); + s->file->path = flb_sds_create("***static***"); + #endif - return s; + return state; } -static int read_config(struct flb_cf *cf, struct local_ctx *ctx, - char *caller_file, char *cfg_file) +static int read_config(struct flb_cf *conf, struct local_ctx *ctx, + struct file_state *parent, char *cfg_file) { int ret; int status; int code = 0; - char *file; struct parser_state *state; + flb_sds_t include_dir = NULL; + flb_sds_t include_file = NULL; yaml_parser_t parser; yaml_event_t event; FILE *fh; + struct file_state fstate; + + if (parent && cfg_file[0] != '/') { + + include_dir = flb_sds_create_size(strlen(cfg_file) + strlen(parent->path)); + + if (include_dir == NULL) { + flb_error("unable to create filename"); + return -1; + } + + if (flb_sds_printf(&include_dir, "%s/%s", parent->path, cfg_file) == NULL) { + flb_error("unable to create full filename"); + return -1; + } + + } + else { + + include_dir = flb_sds_create(cfg_file); + + if (include_dir == NULL) { + flb_error("unable to create filename"); + return -1; + } + } + + include_file = flb_sds_create(include_dir); + + if (include_file == NULL) { + flb_error("unable to create include filename"); + flb_sds_destroy(include_dir); + return -1; + } + + fstate.name = basename(include_dir); + fstate.path = dirname(include_dir); + + fstate.parent = parent; + + state = state_start(ctx, &fstate); - state = state_create(caller_file, cfg_file); if (!state) { + flb_error("unable to push initial include file state: %s", cfg_file); + flb_sds_destroy(include_dir); + flb_sds_destroy(include_file); return -1; } - file = state->file; /* check if this file has been included before */ - ret = is_file_included(ctx, file); + ret = is_file_included(ctx, include_file); + if (ret) { - flb_error("[config] file '%s' is already included", file); + flb_error("[config] file '%s' is already included", cfg_file); + flb_sds_destroy(include_dir); + flb_sds_destroy(include_file); state_destroy(state); return -1; } - fh = fopen(file, "r"); + flb_error("============ %s ============", cfg_file); + fh = fopen(include_file, "r"); + if (!fh) { flb_errno(); + flb_sds_destroy(include_dir); + flb_sds_destroy(include_file); state_destroy(state); return -1; } /* add file to the list of included files */ - ret = flb_slist_add(&ctx->includes, file); + ret = flb_slist_add(&ctx->includes, include_file); + if (ret == -1) { - flb_error("[config] could not register file %s", file); + flb_error("[config] could not register file %s", cfg_file); fclose(fh); + flb_sds_destroy(include_dir); + flb_sds_destroy(include_file); state_destroy(state); return -1; } @@ -1457,63 +2011,50 @@ static int read_config(struct flb_cf *cf, struct local_ctx *ctx, do { status = yaml_parser_parse(&parser, &event); + if (status == YAML_FAILURE) { - flb_error("[config] invalid YAML format in file %s", file); + flb_error("[config] invalid YAML format in file %s", cfg_file); code = -1; goto done; } - status = consume_event(cf, ctx, state, &event); + + status = consume_event(conf, ctx, &event); + if (status == YAML_FAILURE) { + flb_error("yaml error"); code = -1; goto done; } + yaml_event_delete(&event); + state = cfl_list_entry_last(&ctx->states, struct parser_state, _head); + } while (state->state != STATE_STOP); + flb_error("=============================="); done: + if (code == -1) { yaml_event_delete(&event); } yaml_parser_delete(&parser); - state_destroy(state); + state_pop(ctx); fclose(fh); ctx->level--; + flb_sds_destroy(include_file); + flb_sds_destroy(include_dir); + return code; } -static int local_init(struct local_ctx *ctx, char *file) +static int local_init(struct local_ctx *ctx) { - char *end; - char path[PATH_MAX + 1] = {0}; - /* reset the state */ memset(ctx, '\0', sizeof(struct local_ctx)); - -#ifndef FLB_HAVE_STATIC_CONF - char *p; - - if (file) { -#ifdef _MSC_VER - p = _fullpath(path, file, PATH_MAX + 1); -#else - p = realpath(file, path); -#endif - if (!p) { - return -1; - } - } -#endif - - /* lookup path ending and truncate */ - end = strrchr(path, '/'); - if (end) { - end++; - *end = '\0'; - } - + cfl_list_init(&ctx->states); ctx->level = 0; flb_slist_create(&ctx->includes); @@ -1525,34 +2066,37 @@ static void local_exit(struct local_ctx *ctx) flb_slist_destroy(&ctx->includes); } -struct flb_cf *flb_cf_yaml_create(struct flb_cf *cf, char *file_path, +struct flb_cf *flb_cf_yaml_create(struct flb_cf *conf, char *file_path, char *buf, size_t size) { int ret; struct local_ctx ctx; - if (!cf) { - cf = flb_cf_create(); - if (!cf) { + if (!conf) { + conf = flb_cf_create(); + + if (!conf) { return NULL; } } /* initialize the parser state */ - ret = local_init(&ctx, file_path); + ret = local_init(&ctx); + if (ret == -1) { - flb_cf_destroy(cf); + flb_cf_destroy(conf); return NULL; } /* process the entry poing config file */ - ret = read_config(cf, &ctx, NULL, file_path); + ret = read_config(conf, &ctx, NULL, file_path); + if (ret == -1) { - flb_cf_destroy(cf); + flb_cf_destroy(conf); local_exit(&ctx); return NULL; } local_exit(&ctx); - return cf; + return conf; } diff --git a/src/config_format/flb_config_format.c b/src/config_format/flb_config_format.c index af4f56b9d27..8ae8477475e 100644 --- a/src/config_format/flb_config_format.c +++ b/src/config_format/flb_config_format.c @@ -449,6 +449,10 @@ struct flb_cf_group *flb_cf_group_create(struct flb_cf *cf, struct flb_cf_sectio /* initialize lists */ g->properties = cfl_kvlist_create(); + if (g->properties == NULL) { + flb_free(g); + return NULL; + } /* determinate type by name */ if (len <= 0) { @@ -458,6 +462,7 @@ struct flb_cf_group *flb_cf_group_create(struct flb_cf *cf, struct flb_cf_sectio /* create a NULL terminated name */ g->name = flb_sds_create_len(name, len); if (!g->name) { + cfl_kvlist_destroy(g->properties); flb_free(g); return NULL; } diff --git a/src/flb_processor.c b/src/flb_processor.c index c1ece6f6de3..3a4f578e5e3 100644 --- a/src/flb_processor.c +++ b/src/flb_processor.c @@ -42,6 +42,7 @@ static int acquire_lock(pthread_mutex_t *lock, result = pthread_mutex_lock(lock); if (result != 0) { + if (result == EAGAIN) { retry_count++; @@ -75,6 +76,7 @@ static int release_lock(pthread_mutex_t *lock, result = pthread_mutex_unlock(lock); if (result != 0) { + if (result == EAGAIN) { retry_count++; @@ -110,10 +112,12 @@ struct flb_processor *flb_processor_create(struct flb_config *config, struct flb_processor *proc; proc = flb_calloc(1, sizeof(struct flb_processor)); + if (!proc) { flb_errno(); return NULL; } + proc->config = config; proc->is_active = FLB_FALSE; proc->data = source_plugin_instance; @@ -165,13 +169,16 @@ struct flb_processor_unit *flb_processor_unit_create(struct flb_processor *proc, /* allocate and initialize processor unit context */ pu = flb_calloc(1, sizeof(struct flb_processor_unit)); + if (!pu) { flb_errno(); return NULL; } + pu->parent = proc; pu->event_type = event_type; pu->name = flb_sds_create(unit_name); + if (!pu->name) { flb_free(pu); return NULL; @@ -191,6 +198,7 @@ struct flb_processor_unit *flb_processor_unit_create(struct flb_processor *proc, if (f) { /* create an instance of the filter */ f_ins = flb_filter_new(config, unit_name, NULL); + if (!f_ins) { pthread_mutex_destroy(&pu->lock); flb_sds_destroy(pu->name); @@ -264,15 +272,34 @@ struct flb_processor_unit *flb_processor_unit_create(struct flb_processor *proc, return pu; } -int flb_processor_unit_set_property(struct flb_processor_unit *pu, const char *k, const char *v) +int flb_processor_unit_set_property(struct flb_processor_unit *pu, const char *k, struct cfl_variant *v) { + struct cfl_variant *val; + int i; + int ret; + if (pu->unit_type == FLB_PROCESSOR_UNIT_FILTER) { - return flb_filter_set_property(pu->ctx, k, v); + + if (v->type == CFL_VARIANT_STRING) { + return flb_filter_set_property(pu->ctx, k, v->data.as_string); + } + else if (v->type == CFL_VARIANT_ARRAY) { + + for (i = 0; i < v->data.as_array->entry_count; i++) { + val = v->data.as_array->entries[i]; + ret = flb_filter_set_property(pu->ctx, k, val->data.as_string); + + if (ret == -1) { + return ret; + } + } + return 0; + } } return flb_processor_instance_set_property( (struct flb_processor_instance *) pu->ctx, - k, v); + k, v->data.as_string); } void flb_processor_unit_destroy(struct flb_processor_unit *pu) @@ -308,7 +335,8 @@ int flb_processor_unit_init(struct flb_processor_unit *pu) if (pu->unit_type == FLB_PROCESSOR_UNIT_FILTER) { ret = flb_filter_init(proc->config, pu->ctx); - if (ret == -1) { + + if (ret == -1) { flb_error("[processor] error initializing unit filter %s", pu->name); return -1; } @@ -343,7 +371,8 @@ int flb_processor_init(struct flb_processor *proc) mk_list_foreach(head, &proc->logs) { pu = mk_list_entry(head, struct flb_processor_unit, _head); ret = flb_processor_unit_init(pu); - if (ret == -1) { + + if (ret == -1) { return -1; } count++; @@ -352,7 +381,8 @@ int flb_processor_init(struct flb_processor *proc) mk_list_foreach(head, &proc->metrics) { pu = mk_list_entry(head, struct flb_processor_unit, _head); ret = flb_processor_unit_init(pu); - if (ret == -1) { + + if (ret == -1) { return -1; } count++; @@ -361,7 +391,8 @@ int flb_processor_init(struct flb_processor *proc) mk_list_foreach(head, &proc->traces) { pu = mk_list_entry(head, struct flb_processor_unit, _head); ret = flb_processor_unit_init(pu); - if (ret == -1) { + + if (ret == -1) { return -1; } count++; @@ -469,7 +500,8 @@ int flb_processor_run(struct flb_processor *proc, * */ if (ret == FLB_FILTER_MODIFIED) { - /* release intermediate buffer */ + + /* release intermediate buffer */ if (cur_buf != data) { flb_free(cur_buf); } @@ -582,7 +614,8 @@ int flb_processor_run(struct flb_processor *proc, } } else if (type == FLB_PROCESSOR_METRICS) { - if (p_ins->p->cb_process_metrics != NULL) { + + if (p_ins->p->cb_process_metrics != NULL) { ret = p_ins->p->cb_process_metrics(p_ins, (struct cmt *) cur_buf, tag, @@ -598,7 +631,8 @@ int flb_processor_run(struct flb_processor *proc, } } else if (type == FLB_PROCESSOR_TRACES) { - if (p_ins->p->cb_process_traces != NULL) { + + if (p_ins->p->cb_process_traces != NULL) { ret = p_ins->p->cb_process_traces(p_ins, (struct ctrace *) cur_buf, tag, @@ -680,7 +714,8 @@ static int load_from_config_format_group(struct flb_processor *proc, int type, s for (i = 0; i < array->entry_count; i++) { /* every entry in the array must be a map */ tmp = array->entries[i]; - if (tmp->type != CFL_VARIANT_KVLIST) { + + if (tmp->type != CFL_VARIANT_KVLIST) { return -1; } @@ -688,7 +723,8 @@ static int load_from_config_format_group(struct flb_processor *proc, int type, s /* get the processor name, this is a mandatory config field */ tmp = cfl_kvlist_fetch(kvlist, "name"); - if (!tmp) { + + if (!tmp) { flb_error("processor configuration don't have a 'name' defined"); return -1; } @@ -696,7 +732,8 @@ static int load_from_config_format_group(struct flb_processor *proc, int type, s /* create the processor unit and load all the properties */ name = tmp->data.as_string; pu = flb_processor_unit_create(proc, type, name); - if (!pu) { + + if (!pu) { flb_error("cannot create '%s' processor unit", name); return -1; } @@ -704,28 +741,29 @@ static int load_from_config_format_group(struct flb_processor *proc, int type, s /* iterate list of properties and set each one (skip name) */ cfl_list_foreach(head, &kvlist->list) { pair = cfl_list_entry(head, struct cfl_kvpair, _head); - if (strcmp(pair->key, "name") == 0) { + + if (strcmp(pair->key, "name") == 0) { continue; } - if (pair->val->type != CFL_VARIANT_STRING) { - continue; - } /* If filter plugin in processor unit has its own match rule, * we must release the pre-allocated '*' match at first. */ if (pu->unit_type == FLB_PROCESSOR_UNIT_FILTER) { - if (strcmp(pair->key, "match") == 0) { + + if (strcmp(pair->key, "match") == 0) { f_ins = (struct flb_filter_instance *)pu->ctx; - if (f_ins->match != NULL) { + + if (f_ins->match != NULL) { flb_sds_destroy(f_ins->match); f_ins->match = NULL; } } } - ret = flb_processor_unit_set_property(pu, pair->key, pair->val->data.as_string); - if (ret == -1) { + ret = flb_processor_unit_set_property(pu, pair->key, pair->val); + + if (ret == -1) { flb_error("cannot set property '%s' for processor '%s'", pair->key, name); return -1; } @@ -744,9 +782,11 @@ int flb_processors_load_from_config_format_group(struct flb_processor *proc, str /* logs */ val = cfl_kvlist_fetch(g->properties, "logs"); + if (val) { ret = load_from_config_format_group(proc, FLB_PROCESSOR_LOGS, val); - if (ret == -1) { + + if (ret == -1) { flb_error("failed to load 'logs' processors"); return -1; } @@ -754,9 +794,11 @@ int flb_processors_load_from_config_format_group(struct flb_processor *proc, str /* metrics */ val = cfl_kvlist_fetch(g->properties, "metrics"); + if (val) { ret = load_from_config_format_group(proc, FLB_PROCESSOR_METRICS, val); - if (ret == -1) { + + if (ret == -1) { flb_error("failed to load 'metrics' processors"); return -1; } @@ -766,7 +808,8 @@ int flb_processors_load_from_config_format_group(struct flb_processor *proc, str val = cfl_kvlist_fetch(g->properties, "traces"); if (val) { ret = load_from_config_format_group(proc, FLB_PROCESSOR_TRACES, val); - if (ret == -1) { + + if (ret == -1) { flb_error("failed to load 'traces' processors"); return -1; } @@ -805,6 +848,7 @@ int flb_processor_instance_set_property(struct flb_processor_instance *ins, len = strlen(k); tmp = flb_env_var_translate(ins->config->env, v); + if (!tmp) { return -1; } @@ -815,7 +859,8 @@ int flb_processor_instance_set_property(struct flb_processor_instance *ins, else if (prop_key_check("log_level", k, len) == 0 && tmp) { ret = flb_log_get_level_str(tmp); flb_sds_destroy(tmp); - if (ret == -1) { + + if (ret == -1) { return -1; } ins->log_level = ret; @@ -826,8 +871,10 @@ int flb_processor_instance_set_property(struct flb_processor_instance *ins, * map it directly to avoid an extra memory allocation. */ kv = flb_kv_item_create(&ins->properties, (char *) k, NULL); - if (!kv) { - if (tmp) { + + if (!kv) { + + if (tmp) { flb_sds_destroy(tmp); } return -1; @@ -860,6 +907,7 @@ struct flb_processor_instance *flb_processor_instance_create( mk_list_foreach(head, &config->processor_plugins) { plugin = mk_list_entry(head, struct flb_processor_plugin, _head); + if (strcasecmp(plugin->name, name) == 0) { break; } @@ -871,6 +919,7 @@ struct flb_processor_instance *flb_processor_instance_create( } instance = flb_calloc(1, sizeof(struct flb_filter_instance)); + if (!instance) { flb_errno(); return NULL; @@ -954,7 +1003,8 @@ int flb_processor_instance_check_properties( * instance in question. */ config_map = flb_config_map_create(config, p->config_map); - if (!config_map) { + + if (!config_map) { flb_error("[native processor] error loading config map for '%s' plugin", p->name); return -1; @@ -965,8 +1015,10 @@ int flb_processor_instance_check_properties( ret = flb_config_map_properties_check(ins->p->name, &ins->properties, ins->config_map); - if (ret == -1) { - if (config->program_name) { + + if (ret == -1) { + + if (config->program_name) { flb_helper("try the command: %s -F %s -h\n", config->program_name, ins->p->name); } diff --git a/tests/internal/config_format_yaml.c b/tests/internal/config_format_yaml.c index 126cb4f0899..dac39f7d24c 100644 --- a/tests/internal/config_format_yaml.c +++ b/tests/internal/config_format_yaml.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -10,8 +11,22 @@ #include "flb_tests_internal.h" -#define FLB_000 FLB_TESTS_DATA_PATH "/data/config_format/yaml/fluent-bit.yaml" -#define FLB_001 FLB_TESTS_DATA_PATH "/data/config_format/yaml/issue_7559.yaml" +#define FLB_TESTS_CONF_PATH FLB_TESTS_DATA_PATH "/data/config_format/yaml" +#define FLB_000 FLB_TESTS_CONF_PATH "/fluent-bit.yaml" +#define FLB_001 FLB_TESTS_CONF_PATH "/issue_7559.yaml" + +/* + * Configurations to test: + * * basic single input to single output + * * basic single input to single output with a filter + * * includes + * * slist + * * conf parsers + * * yaml parsers + * * customs + * * service + * * env + */ /* data/config_format/fluent-bit.yaml */ void test_basic() @@ -20,6 +35,8 @@ void test_basic() struct flb_cf *cf; struct flb_cf_section *s; struct flb_cf_group *g; + struct cfl_variant *v; + int idx = 0; cf = flb_cf_yaml_create(NULL, FLB_000, NULL, 0); TEST_CHECK(cf != NULL); @@ -45,6 +62,69 @@ void test_basic() TEST_CHECK(mk_list_size(&cf->outputs) == 2); TEST_CHECK(mk_list_size(&cf->others) == 1); + /* check inputs */ + idx = 0; + mk_list_foreach(head, &cf->inputs) { + s = mk_list_entry(head, struct flb_cf_section, _head_section); + switch (idx) { + case 0: + v = flb_cf_section_property_get(cf, s, "name"); + TEST_CHECK(v->type == CFL_VARIANT_STRING); + TEST_CHECK(strcmp(v->data.as_string, "dummy") == 0); + break; + case 1: + v = flb_cf_section_property_get(cf, s, "name"); + TEST_CHECK(v->type == CFL_VARIANT_STRING); + TEST_CHECK(strcmp(v->data.as_string, "tail") == 0); + v = flb_cf_section_property_get(cf, s, "path"); + TEST_CHECK(v->type == CFL_VARIANT_STRING); + TEST_CHECK(strcmp(v->data.as_string, "./test.log") == 0); + break; + case 2: + v = flb_cf_section_property_get(cf, s, "name"); + TEST_CHECK(v->type == CFL_VARIANT_STRING); + TEST_CHECK(strcmp(v->data.as_string, "tail") == 0); + v = flb_cf_section_property_get(cf, s, "path"); + TEST_CHECK(v->type == CFL_VARIANT_STRING); + TEST_CHECK(strcmp(v->data.as_string, "./test.log") == 0); + break; + } + idx++; + } + + /* check outputs */ + idx = 0; + mk_list_foreach(head, &cf->outputs) { + s = mk_list_entry(head, struct flb_cf_section, _head_section); + switch (idx) { + case 0: + v = flb_cf_section_property_get(cf, s, "name"); + TEST_CHECK(v->type == CFL_VARIANT_STRING); + TEST_CHECK(strcmp(v->data.as_string, "stdout") == 0); + break; + case 1: + v = flb_cf_section_property_get(cf, s, "name"); + TEST_CHECK(v->type == CFL_VARIANT_STRING); + TEST_CHECK(strcmp(v->data.as_string, "stdout") == 0); + break; + } + idx++; + } + + /* check filters */ + idx = 0; + mk_list_foreach(head, &cf->filters) { + s = mk_list_entry(head, struct flb_cf_section, _head_section); + switch (idx) { + case 0: + v = flb_cf_section_property_get(cf, s, "name"); + TEST_CHECK(v->type == CFL_VARIANT_STRING); + TEST_CHECK(strcmp(v->data.as_string, "record_modifier") == 0); + break; + } + idx++; + } + /* groups */ s = flb_cf_section_get_by_name(cf, "input"); TEST_CHECK(s != NULL); @@ -87,8 +167,114 @@ void test_customs_section() flb_cf_destroy(cf); } +void test_slist_even() +{ + struct flb_cf *cf; + struct flb_cf_section *s; + struct cfl_variant *v; + struct mk_list *head; + + cf = flb_cf_yaml_create(NULL, FLB_TESTS_CONF_PATH "/pipelines/slist/even.yaml", NULL, 0); + TEST_CHECK(cf != NULL); + if (!cf) { + exit(EXIT_FAILURE); + } + + /* Total number of inputs */ + if(!TEST_CHECK(mk_list_size(&cf->inputs) == 1)) { + TEST_MSG("Section number error. Got=%d expect=1", mk_list_size(&cf->inputs)); + } + + mk_list_foreach(head, &cf->inputs) { + s = mk_list_entry(head, struct flb_cf_section, _head_section); + TEST_CHECK(s != NULL); + + v = flb_cf_section_property_get(cf, s, "success_header"); + TEST_CHECK(v->type == CFL_VARIANT_ARRAY); + if (!TEST_CHECK(v->data.as_array->entry_count == 2)) { + TEST_MSG("Section number error. Got=%lud expect=2", v->data.as_array->entry_count); + } + } + + flb_cf_dump(cf); + flb_cf_destroy(cf); +} + +void test_slist_odd() +{ + struct flb_cf *cf; + struct flb_cf_section *s; + struct cfl_variant *v; + struct mk_list *head; + + cf = flb_cf_yaml_create(NULL, FLB_TESTS_CONF_PATH "/pipelines/slist/odd.yaml", NULL, 0); + TEST_CHECK(cf != NULL); + if (!cf) { + exit(EXIT_FAILURE); + } + + /* Total number of inputs */ + if(!TEST_CHECK(mk_list_size(&cf->inputs) == 1)) { + TEST_MSG("Section number error. Got=%d expect=1", mk_list_size(&cf->inputs)); + } + + mk_list_foreach(head, &cf->inputs) { + s = mk_list_entry(head, struct flb_cf_section, _head_section); + TEST_CHECK(s != NULL); + + v = flb_cf_section_property_get(cf, s, "success_header"); + TEST_CHECK(v->type == CFL_VARIANT_ARRAY); + if (!TEST_CHECK(v->data.as_array->entry_count == 3)) { + TEST_MSG("Section number error. Got=%lud expect=3", v->data.as_array->entry_count); + } + } + + flb_cf_dump(cf); + flb_cf_destroy(cf); +} + +void test_parser_conf() +{ + struct flb_cf *cf; + struct flb_config *config; + int ret; + int cnt; + + cf = flb_cf_yaml_create(NULL, FLB_TESTS_CONF_PATH "/parsers/parsers-conf.yaml", NULL, 0); + TEST_CHECK(cf != NULL); + if (!cf) { + exit(EXIT_FAILURE); + } + + config = flb_config_init(); + TEST_CHECK(config != NULL); + config->conf_path = flb_strdup(FLB_TESTS_CONF_PATH "/parsers/"); + + // count the parsers registered automatically by fluent-bit + cnt = mk_list_size(&config->parsers); + // load the parsers from the configuration + ret = flb_config_load_config_format(config, cf); + if (ret != 0) { + exit(EXIT_FAILURE);; + } + + /* Total number of inputs */ + if(!TEST_CHECK(mk_list_size(&config->parsers) == cnt+1)) { + TEST_MSG("Section number error. Got=%d expect=%d", + mk_list_size(&config->parsers), + cnt+1); + } + + flb_cf_dump(cf); + flb_cf_destroy(cf); + flb_config_exit(config); +} + TEST_LIST = { { "basic" , test_basic}, { "customs section", test_customs_section}, + { "slist odd", test_slist_odd}, + { "slist even", test_slist_even}, + { "parsers file conf", test_parser_conf}, { 0 } }; diff --git a/tests/internal/data/config_format/yaml/fluent-bit.yaml b/tests/internal/data/config_format/yaml/fluent-bit.yaml index eee5a907629..49894552fc6 100644 --- a/tests/internal/data/config_format/yaml/fluent-bit.yaml +++ b/tests/internal/data/config_format/yaml/fluent-bit.yaml @@ -5,25 +5,25 @@ includes: - service.yaml customs: - - ${observability}: - api_key: zyJUb2tlbklEItoiY2ZlMTcx + - name: ${observability} + api_key: zyJUb2tlbklEItoiY2ZlMTcx pipeline: inputs: - - tail: - path: ./test.log - parser: json - read_from_head: true - - tail: - path: ./test.log - parser: json - read_from_head: true + - name: tail + path: ./test.log + parser: json + read_from_head: true + - name: tail + path: ./test.log + parser: json + read_from_head: true filters: - - record_modifier: - match: "*" - record: powered_by calyptia + - name: record_modifier + match: "*" + record: powered_by calyptia outputs: - - stdout: - match: "*" + - name: stdout + match: "*" diff --git a/tests/internal/data/config_format/yaml/parsers/parsers-conf.yaml b/tests/internal/data/config_format/yaml/parsers/parsers-conf.yaml new file mode 100644 index 00000000000..6421a8a1f85 --- /dev/null +++ b/tests/internal/data/config_format/yaml/parsers/parsers-conf.yaml @@ -0,0 +1,3 @@ +--- +service: + parsers_file: parsers.conf diff --git a/tests/internal/data/config_format/yaml/parsers/parsers.conf b/tests/internal/data/config_format/yaml/parsers/parsers.conf new file mode 100644 index 00000000000..9f3b6b33102 --- /dev/null +++ b/tests/internal/data/config_format/yaml/parsers/parsers.conf @@ -0,0 +1,6 @@ +[PARSER] + Name docker + Format json + Time_Key time + Time_Format %Y-%m-%dT%H:%M:%S.%L + Time_Keep On diff --git a/tests/internal/data/config_format/yaml/pipelines/slist/even.yaml b/tests/internal/data/config_format/yaml/pipelines/slist/even.yaml new file mode 100644 index 00000000000..5d5b7c46f3e --- /dev/null +++ b/tests/internal/data/config_format/yaml/pipelines/slist/even.yaml @@ -0,0 +1,7 @@ +--- +pipeline: + inputs: + - name: http + success_header: + - foo bar + - bar foo diff --git a/tests/internal/data/config_format/yaml/pipelines/slist/odd.yaml b/tests/internal/data/config_format/yaml/pipelines/slist/odd.yaml new file mode 100644 index 00000000000..a7d2058c9a5 --- /dev/null +++ b/tests/internal/data/config_format/yaml/pipelines/slist/odd.yaml @@ -0,0 +1,8 @@ +--- +pipeline: + inputs: + - name: http + success_header: + - foo bar + - bar foo + - foobar barfoo diff --git a/tests/internal/processor.c b/tests/internal/processor.c index 9a8952052ea..679fd131b8d 100644 --- a/tests/internal/processor.c +++ b/tests/internal/processor.c @@ -67,11 +67,20 @@ static void processor() size_t mp_size; void *out_buf = NULL; size_t out_size; + flb_sds_t hostname_prop_key; + struct cfl_variant var = { + .type = CFL_VARIANT_STRING, + .data.as_string = NULL, + }; printf("\n\n"); flb_init_env(); + hostname_prop_key = flb_sds_create("hostname monox"); + TEST_CHECK(hostname_prop_key != NULL); + var.data.as_string = hostname_prop_key; + config = flb_config_init(); TEST_CHECK(config != NULL); @@ -84,7 +93,7 @@ static void processor() pu = flb_processor_unit_create(proc, FLB_PROCESSOR_LOGS, "modify"); TEST_CHECK(pu != NULL); - ret = flb_processor_unit_set_property(pu, "add", "hostname monox"); + ret = flb_processor_unit_set_property(pu, "add", &var); TEST_CHECK(ret == 0); pu = flb_processor_unit_create(proc, FLB_PROCESSOR_LOGS, "stdout"); @@ -107,6 +116,7 @@ static void processor() flb_processor_destroy(proc); flb_config_exit(config); + flb_sds_destroy(hostname_prop_key); } TEST_LIST = { From 4c37d914cb50b2135ea76c2dc1c16be9418ae0d4 Mon Sep 17 00:00:00 2001 From: David Korczynski Date: Wed, 9 Aug 2023 14:48:22 -0700 Subject: [PATCH 180/315] tests: internal: fuzzers: add config yaml fuzzer Signed-off-by: David Korczynski --- CMakeLists.txt | 2 - tests/internal/fuzzers/CMakeLists.txt | 1 + tests/internal/fuzzers/config_yaml_fuzzer.c | 65 +++++++++++++++++++++ 3 files changed, 66 insertions(+), 2 deletions(-) create mode 100644 tests/internal/fuzzers/config_yaml_fuzzer.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 8d723fc0da5..a0369817cce 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -375,8 +375,6 @@ endif() if (FLB_TESTS_OSSFUZZ) FLB_DEFINITION(FLB_HAVE_TESTS_OSSFUZZ) - # Disable for fuzz testing - set(FLB_CONFIG_YAML Off) endif() if (FLB_WASM) diff --git a/tests/internal/fuzzers/CMakeLists.txt b/tests/internal/fuzzers/CMakeLists.txt index e61ff698277..4f2600b1336 100644 --- a/tests/internal/fuzzers/CMakeLists.txt +++ b/tests/internal/fuzzers/CMakeLists.txt @@ -24,6 +24,7 @@ set(UNIT_TESTS_FILES utils_fuzzer.c config_map_fuzzer.c record_ac_fuzzer.c + config_yaml_fuzzer.c ) # Prepare list of unit tests diff --git a/tests/internal/fuzzers/config_yaml_fuzzer.c b/tests/internal/fuzzers/config_yaml_fuzzer.c new file mode 100644 index 00000000000..99e17ba64b5 --- /dev/null +++ b/tests/internal/fuzzers/config_yaml_fuzzer.c @@ -0,0 +1,65 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Fluent Bit + * ========== + * Copyright (C) 2015-2023 The Fluent Bit Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +#include +#include + +#include "flb_fuzz_header.h" + + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + /* Set fuzzer-malloc chance of failure */ + flb_malloc_p = 0; + flb_malloc_mod = 25000; + + /* Limit the size of the config files to 32KB. */ + if (size > 32768) { + return 0; + } + + /* Write the config file to a location we know OSS-Fuzz has */ + char filename[256]; + sprintf(filename, "/tmp/libfuzzer.%d.yaml", getpid()); + FILE *fp = fopen(filename, "wb"); + if (!fp) { + return 0; + } + fwrite(data, size, 1, fp); + fclose(fp); + + + struct flb_cf *cf; + struct flb_cf_section *s; + + cf = flb_cf_yaml_create(NULL, filename, NULL, 0); + if (cf != NULL) { + flb_cf_destroy(cf); + } + + /* clean up the file */ + unlink(filename); + + return 0; +} From 29593b0262d473e0a9221780358f853583ca4384 Mon Sep 17 00:00:00 2001 From: David Korczynski Date: Fri, 11 Aug 2023 04:08:28 -0700 Subject: [PATCH 181/315] tests: internal: fuzzers: add mp fuzzer Signed-off-by: David Korczynski --- tests/internal/fuzzers/CMakeLists.txt | 1 + tests/internal/fuzzers/flb_mp_fuzzer.c | 55 ++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 tests/internal/fuzzers/flb_mp_fuzzer.c diff --git a/tests/internal/fuzzers/CMakeLists.txt b/tests/internal/fuzzers/CMakeLists.txt index 4f2600b1336..b3c4ce9bb42 100644 --- a/tests/internal/fuzzers/CMakeLists.txt +++ b/tests/internal/fuzzers/CMakeLists.txt @@ -10,6 +10,7 @@ set(UNIT_TESTS_FILES input_fuzzer.c signv4_fuzzer.c flb_json_fuzzer.c + flb_mp_fuzzer.c filter_stdout_fuzzer.c parser_fuzzer.c parse_json_fuzzer.c diff --git a/tests/internal/fuzzers/flb_mp_fuzzer.c b/tests/internal/fuzzers/flb_mp_fuzzer.c new file mode 100644 index 00000000000..b33c90407f5 --- /dev/null +++ b/tests/internal/fuzzers/flb_mp_fuzzer.c @@ -0,0 +1,55 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Fluent Bit + * ========== + * Copyright (C) 2015-2023 The Fluent Bit Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include +#include + +#include "flb_fuzz_header.h" + +int LLVMFuzzerTestOneInput(unsigned char *data, size_t size) +{ + /* Set flb_malloc_mod to be fuzzer-data dependent */ + if (size < 5) { + return 0; + } + flb_malloc_p = 0; + flb_malloc_mod = *(int*)data; + data += 4; + size -= 4; + + /* Avoid division by zero for modulo operations */ + if (flb_malloc_mod == 0) { + flb_malloc_mod = 1; + } + + unsigned char decider = *data; + data++; + size--; + + int out_records; + size_t processed_bytes; + if (decider % 2 == 0) { + flb_mp_validate_log_chunk(data, size, &out_records, &processed_bytes); + } + else if (decider % 2 == 1) { + flb_mp_validate_metric_chunk(data, size, &out_records, &processed_bytes); + } + return 0; +} From 8ce503739e6a831218b49e8ba9786722c69a9f36 Mon Sep 17 00:00:00 2001 From: Jeff Date: Tue, 8 Aug 2023 18:13:16 +0000 Subject: [PATCH 182/315] emitter_create: exit and destroy instance on fail Signed-off-by: Jeff --- plugins/filter_multiline/ml.c | 2 ++ plugins/filter_rewrite_tag/rewrite_tag.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/plugins/filter_multiline/ml.c b/plugins/filter_multiline/ml.c index 2980de89f0a..b63282628d5 100644 --- a/plugins/filter_multiline/ml.c +++ b/plugins/filter_multiline/ml.c @@ -97,6 +97,8 @@ static int emitter_create(struct ml_ctx *ctx) if (ret == -1) { flb_plg_error(ctx->ins, "cannot initialize storage for stream '%s'", ctx->emitter_name); + flb_input_instance_exit(ins, ctx->config); + flb_input_instance_destroy(ins); return -1; } ctx->ins_emitter = ins; diff --git a/plugins/filter_rewrite_tag/rewrite_tag.c b/plugins/filter_rewrite_tag/rewrite_tag.c index febeaeb3d03..5969d1582b1 100644 --- a/plugins/filter_rewrite_tag/rewrite_tag.c +++ b/plugins/filter_rewrite_tag/rewrite_tag.c @@ -97,6 +97,8 @@ static int emitter_create(struct flb_rewrite_tag *ctx) if (ret == -1) { flb_plg_error(ctx->ins, "cannot initialize storage for stream '%s'", ctx->emitter_name); + flb_input_instance_exit(ins, ctx->config); + flb_input_instance_destroy(ins); return -1; } ctx->ins_emitter = ins; From 88471cc32d2a2d22217b87cc018f438253580f3f Mon Sep 17 00:00:00 2001 From: David Korczynski Date: Tue, 8 Aug 2023 11:04:38 -0700 Subject: [PATCH 183/315] out_kinesis_streams: remove dead stores `tmp_size` is assigned twice where each of the assignments are not used. Signed-off-by: David Korczynski --- plugins/out_kinesis_streams/kinesis_api.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/plugins/out_kinesis_streams/kinesis_api.c b/plugins/out_kinesis_streams/kinesis_api.c index 664e4fe4dad..9124657bc19 100644 --- a/plugins/out_kinesis_streams/kinesis_api.c +++ b/plugins/out_kinesis_streams/kinesis_api.c @@ -309,8 +309,6 @@ static int process_event(struct flb_kinesis *ctx, struct flush *buf, time_key_ptr += strlen(ctx->time_key); memcpy(time_key_ptr, "\":\"", 3); time_key_ptr += 3; - tmp_size = buf->tmp_buf_size - buf->tmp_buf_offset; - tmp_size -= (time_key_ptr - tmp_buf_ptr); /* merge out_buf to time_key_ptr */ memcpy(time_key_ptr, out_buf, len); From 30e2aea454baabbc6d5342de94ebb52316f1353c Mon Sep 17 00:00:00 2001 From: Takahiro Yamashita Date: Sat, 26 Aug 2023 21:35:53 +0900 Subject: [PATCH 184/315] tests: runtime: in_mqtt: add test for in_mqtt Signed-off-by: Takahiro Yamashita --- tests/runtime/CMakeLists.txt | 1 + tests/runtime/in_mqtt.c | 316 +++++++++++++++++++++++++++++++++++ 2 files changed, 317 insertions(+) create mode 100644 tests/runtime/in_mqtt.c diff --git a/tests/runtime/CMakeLists.txt b/tests/runtime/CMakeLists.txt index 8fc75339adc..4c0637c6416 100644 --- a/tests/runtime/CMakeLists.txt +++ b/tests/runtime/CMakeLists.txt @@ -45,6 +45,7 @@ if(FLB_OUT_LIB) FLB_RT_TEST(FLB_IN_DUMMY "in_dummy.c") FLB_RT_TEST(FLB_IN_HTTP "in_http.c") FLB_RT_TEST(FLB_IN_ELASTICSEARCH "in_elasticsearch.c") + FLB_RT_TEST(FLB_IN_MQTT "in_mqtt.c") FLB_RT_TEST(FLB_IN_OPENTELEMETRY "in_opentelemetry.c") FLB_RT_TEST(FLB_IN_RANDOM "in_random.c") FLB_RT_TEST(FLB_IN_STATSD "in_statsd.c") diff --git a/tests/runtime/in_mqtt.c b/tests/runtime/in_mqtt.c new file mode 100644 index 00000000000..de9241aede0 --- /dev/null +++ b/tests/runtime/in_mqtt.c @@ -0,0 +1,316 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Fluent Bit + * ========== + * Copyright (C) 2019-2023 The Fluent Bit Authors + * Copyright (C) 2015-2018 Treasure Data Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include "flb_tests_runtime.h" + +struct test_ctx { + flb_ctx_t *flb; /* Fluent Bit library context */ + int i_ffd; /* Input fd */ + int f_ffd; /* Filter fd (unused) */ + int o_ffd; /* Output fd */ +}; + +pthread_mutex_t result_mutex = PTHREAD_MUTEX_INITIALIZER; +int num_output = 0; +static int get_output_num() +{ + int ret; + pthread_mutex_lock(&result_mutex); + ret = num_output; + pthread_mutex_unlock(&result_mutex); + + return ret; +} + +static void set_output_num(int num) +{ + pthread_mutex_lock(&result_mutex); + num_output = num; + pthread_mutex_unlock(&result_mutex); +} + +static void clear_output_num() +{ + set_output_num(0); +} + +struct str_list { + size_t size; + char **lists; +}; + +/* Callback to check expected results */ +static int cb_check_json_str_list(void *record, size_t size, void *data) +{ + char *p; + char *result; + int num = get_output_num(); + size_t i; + struct str_list *l = (struct str_list*)data; + + if (!TEST_CHECK(l != NULL)) { + flb_error("Data is NULL"); + flb_free(record); + return 0; + } + set_output_num(num+1); + + result = (char *) record; + + for (i=0; isize; i++) { + p = strstr(result, l->lists[i]); + if(!TEST_CHECK(p != NULL)) { + flb_error("Expected to find: '%s' in result '%s'", + l->lists[i], result); + } + } + flb_free(record); + return 0; +} + +static struct test_ctx *test_ctx_create(struct flb_lib_out_cb *data) +{ + int i_ffd; + int o_ffd; + int ret; + struct test_ctx *ctx = NULL; + + ctx = flb_malloc(sizeof(struct test_ctx)); + if (!TEST_CHECK(ctx != NULL)) { + TEST_MSG("malloc failed"); + flb_errno(); + return NULL; + } + + /* Service config */ + ctx->flb = flb_create(); + flb_service_set(ctx->flb, + "Flush", "0.200000000", + "Grace", "1", + "Log_Level", "error", + NULL); + + /* Input */ + i_ffd = flb_input(ctx->flb, (char *) "mqtt", NULL); + TEST_CHECK(i_ffd >= 0); + ctx->i_ffd = i_ffd; + + /* Output */ + o_ffd = flb_output(ctx->flb, (char *) "lib", (void *) data); + ctx->o_ffd = o_ffd; + ret = flb_output_set(ctx->flb, ctx->o_ffd, + "format", "json", + NULL); + TEST_CHECK(ret == 0); + + return ctx; +} + +static void test_ctx_destroy(struct test_ctx *ctx) +{ + TEST_CHECK(ctx != NULL); + + sleep(1); + flb_stop(ctx->flb); + flb_destroy(ctx->flb); + flb_free(ctx); +} + +#define DEFAULT_HOST "127.0.0.1" +#define DEFAULT_PORT 1883 +static flb_sockfd_t connect_tcp(char *in_host, int in_port) +{ + int port = in_port; + char *host = in_host; + flb_sockfd_t fd; + int ret; + struct sockaddr_in addr; + + if (host == NULL) { + host = DEFAULT_HOST; + } + if (port < 0) { + port = DEFAULT_PORT; + } + + memset(&addr, 0, sizeof(addr)); + fd = socket(PF_INET, SOCK_STREAM, 0); + if (!TEST_CHECK(fd >= 0)) { + TEST_MSG("failed to socket. host=%s port=%d errno=%d", host, port, errno); + return -1; + } + + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = inet_addr(host); + addr.sin_port = htons(port); + + ret = connect(fd, (const struct sockaddr *)&addr, sizeof(addr)); + if (!TEST_CHECK(ret >= 0)) { + TEST_MSG("failed to connect. host=%s port=%d errno=%d", host, port, errno); + flb_socket_close(fd); + return -1; + } + return fd; +} + +/* http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718028 */ +int send_CONNECT(flb_sockfd_t fd) +{ + ssize_t w_size; + char buf[] = {0x10, 0xa, + 0x0,0x4, 'M', 'Q', 'T', 'T', 0x4, 0xce, 0x0, 0xa + }; + + w_size = send(fd, buf, sizeof(buf), 0); + if (!TEST_CHECK(w_size == sizeof(buf))) { + TEST_MSG("failed to send CONNECT, errno=%d", errno); + return -1; + } + return 0; +} + +/* http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718033 */ +int recv_CONNACK(flb_sockfd_t fd) +{ + ssize_t r_size; + char buf[1024] = {0}; + + r_size = recv(fd, &buf[0], sizeof(buf), 0); + if (!TEST_CHECK(r_size != -1)) { + TEST_MSG("failed to recv CONNACK, errno=%d", errno); + return -1; + } + return 0; +} + +/* http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718037 */ +int send_PUBLISH(flb_sockfd_t fd, const char *payload, size_t payload_size) +{ + ssize_t w_size; + char buf[1024] = {0}; + + buf[0] = 0x30; + + buf[2] = 0x0; + buf[3] = 0x3; + buf[4] = 'a'; + buf[5] = '/'; + buf[6] = 'b'; + /* No packet id since QoS Level is 0 */ + buf[1] = 5 + (char)payload_size; + + if (!TEST_CHECK(sizeof(buf) >= buf[1])) { + TEST_MSG("payload is too long"); + return -1; + } + + strncpy(&buf[7], payload, payload_size); + + w_size = send(fd, buf, sizeof(buf), 0); + if (!TEST_CHECK(w_size == sizeof(buf))) { + TEST_MSG("failed to send PUBLISH, errno=%d", errno); + return -1; + } + return 0; +} + +void flb_test_mqtt() +{ + struct flb_lib_out_cb cb_data; + struct test_ctx *ctx; + flb_sockfd_t fd; + int ret; + int num; + + char *expected_strs[] = {"\"key\":\"val\""}; + struct str_list expected = { + .size = sizeof(expected_strs)/sizeof(char*), + .lists = &expected_strs[0], + }; + const char *payload = "{\"key\":\"val\"}"; + size_t payload_size = strlen(payload); + + clear_output_num(); + + cb_data.cb = cb_check_json_str_list; + cb_data.data = &expected; + + ctx = test_ctx_create(&cb_data); + if (!TEST_CHECK(ctx != NULL)) { + TEST_MSG("test_ctx_create failed"); + exit(EXIT_FAILURE); + } + + /* Start the engine */ + ret = flb_start(ctx->flb); + TEST_CHECK(ret == 0); + + /* use default host/port */ + fd = connect_tcp(NULL, -1); + if (!TEST_CHECK(fd >= 0)) { + test_ctx_destroy(ctx); + exit(EXIT_FAILURE); + } + + ret = send_CONNECT(fd); + if (!TEST_CHECK(ret == 0)) { + TEST_MSG("failed to send, errno=%d", errno); + flb_socket_close(fd); + test_ctx_destroy(ctx); + exit(EXIT_FAILURE); + } + + ret = recv_CONNACK(fd); + if (!TEST_CHECK(ret == 0)) { + TEST_MSG("failed to recv, errno=%d", errno); + flb_socket_close(fd); + test_ctx_destroy(ctx); + exit(EXIT_FAILURE); + } + + ret = send_PUBLISH(fd, payload, payload_size); + if (!TEST_CHECK(ret == 0)) { + TEST_MSG("failed to send, errno=%d", errno); + flb_socket_close(fd); + test_ctx_destroy(ctx); + exit(EXIT_FAILURE); + } + + /* waiting to flush */ + flb_time_msleep(500); + + num = get_output_num(); + if (!TEST_CHECK(num > 0)) { + TEST_MSG("no outputs"); + } + + flb_socket_close(fd); + test_ctx_destroy(ctx); +} + +TEST_LIST = { + {"mqtt", flb_test_mqtt}, + {NULL, NULL} +}; + From 18914ee27b385358615b40fb0a34d64dd9f09815 Mon Sep 17 00:00:00 2001 From: Takahiro Yamashita Date: Sun, 27 Aug 2023 09:05:58 +0900 Subject: [PATCH 185/315] tests: runtime: in_mqtt: add test for payload_key Signed-off-by: Takahiro Yamashita --- tests/runtime/in_mqtt.c | 80 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/tests/runtime/in_mqtt.c b/tests/runtime/in_mqtt.c index de9241aede0..0e38d0c51c4 100644 --- a/tests/runtime/in_mqtt.c +++ b/tests/runtime/in_mqtt.c @@ -309,8 +309,88 @@ void flb_test_mqtt() test_ctx_destroy(ctx); } +void flb_test_payload_key() +{ + struct flb_lib_out_cb cb_data; + struct test_ctx *ctx; + flb_sockfd_t fd; + int ret; + int num; + + char *expected_strs[] = {"\"payload_k\":{\"key\":\"val\"}"}; + struct str_list expected = { + .size = sizeof(expected_strs)/sizeof(char*), + .lists = &expected_strs[0], + }; + const char *payload = "{\"key\":\"val\"}"; + size_t payload_size = strlen(payload); + + clear_output_num(); + + cb_data.cb = cb_check_json_str_list; + cb_data.data = &expected; + + ctx = test_ctx_create(&cb_data); + if (!TEST_CHECK(ctx != NULL)) { + TEST_MSG("test_ctx_create failed"); + exit(EXIT_FAILURE); + } + + ret = flb_input_set(ctx->flb, ctx->i_ffd, + "payload_key", "payload_k", + NULL); + TEST_CHECK(ret == 0); + + /* Start the engine */ + ret = flb_start(ctx->flb); + TEST_CHECK(ret == 0); + + /* use default host/port */ + fd = connect_tcp(NULL, -1); + if (!TEST_CHECK(fd >= 0)) { + test_ctx_destroy(ctx); + exit(EXIT_FAILURE); + } + + ret = send_CONNECT(fd); + if (!TEST_CHECK(ret == 0)) { + TEST_MSG("failed to send, errno=%d", errno); + flb_socket_close(fd); + test_ctx_destroy(ctx); + exit(EXIT_FAILURE); + } + + ret = recv_CONNACK(fd); + if (!TEST_CHECK(ret == 0)) { + TEST_MSG("failed to recv, errno=%d", errno); + flb_socket_close(fd); + test_ctx_destroy(ctx); + exit(EXIT_FAILURE); + } + + ret = send_PUBLISH(fd, payload, payload_size); + if (!TEST_CHECK(ret == 0)) { + TEST_MSG("failed to send, errno=%d", errno); + flb_socket_close(fd); + test_ctx_destroy(ctx); + exit(EXIT_FAILURE); + } + + /* waiting to flush */ + flb_time_msleep(500); + + num = get_output_num(); + if (!TEST_CHECK(num > 0)) { + TEST_MSG("no outputs"); + } + + flb_socket_close(fd); + test_ctx_destroy(ctx); +} + TEST_LIST = { {"mqtt", flb_test_mqtt}, + {"payload_key", flb_test_payload_key}, {NULL, NULL} }; From 7fa08e691fc46f39d793433d4394a1d150f79231 Mon Sep 17 00:00:00 2001 From: Takahiro Yamashita Date: Sun, 27 Aug 2023 09:06:31 +0900 Subject: [PATCH 186/315] in_mqtt: support payload_key Signed-off-by: Takahiro Yamashita --- plugins/in_mqtt/mqtt.c | 6 +++++- plugins/in_mqtt/mqtt.h | 3 +++ plugins/in_mqtt/mqtt_config.c | 8 ++++++++ plugins/in_mqtt/mqtt_prot.c | 11 +++++++++++ 4 files changed, 27 insertions(+), 1 deletion(-) diff --git a/plugins/in_mqtt/mqtt.c b/plugins/in_mqtt/mqtt.c index c8928fddb00..d1ae74f1ed1 100644 --- a/plugins/in_mqtt/mqtt.c +++ b/plugins/in_mqtt/mqtt.c @@ -139,7 +139,11 @@ static int in_mqtt_exit(void *data, struct flb_config *config) /* Configuration properties map */ static struct flb_config_map config_map[] = { - + { + FLB_CONFIG_MAP_STR, "payload_key", NULL, + 0, FLB_TRUE, offsetof(struct flb_in_mqtt_config, payload_key), + "Key where the payload will be preserved" + }, /* EOF */ {0} }; diff --git a/plugins/in_mqtt/mqtt.h b/plugins/in_mqtt/mqtt.h index 72ab489fa0c..01c3b7be9e4 100644 --- a/plugins/in_mqtt/mqtt.h +++ b/plugins/in_mqtt/mqtt.h @@ -20,6 +20,7 @@ #ifndef FLB_IN_MQTT_H #define FLB_IN_MQTT_H +#include #include #define MQTT_MSGP_BUF_SIZE 8192 @@ -28,6 +29,8 @@ struct flb_in_mqtt_config { char *listen; /* Listen interface */ char *tcp_port; /* TCP Port */ + flb_sds_t payload_key; /* payload key */ + int msgp_len; /* msgpack data length */ char msgp[MQTT_MSGP_BUF_SIZE]; /* msgpack static buffer */ struct flb_input_instance *ins; /* plugin input instance */ diff --git a/plugins/in_mqtt/mqtt_config.c b/plugins/in_mqtt/mqtt_config.c index f58eeb3f562..800834c05bd 100644 --- a/plugins/in_mqtt/mqtt_config.c +++ b/plugins/in_mqtt/mqtt_config.c @@ -30,6 +30,7 @@ struct flb_in_mqtt_config *mqtt_config_init(struct flb_input_instance *ins) { char tmp[16]; struct flb_in_mqtt_config *config; + int ret; config = flb_calloc(1, sizeof(struct flb_in_mqtt_config)); if (!config) { @@ -37,6 +38,13 @@ struct flb_in_mqtt_config *mqtt_config_init(struct flb_input_instance *ins) return NULL; } + ret = flb_input_config_map_set(ins, (void*) config); + if (ret == -1) { + flb_plg_error(ins, "could not initialize config map"); + flb_free(config); + return NULL; + } + config->log_encoder = flb_log_event_encoder_create( FLB_LOG_EVENT_FORMAT_DEFAULT); diff --git a/plugins/in_mqtt/mqtt_prot.c b/plugins/in_mqtt/mqtt_prot.c index a072cbfe588..e0267daf269 100644 --- a/plugins/in_mqtt/mqtt_prot.c +++ b/plugins/in_mqtt/mqtt_prot.c @@ -171,6 +171,13 @@ static int mqtt_data_append(char *topic, size_t topic_len, FLB_LOG_EVENT_STRING_VALUE(topic, topic_len)); } + if (ctx->payload_key) { + flb_log_event_encoder_append_body_string_length(ctx->log_encoder, flb_sds_len(ctx->payload_key)); + flb_log_event_encoder_append_body_string_body(ctx->log_encoder, ctx->payload_key, + flb_sds_len(ctx->payload_key)); + flb_log_event_encoder_body_begin_map(ctx->log_encoder); + } + /* Re-pack original KVs */ for (i = 0; i < root.via.map.size && @@ -182,6 +189,10 @@ static int mqtt_data_append(char *topic, size_t topic_len, FLB_LOG_EVENT_MSGPACK_OBJECT_VALUE(&root.via.map.ptr[i].val)); } + if (ctx->payload_key) { + flb_log_event_encoder_body_commit_map(ctx->log_encoder); + } + if (ret == FLB_EVENT_ENCODER_SUCCESS) { ret = flb_log_event_encoder_commit_record(ctx->log_encoder); } From b273cb63d9a5a0fc1ebe25911061aebdd4cf50d0 Mon Sep 17 00:00:00 2001 From: Hiroshi Hatake Date: Tue, 22 Aug 2023 14:25:36 +0900 Subject: [PATCH 187/315] in_winevtlog: Support XML query parameter for filtering events Signed-off-by: Hiroshi Hatake --- plugins/in_winevtlog/in_winevtlog.c | 8 +++++-- plugins/in_winevtlog/winevtlog.c | 37 +++++++++++++++++++++++------ plugins/in_winevtlog/winevtlog.h | 4 +++- 3 files changed, 39 insertions(+), 10 deletions(-) diff --git a/plugins/in_winevtlog/in_winevtlog.c b/plugins/in_winevtlog/in_winevtlog.c index f441283ce32..60c5bcecb3b 100644 --- a/plugins/in_winevtlog/in_winevtlog.c +++ b/plugins/in_winevtlog/in_winevtlog.c @@ -78,7 +78,7 @@ static int in_winevtlog_init(struct flb_input_instance *in, tmp = "Application"; } - ctx->active_channel = winevtlog_open_all(tmp, ctx->read_existing_events, ctx->ignore_missing_channels); + ctx->active_channel = winevtlog_open_all(tmp, ctx); if (!ctx->active_channel) { flb_plg_error(ctx->ins, "failed to open channels"); flb_log_event_encoder_destroy(ctx->log_encoder); @@ -256,7 +256,11 @@ static struct flb_config_map config_map[] = { 0, FLB_TRUE, offsetof(struct winevtlog_config, ignore_missing_channels), "Whether to ignore channels missing in eventlog" }, - + { + FLB_CONFIG_MAP_STR, "event_query", "*", + 0, FLB_TRUE, offsetof(struct winevtlog_config, event_query), + "Specify XML query for filtering events" + }, /* EOF */ {0} }; diff --git a/plugins/in_winevtlog/winevtlog.c b/plugins/in_winevtlog/winevtlog.c index b7c618ab604..09d3f962456 100644 --- a/plugins/in_winevtlog/winevtlog.c +++ b/plugins/in_winevtlog/winevtlog.c @@ -31,15 +31,15 @@ static char* convert_wstr(wchar_t *wstr, UINT codePage); static wchar_t* convert_str(char *str); struct winevtlog_channel *winevtlog_subscribe(const char *channel, int read_existing_events, - EVT_HANDLE stored_bookmark) + EVT_HANDLE stored_bookmark, const char *query) { struct winevtlog_channel *ch; EVT_HANDLE bookmark = NULL; HANDLE signal_event = NULL; DWORD len; DWORD flags = 0L; - PWSTR wide_channel = L"Application"; - PWSTR wide_query = L"*"; + PWSTR wide_channel = NULL; + PWSTR wide_query = NULL; void *buf; ch = flb_calloc(1, sizeof(struct winevtlog_channel)); @@ -54,6 +54,7 @@ struct winevtlog_channel *winevtlog_subscribe(const char *channel, int read_exis flb_free(ch); return NULL; } + ch->query = NULL; signal_event = CreateEvent(NULL, FALSE, FALSE, NULL); @@ -61,6 +62,13 @@ struct winevtlog_channel *winevtlog_subscribe(const char *channel, int read_exis len = MultiByteToWideChar(CP_UTF8, 0, channel, -1, NULL, 0); wide_channel = flb_malloc(sizeof(PWSTR) * len); MultiByteToWideChar(CP_UTF8, 0, channel, -1, wide_channel, len); + if (query != NULL) { + // query : To wide char + len = MultiByteToWideChar(CP_UTF8, 0, query, -1, NULL, 0); + wide_query = flb_malloc(sizeof(PWSTR) * len); + MultiByteToWideChar(CP_UTF8, 0, query, -1, wide_query, len); + ch->query = flb_strdup(query); + } if (stored_bookmark) { flags |= EvtSubscribeStartAfterBookmark; @@ -70,11 +78,17 @@ struct winevtlog_channel *winevtlog_subscribe(const char *channel, int read_exis flags |= EvtSubscribeToFutureEvents; } + /* The wide_query parameter can handle NULL as `*` for retrieving all events. + * ref. https://learn.microsoft.com/en-us/windows/win32/api/winevt/nf-winevt-evtsubscribe + */ ch->subscription = EvtSubscribe(NULL, signal_event, wide_channel, wide_query, stored_bookmark, NULL, NULL, flags); if (!ch->subscription) { flb_error("[in_winevtlog] cannot subscribe '%s' (%i)", channel, GetLastError()); flb_free(ch->name); + if (ch->query != NULL) { + flb_free(ch->query); + } flb_free(ch); return NULL; } @@ -98,12 +112,18 @@ struct winevtlog_channel *winevtlog_subscribe(const char *channel, int read_exis flb_error("[in_winevtlog] cannot subscribe '%s' (%i)", channel, GetLastError()); flb_free(wide_channel); flb_free(ch->name); + if (ch->query != NULL) { + flb_free(ch->query); + } flb_free(ch); return NULL; } } flb_free(wide_channel); + if (wide_query != NULL) { + flb_free(wide_query); + } return ch; } @@ -142,6 +162,9 @@ static void close_handles(struct winevtlog_channel *ch) void winevtlog_close(struct winevtlog_channel *ch) { flb_free(ch->name); + if (ch->query != NULL) { + flb_free(ch->query); + } close_handles(ch); flb_free(ch); @@ -587,7 +610,7 @@ int winevtlog_read(struct winevtlog_channel *ch, struct winevtlog_config *ctx, * * "channels" are comma-separated names like "Setup,Security". */ -struct mk_list *winevtlog_open_all(const char *channels, int read_existing_events, int ignore_missing_channels) +struct mk_list *winevtlog_open_all(const char *channels, struct winevtlog_config *ctx) { char *tmp; char *channel; @@ -611,12 +634,12 @@ struct mk_list *winevtlog_open_all(const char *channels, int read_existing_event channel = strtok_s(tmp , ",", &state); while (channel) { - ch = winevtlog_subscribe(channel, read_existing_events, NULL); + ch = winevtlog_subscribe(channel, ctx->read_existing_events, NULL, ctx->event_query); if (ch) { mk_list_add(&ch->_head, list); } else { - if (ignore_missing_channels) { + if (ctx->ignore_missing_channels) { flb_debug("[in_winevtlog] channel '%s' does not exist", channel); } else { @@ -746,7 +769,7 @@ int winevtlog_sqlite_load(struct winevtlog_channel *ch, struct flb_sqldb *db) bookmark = EvtCreateBookmark(bookmark_xml); if (bookmark) { /* re-create subscription handles */ - re_ch = winevtlog_subscribe(ch->name, FLB_FALSE, bookmark); + re_ch = winevtlog_subscribe(ch->name, FLB_FALSE, bookmark, ch->query); if (re_ch != NULL) { close_handles(ch); diff --git a/plugins/in_winevtlog/winevtlog.h b/plugins/in_winevtlog/winevtlog.h index 584ce78d4dc..10ef3e457e7 100644 --- a/plugins/in_winevtlog/winevtlog.h +++ b/plugins/in_winevtlog/winevtlog.h @@ -33,6 +33,7 @@ struct winevtlog_config { int render_event_as_xml; int use_ansi; int ignore_missing_channels; + flb_sds_t event_query; struct mk_list *active_channel; struct flb_sqldb *db; @@ -54,6 +55,7 @@ struct winevtlog_channel { int count; char *name; + char *query; unsigned int time_updated; unsigned int time_created; struct mk_list _head; @@ -83,7 +85,7 @@ int winevtlog_read(struct winevtlog_channel *ch, * * "channels" are comma-separated names like "Setup,Security". */ -struct mk_list *winevtlog_open_all(const char *channels, int read_exising_events, int ignore_missing_channels); +struct mk_list *winevtlog_open_all(const char *channels, struct winevtlog_config *ctx); void winevtlog_close_all(struct mk_list *list); void winevtlog_pack_xml_event(WCHAR *system_xml, WCHAR *message, From 45fcc61b7c99701a26a7071dc054cd2303c5dbb0 Mon Sep 17 00:00:00 2001 From: Phillip Whelan Date: Wed, 16 Aug 2023 16:54:03 -0400 Subject: [PATCH 188/315] custom_calyptia: submit metrics when not in fleet mode. Signed-off-by: Phillip Whelan --- plugins/custom_calyptia/calyptia.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/custom_calyptia/calyptia.c b/plugins/custom_calyptia/calyptia.c index b1f8558cf28..bb5e2cafccc 100644 --- a/plugins/custom_calyptia/calyptia.c +++ b/plugins/custom_calyptia/calyptia.c @@ -339,7 +339,7 @@ static int cb_calyptia_init(struct flb_custom_instance *ins, flb_input_set_property(ctx->i, "scrape_interval", "30"); /* output cloud connector */ - if (ctx->fleet_id != NULL) { + if (ctx->fleet_id != NULL || ctx->fleet_name == NULL) { ctx->o = setup_cloud_output(config, ctx); if (ctx->o == NULL) { return -1; From 019fdbf89515b06f9b1e14f134d7e0f36f5cc27f Mon Sep 17 00:00:00 2001 From: Phillip Whelan Date: Wed, 16 Aug 2023 17:15:56 -0400 Subject: [PATCH 189/315] custom_calyptia: clarify code that conditionally activates metrics. Signed-off-by: Phillip Whelan --- plugins/custom_calyptia/calyptia.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/plugins/custom_calyptia/calyptia.c b/plugins/custom_calyptia/calyptia.c index bb5e2cafccc..3e4c585407b 100644 --- a/plugins/custom_calyptia/calyptia.c +++ b/plugins/custom_calyptia/calyptia.c @@ -309,6 +309,7 @@ static int cb_calyptia_init(struct flb_custom_instance *ins, { int ret; struct calyptia *ctx; + int is_fleet_mode; (void) data; ctx = flb_calloc(1, sizeof(struct calyptia)); @@ -338,8 +339,14 @@ static int cb_calyptia_init(struct flb_custom_instance *ins, flb_input_set_property(ctx->i, "scrape_on_start", "true"); flb_input_set_property(ctx->i, "scrape_interval", "30"); + if (ctx->fleet_name || ctx->fleet_id) { + is_fleet_mode = FLB_TRUE; + } else { + is_fleet_mode = FLB_FALSE; + } /* output cloud connector */ - if (ctx->fleet_id != NULL || ctx->fleet_name == NULL) { + if ((is_fleet_mode == FLB_TRUE && ctx->fleet_id != NULL) || + (is_fleet_mode == FLB_FALSE)) { ctx->o = setup_cloud_output(config, ctx); if (ctx->o == NULL) { return -1; From 826843cb10809e322fbd7a184764248f669bb212 Mon Sep 17 00:00:00 2001 From: Phillip Whelan Date: Mon, 21 Aug 2023 11:13:10 -0400 Subject: [PATCH 190/315] custom_calyptia: add missing new lines for if and else. Signed-off-by: Phillip Whelan --- plugins/custom_calyptia/calyptia.c | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/plugins/custom_calyptia/calyptia.c b/plugins/custom_calyptia/calyptia.c index 3e4c585407b..a028986b762 100644 --- a/plugins/custom_calyptia/calyptia.c +++ b/plugins/custom_calyptia/calyptia.c @@ -125,6 +125,7 @@ flb_sds_t custom_calyptia_pipeline_config_get(struct flb_config *ctx) struct flb_output_instance *o_ins; buf = flb_sds_create_size(2048); + if (!buf) { return NULL; } @@ -134,9 +135,11 @@ flb_sds_t custom_calyptia_pipeline_config_get(struct flb_config *ctx) i_ins = mk_list_entry(head, struct flb_input_instance, _head); flb_sds_printf(&buf, "[INPUT]\n"); flb_sds_printf(&buf, " name %s\n", i_ins->name); + if (i_ins->alias) { flb_sds_printf(&buf, " alias %s\n", i_ins->alias); } + if (i_ins->tag) { flb_sds_printf(&buf, " tag %s\n", i_ins->tag); } @@ -167,6 +170,7 @@ flb_sds_t custom_calyptia_pipeline_config_get(struct flb_config *ctx) o_ins = mk_list_entry(head, struct flb_output_instance, _head); flb_sds_printf(&buf, "[OUTPUT]\n"); flb_sds_printf(&buf, " name %s\n", o_ins->name); + if (o_ins->match) { flb_sds_printf(&buf, " match %s\n", o_ins->match); } @@ -200,6 +204,7 @@ flb_sds_t custom_calyptia_pipeline_config_get(struct flb_config *ctx) } } #endif + if (o_ins->retry_limit == FLB_OUT_RETRY_UNLIMITED) { flb_sds_printf(&buf, " retry_limit no_limits\n"); } @@ -232,6 +237,7 @@ static struct flb_output_instance *setup_cloud_output(struct flb_config *config, struct flb_config_map_val *mv; cloud = flb_output_new(config, "calyptia", ctx, FLB_FALSE); + if (!cloud) { flb_plg_error(ctx->ins, "could not load Calyptia Cloud connector"); flb_free(ctx); @@ -240,6 +246,7 @@ static struct flb_output_instance *setup_cloud_output(struct flb_config *config, /* direct connect / routing */ ret = flb_router_connect_direct(ctx->i, cloud); + if (ret != 0) { flb_plg_error(ctx->ins, "could not load Calyptia Cloud connector"); flb_free(ctx); @@ -252,6 +259,7 @@ static struct flb_output_instance *setup_cloud_output(struct flb_config *config, k = mk_list_entry_first(mv->val.list, struct flb_slist_entry, _head); v = mk_list_entry_last(mv->val.list, struct flb_slist_entry, _head); kv = flb_sds_create_size(strlen(k->str) + strlen(v->str) + 1); + if(!kv) { flb_free(ctx); return NULL; @@ -265,6 +273,7 @@ static struct flb_output_instance *setup_cloud_output(struct flb_config *config, flb_output_set_property(cloud, "match", "_calyptia_cloud"); flb_output_set_property(cloud, "api_key", ctx->api_key); + if (ctx->store_path) { flb_output_set_property(cloud, "store_path", ctx->store_path); } @@ -313,6 +322,7 @@ static int cb_calyptia_init(struct flb_custom_instance *ins, (void) data; ctx = flb_calloc(1, sizeof(struct calyptia)); + if (!ctx) { flb_errno(); return -1; @@ -321,6 +331,7 @@ static int cb_calyptia_init(struct flb_custom_instance *ins, /* Load the config map */ ret = flb_custom_config_map_set(ins, (void *) ctx); + if (ret == -1) { flb_free(ctx); return -1; @@ -331,6 +342,7 @@ static int cb_calyptia_init(struct flb_custom_instance *ins, /* input collector */ ctx->i = flb_input_new(config, "fluentbit_metrics", NULL, FLB_TRUE); + if (!ctx->i) { flb_plg_error(ctx->ins, "could not load metrics collector"); return -1; @@ -341,13 +353,16 @@ static int cb_calyptia_init(struct flb_custom_instance *ins, if (ctx->fleet_name || ctx->fleet_id) { is_fleet_mode = FLB_TRUE; - } else { + } + else { is_fleet_mode = FLB_FALSE; } + /* output cloud connector */ if ((is_fleet_mode == FLB_TRUE && ctx->fleet_id != NULL) || (is_fleet_mode == FLB_FALSE)) { ctx->o = setup_cloud_output(config, ctx); + if (ctx->o == NULL) { return -1; } @@ -355,6 +370,7 @@ static int cb_calyptia_init(struct flb_custom_instance *ins, if (ctx->fleet_id || ctx->fleet_name) { ctx->fleet = flb_input_new(config, "calyptia_fleet", NULL, FLB_FALSE); + if (!ctx->fleet) { flb_plg_error(ctx->ins, "could not load Calyptia Fleet plugin"); return -1; @@ -364,7 +380,8 @@ static int cb_calyptia_init(struct flb_custom_instance *ins, // TODO: set this once the fleet_id has been retrieved... // flb_output_set_property(ctx->o, "fleet_id", ctx->fleet_id); flb_input_set_property(ctx->fleet, "fleet_name", ctx->fleet_name); - } else { + } + else { flb_output_set_property(ctx->o, "fleet_id", ctx->fleet_id); flb_input_set_property(ctx->fleet, "fleet_id", ctx->fleet_id); } @@ -372,16 +389,21 @@ static int cb_calyptia_init(struct flb_custom_instance *ins, flb_input_set_property(ctx->fleet, "api_key", ctx->api_key); flb_input_set_property(ctx->fleet, "host", ctx->cloud_host); flb_input_set_property(ctx->fleet, "port", ctx->cloud_port); + if (ctx->cloud_tls == 1) { flb_input_set_property(ctx->fleet, "tls", "on"); - } else { + } + else { flb_input_set_property(ctx->fleet, "tls", "off"); } + if (ctx->cloud_tls_verify == 1) { flb_input_set_property(ctx->fleet, "tls.verify", "on"); - } else { + } + else { flb_input_set_property(ctx->fleet, "tls.verify", "off"); } + if (ctx->fleet_config_dir) { flb_input_set_property(ctx->fleet, "config_dir", ctx->fleet_config_dir); } From eaa64dae3ca6d757ed3e94004cdfb2cb53259292 Mon Sep 17 00:00:00 2001 From: Phillip Whelan Date: Mon, 21 Aug 2023 11:18:31 -0400 Subject: [PATCH 191/315] in_calyptia_fleet: add missing new lines for if and else. Signed-off-by: Phillip Whelan --- plugins/in_calyptia_fleet/in_calyptia_fleet.c | 59 ++++++++++++++++++- 1 file changed, 56 insertions(+), 3 deletions(-) diff --git a/plugins/in_calyptia_fleet/in_calyptia_fleet.c b/plugins/in_calyptia_fleet/in_calyptia_fleet.c index 6452d49b174..85a91769743 100644 --- a/plugins/in_calyptia_fleet/in_calyptia_fleet.c +++ b/plugins/in_calyptia_fleet/in_calyptia_fleet.c @@ -88,12 +88,14 @@ static char *find_case_header(struct flb_http_client *c, const char *header) headstart = strstr(c->resp.data, "\r\n"); + if (headstart == NULL) { return NULL; } /* Lookup the beginning of the header */ for (p = headstart; p != NULL && p+2 < c->resp.payload; p = strstr(p, "\r\n")) { + if (p + 4 < c->resp.payload && strcmp(p, "\r\n\r\n") == 0) { return NULL; } @@ -104,8 +106,10 @@ static char *find_case_header(struct flb_http_client *c, const char *header) if (p + strlen(header)+2 >= c->resp.payload) { return NULL; } + // matched header and the delimiter if (strncasecmp(p, header, strlen(header)) == 0) { + if (p[strlen(header)] == ':' && p[strlen(header)+1] == ' ') { return p; } @@ -129,7 +133,9 @@ static int case_header_lookup(struct flb_http_client *c, p = find_case_header(c, header); end = strstr(c->resp.data, "\r\n\r\n"); + if (!p) { + if (end) { /* The headers are complete but the header is not there */ return -1; @@ -146,6 +152,7 @@ static int case_header_lookup(struct flb_http_client *c, /* Lookup CRLF (end of line \r\n) */ crlf = strstr(p, "\r\n"); + if (!crlf) { return -1; } @@ -168,9 +175,11 @@ static flb_sds_t fleet_config_filename(struct flb_in_calyptia_fleet_config *ctx, flb_sds_t cfgname; cfgname = flb_sds_create_size(4096); + if (ctx->fleet_name != NULL) { flb_sds_printf(&cfgname, "%s" PATH_SEPARATOR "%s" PATH_SEPARATOR "%s.ini", ctx->config_dir, ctx->fleet_name, fname); - } else { + } + else { flb_sds_printf(&cfgname, "%s" PATH_SEPARATOR "%s" PATH_SEPARATOR "%s.ini", ctx->config_dir, ctx->fleet_id, fname); } @@ -209,7 +218,9 @@ static int is_new_fleet_config(struct flb_in_calyptia_fleet_config *ctx, struct if (cfg->conf_path_file == NULL) { return FLB_FALSE; } + cfgnewname = new_fleet_config_filename(ctx); + if (strcmp(cfgnewname, cfg->conf_path_file) == 0) { ret = FLB_TRUE; } @@ -228,7 +239,9 @@ static int is_cur_fleet_config(struct flb_in_calyptia_fleet_config *ctx, struct if (cfg->conf_path_file == NULL) { return FLB_FALSE; } + cfgcurname = cur_fleet_config_filename(ctx); + if (strcmp(cfgcurname, cfg->conf_path_file) == 0) { ret = FLB_TRUE; } @@ -243,6 +256,7 @@ static int is_fleet_config(struct flb_in_calyptia_fleet_config *ctx, struct flb_ if (cfg->conf_path_file == NULL) { return FLB_FALSE; } + return is_new_fleet_config(ctx, cfg) || is_cur_fleet_config(ctx, cfg); } @@ -293,16 +307,19 @@ static int test_config_is_valid(flb_sds_t cfgpath) config = flb_config_init(); + if (config == NULL) { goto config_init_error; } cf = flb_cf_create(); + if (cf == NULL) { goto cf_create_error; } cf = flb_cf_create_from_file(cf, cfgpath); + if (cf == NULL) { goto cf_create_from_file_error; } @@ -339,6 +356,7 @@ static int execute_reload(struct flb_in_calyptia_fleet_config *ctx, flb_sds_t cf flb_plg_error(ctx->ins, "unable to get fluent-bit context."); return FLB_FALSE; } + // fix execution in valgrind... // otherwise flb_reload errors out with: // [error] [reload] given flb context is NULL @@ -365,6 +383,7 @@ static char *tls_setting_string(int use_tls) if (use_tls) { return "On"; } + return "Off"; } @@ -405,12 +424,14 @@ static flb_sds_t parse_api_key_json(struct flb_in_calyptia_fleet_config *ctx, msgpack_unpacked_init(&result); while (msgpack_unpack_next(&result, pack, out_size, &off) == MSGPACK_UNPACK_SUCCESS) { + if (result.data.type == MSGPACK_OBJECT_MAP) { for (i = 0; i < result.data.via.map.size; i++) { cur = &result.data.via.map.ptr[i]; key = &cur->key.via.str; if (strncmp(key->ptr, "ProjectID", key->size) == 0) { + if (cur->val.type != MSGPACK_OBJECT_STR) { flb_plg_error(ctx->ins, "unable to find fleet by name"); msgpack_unpacked_destroy(&result); @@ -469,14 +490,17 @@ static ssize_t parse_fleet_search_json(struct flb_in_calyptia_fleet_config *ctx, msgpack_unpacked_init(&result); while (msgpack_unpack_next(&result, pack, out_size, &off) == MSGPACK_UNPACK_SUCCESS) { + if (result.data.type == MSGPACK_OBJECT_ARRAY) { results = &result.data.via.array; + if (results->ptr[0].type == MSGPACK_OBJECT_MAP) { for (i = 0; i < results->ptr[0].via.map.size; i++) { cur = &results->ptr[0].via.map.ptr[i]; key = &cur->key.via.str; if (strncasecmp(key->ptr, "id", key->size) == 0) { + if (cur->val.type != MSGPACK_OBJECT_STR) { flb_plg_error(ctx->ins, "unable to find fleet by name"); msgpack_unpacked_destroy(&result); @@ -499,6 +523,7 @@ static ssize_t parse_fleet_search_json(struct flb_in_calyptia_fleet_config *ctx, if (ctx->fleet_id == NULL) { return -1; } + return 0; } @@ -518,12 +543,14 @@ static int get_calyptia_fleet_id_by_name(struct flb_in_calyptia_fleet_config *ct int ret; api_token_sep = strchr(ctx->api_key, '.'); + if (api_token_sep == NULL) { return -1; } elen = api_token_sep-ctx->api_key; elen = elen + (4 - (elen % 4)); + if (elen > sizeof(encoded)) { flb_plg_error(ctx->ins, "API Token is too large"); return -1; @@ -534,11 +561,13 @@ static int get_calyptia_fleet_id_by_name(struct flb_in_calyptia_fleet_config *ct ret = flb_base64_decode(token, sizeof(token)-1, &tlen, encoded, elen); + if (ret != 0) { return ret; } project_id = parse_api_key_json(ctx, (char *)token, tlen); + if (project_id == NULL) { return -1; } @@ -549,6 +578,7 @@ static int get_calyptia_fleet_id_by_name(struct flb_in_calyptia_fleet_config *ct client = flb_http_client(u_conn, FLB_HTTP_GET, url, NULL, 0, ctx->ins->host.name, ctx->ins->host.port, NULL, 0); + if (!client) { flb_plg_error(ctx->ins, "unable to create http client"); return -1; @@ -561,6 +591,7 @@ static int get_calyptia_fleet_id_by_name(struct flb_in_calyptia_fleet_config *ct ctx->api_key, flb_sds_len(ctx->api_key)); ret = flb_http_do(client, &b_sent); + if (ret != 0) { flb_plg_error(ctx->ins, "http do error"); return -1; @@ -610,6 +641,7 @@ static int in_calyptia_fleet_collect(struct flb_input_instance *ins, int ret = -1; u_conn = flb_upstream_conn_get(ctx->u); + if (!u_conn) { flb_plg_error(ctx->ins, "could not get an upstream connection to %s:%u", ctx->ins->host.name, ctx->ins->host.port); @@ -617,6 +649,7 @@ static int in_calyptia_fleet_collect(struct flb_input_instance *ins, } if (ctx->fleet_id == NULL) { + if (get_calyptia_fleet_id_by_name(ctx, u_conn, config) == -1) { flb_plg_error(ctx->ins, "unable to find fleet: %s", ctx->fleet_name); goto conn_error; @@ -631,6 +664,7 @@ static int in_calyptia_fleet_collect(struct flb_input_instance *ins, client = flb_http_client(u_conn, FLB_HTTP_GET, ctx->fleet_url, NULL, 0, ctx->ins->host.name, ctx->ins->host.port, NULL, 0); + if (!client) { flb_plg_error(ins, "unable to create http client"); goto client_error; @@ -643,6 +677,7 @@ static int in_calyptia_fleet_collect(struct flb_input_instance *ins, ctx->api_key, flb_sds_len(ctx->api_key)); ret = flb_http_do(client, &b_sent); + if (ret != 0) { flb_plg_error(ins, "http do error"); goto http_error; @@ -660,6 +695,7 @@ static int in_calyptia_fleet_collect(struct flb_input_instance *ins, /* copy and NULL terminate the payload */ data = flb_sds_create_size(client->resp.payload_size + 1); + if (!data) { goto http_error; } @@ -668,6 +704,7 @@ static int in_calyptia_fleet_collect(struct flb_input_instance *ins, ret = case_header_lookup(client, "Last-modified", strlen("Last-modified"), &fbit_last_modified, &fbit_last_modified_len); + if (ret == -1) { flb_plg_error(ctx->ins, "unable to get last-modified header"); goto http_error; @@ -678,13 +715,17 @@ static int in_calyptia_fleet_collect(struct flb_input_instance *ins, time_last_modified = mktime(&tm_last_modified.tm); cfgname = time_fleet_config_filename(ctx, time_last_modified); + if (access(cfgname, F_OK) == -1 && errno == ENOENT) { cfgfp = fopen(cfgname, "w+"); + if (cfgfp == NULL) { flb_plg_error(ctx->ins, "unable to open configuration file: %s", cfgname); goto http_error; } + header = flb_sds_create_size(4096); + if (ctx->fleet_name == NULL) { flb_sds_printf(&header, "[CUSTOM]\n" @@ -704,7 +745,8 @@ static int in_calyptia_fleet_collect(struct flb_input_instance *ins, ctx->ins->host.port, tls_setting_string(ctx->ins->use_tls) ); - } else { + } + else { flb_sds_printf(&header, "[CUSTOM]\n" " Name calyptia\n" @@ -732,12 +774,14 @@ static int in_calyptia_fleet_collect(struct flb_input_instance *ins, fclose(cfgfp); cfgnewname = new_fleet_config_filename(ctx); + if (exists_new_fleet_config(ctx) == FLB_TRUE) { cfgoldname = old_fleet_config_filename(ctx); rename(cfgnewname, cfgoldname); unlink(cfgnewname); flb_sds_destroy(cfgoldname); } + link(cfgname, cfgnewname); // FORCE THE RELOAD!!! @@ -777,11 +821,14 @@ static void create_fleet_directory(struct flb_in_calyptia_fleet_config *ctx) } myfleetdir = flb_sds_create_size(256); + if (ctx->fleet_name != NULL) { flb_sds_printf(&myfleetdir, "%s" PATH_SEPARATOR "%s", ctx->config_dir, ctx->fleet_name); - } else { + } + else { flb_sds_printf(&myfleetdir, "%s" PATH_SEPARATOR "%s", ctx->config_dir, ctx->fleet_id); } + if (access(myfleetdir, F_OK)) { mkdir(myfleetdir, 0700); } @@ -818,6 +865,7 @@ static int in_calyptia_fleet_init(struct flb_input_instance *in, #endif flb_plg_info(in, "initializing calyptia fleet input."); + if (in->host.name == NULL) { flb_plg_error(in, "no input 'Host' provided"); return -1; @@ -825,6 +873,7 @@ static int in_calyptia_fleet_init(struct flb_input_instance *in, /* Allocate space for the configuration */ ctx = flb_calloc(1, sizeof(struct flb_in_calyptia_fleet_config)); + if (!ctx) { flb_errno(); return -1; @@ -834,6 +883,7 @@ static int in_calyptia_fleet_init(struct flb_input_instance *in, /* Load the config map */ ret = flb_input_config_map_set(in, (void *)ctx); + if (ret == -1) { flb_free(ctx); flb_plg_error(in, "unable to load configuration"); @@ -843,12 +893,14 @@ static int in_calyptia_fleet_init(struct flb_input_instance *in, #ifdef _WIN32 if (ctx->config_dir == NULL) { tmpdir = getenv("TEMP"); + if (tmpdir == NULL) { flb_plg_error(in, "unable to find temporary directory (%%TEMP%%)."); return -1; } ctx->config_dir = flb_sds_create_size(4096); + if (ctx->config_dir == NULL) { flb_plg_error(in, "unable to allocate config-dir."); return -1; @@ -887,6 +939,7 @@ static int in_calyptia_fleet_init(struct flb_input_instance *in, ctx->interval_sec, ctx->interval_nsec, config); + if (ret == -1) { flb_plg_error(ctx->ins, "could not set collector for Health input plugin"); flb_free(ctx); From 2a14bee5535783746aa15f1776f731ba171abba6 Mon Sep 17 00:00:00 2001 From: Phillip Whelan Date: Mon, 21 Aug 2023 11:32:13 -0400 Subject: [PATCH 192/315] custom_calyptia: update code to be more inline with coding guidelines. Signed-off-by: Phillip Whelan --- plugins/custom_calyptia/calyptia.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/plugins/custom_calyptia/calyptia.c b/plugins/custom_calyptia/calyptia.c index a028986b762..50158ca0b68 100644 --- a/plugins/custom_calyptia/calyptia.c +++ b/plugins/custom_calyptia/calyptia.c @@ -157,6 +157,7 @@ flb_sds_t custom_calyptia_pipeline_config_get(struct flb_config *ctx) /* Config: [FILTER] */ mk_list_foreach(head, &ctx->filters) { f_ins = mk_list_entry(head, struct flb_filter_instance, _head); + flb_sds_printf(&buf, "[FILTER]\n"); flb_sds_printf(&buf, " name %s\n", f_ins->name); flb_sds_printf(&buf, " match %s\n", f_ins->match); @@ -168,6 +169,7 @@ flb_sds_t custom_calyptia_pipeline_config_get(struct flb_config *ctx) /* Config: [OUTPUT] */ mk_list_foreach(head, &ctx->outputs) { o_ins = mk_list_entry(head, struct flb_output_instance, _head); + flb_sds_printf(&buf, "[OUTPUT]\n"); flb_sds_printf(&buf, " name %s\n", o_ins->name); @@ -231,9 +233,9 @@ static struct flb_output_instance *setup_cloud_output(struct flb_config *config, int ret; struct flb_output_instance *cloud; struct mk_list *head; - struct flb_slist_entry *k = NULL; - struct flb_slist_entry *v = NULL; - flb_sds_t kv; + struct flb_slist_entry *key = NULL; + struct flb_slist_entry *val = NULL; + flb_sds_t label; struct flb_config_map_val *mv; cloud = flb_output_new(config, "calyptia", ctx, FLB_FALSE); @@ -254,20 +256,22 @@ static struct flb_output_instance *setup_cloud_output(struct flb_config *config, } if (ctx->add_labels && mk_list_size(ctx->add_labels) > 0) { + /* iterate all 'add_label' definitions */ flb_config_map_foreach(head, mv, ctx->add_labels) { - k = mk_list_entry_first(mv->val.list, struct flb_slist_entry, _head); - v = mk_list_entry_last(mv->val.list, struct flb_slist_entry, _head); - kv = flb_sds_create_size(strlen(k->str) + strlen(v->str) + 1); + key = mk_list_entry_first(mv->val.list, struct flb_slist_entry, _head); + val = mk_list_entry_last(mv->val.list, struct flb_slist_entry, _head); - if(!kv) { + label = flb_sds_create_size(strlen(key->str) + strlen(val->str) + 1); + + if(!label) { flb_free(ctx); return NULL; } - flb_sds_printf(&kv, "%s %s", k->str, v->str); - flb_output_set_property(cloud, "add_label", kv); - flb_sds_destroy(kv); + flb_sds_printf(&label, "%s %s", key->str, val->str); + flb_output_set_property(cloud, "add_label", label); + flb_sds_destroy(label); } } @@ -347,6 +351,7 @@ static int cb_calyptia_init(struct flb_custom_instance *ins, flb_plg_error(ctx->ins, "could not load metrics collector"); return -1; } + flb_input_set_property(ctx->i, "tag", "_calyptia_cloud"); flb_input_set_property(ctx->i, "scrape_on_start", "true"); flb_input_set_property(ctx->i, "scrape_interval", "30"); From 32c8bd1ab90d6e2fa55a16433bfbb9ea78bf6ccf Mon Sep 17 00:00:00 2001 From: Phillip Whelan Date: Mon, 21 Aug 2023 11:56:05 -0400 Subject: [PATCH 193/315] in_calyptia_fleet: use more understandable variable names. Signed-off-by: Phillip Whelan --- plugins/in_calyptia_fleet/in_calyptia_fleet.c | 90 +++++++++++-------- 1 file changed, 51 insertions(+), 39 deletions(-) diff --git a/plugins/in_calyptia_fleet/in_calyptia_fleet.c b/plugins/in_calyptia_fleet/in_calyptia_fleet.c index 85a91769743..fc5d0addbde 100644 --- a/plugins/in_calyptia_fleet/in_calyptia_fleet.c +++ b/plugins/in_calyptia_fleet/in_calyptia_fleet.c @@ -81,60 +81,61 @@ struct flb_in_calyptia_fleet_config { int collect_fd; }; -static char *find_case_header(struct flb_http_client *c, const char *header) +static char *find_case_header(struct flb_http_client *cli, const char *header) { - char *p; + char *ptr; char *headstart; - headstart = strstr(c->resp.data, "\r\n"); + headstart = strstr(cli->resp.data, "\r\n"); if (headstart == NULL) { return NULL; } /* Lookup the beginning of the header */ - for (p = headstart; p != NULL && p+2 < c->resp.payload; p = strstr(p, "\r\n")) { + for (ptr = headstart; ptr != NULL && ptr+2 < cli->resp.payload; ptr = strstr(ptr, "\r\n")) { - if (p + 4 < c->resp.payload && strcmp(p, "\r\n\r\n") == 0) { + if (ptr + 4 < cli->resp.payload && strcmp(ptr, "\r\n\r\n") == 0) { return NULL; } - p+=2; + ptr+=2; // no space left for header - if (p + strlen(header)+2 >= c->resp.payload) { + if (ptr + strlen(header)+2 >= cli->resp.payload) { return NULL; } // matched header and the delimiter - if (strncasecmp(p, header, strlen(header)) == 0) { + if (strncasecmp(ptr, header, strlen(header)) == 0) { - if (p[strlen(header)] == ':' && p[strlen(header)+1] == ' ') { - return p; + if (ptr[strlen(header)] == ':' && ptr[strlen(header)+1] == ' ') { + return ptr; } } } + return NULL; } /* Try to find a header value in the buffer. Copied from flb_http_client.c. */ -static int case_header_lookup(struct flb_http_client *c, +static int case_header_lookup(struct flb_http_client *cli, const char *header, int header_len, const char **out_val, int *out_len) { - char *p; + char *ptr; char *crlf; char *end; - if (!c->resp.data) { + if (!cli->resp.data) { return -1; } - p = find_case_header(c, header); - end = strstr(c->resp.data, "\r\n\r\n"); + ptr = find_case_header(cli, header); + end = strstr(cli->resp.data, "\r\n\r\n"); - if (!p) { + if (!ptr) { if (end) { /* The headers are complete but the header is not there */ @@ -146,21 +147,21 @@ static int case_header_lookup(struct flb_http_client *c, } /* Exclude matches in the body */ - if (end && p > end) { + if (end && ptr > end) { return -1; } /* Lookup CRLF (end of line \r\n) */ - crlf = strstr(p, "\r\n"); + crlf = strstr(ptr, "\r\n"); if (!crlf) { return -1; } - p += header_len + 2; + ptr += header_len + 2; - *out_val = p; - *out_len = (crlf - p); + *out_val = ptr; + *out_len = (crlf - ptr); return 0; } @@ -177,10 +178,12 @@ static flb_sds_t fleet_config_filename(struct flb_in_calyptia_fleet_config *ctx, cfgname = flb_sds_create_size(4096); if (ctx->fleet_name != NULL) { - flb_sds_printf(&cfgname, "%s" PATH_SEPARATOR "%s" PATH_SEPARATOR "%s.ini", ctx->config_dir, ctx->fleet_name, fname); + flb_sds_printf(&cfgname, "%s" PATH_SEPARATOR "%s" PATH_SEPARATOR "%s.ini", + ctx->config_dir, ctx->fleet_name, fname); } else { - flb_sds_printf(&cfgname, "%s" PATH_SEPARATOR "%s" PATH_SEPARATOR "%s.ini", ctx->config_dir, ctx->fleet_id, fname); + flb_sds_printf(&cfgname, "%s" PATH_SEPARATOR "%s" PATH_SEPARATOR "%s.ini", + ctx->config_dir, ctx->fleet_id, fname); } return cfgname; @@ -289,10 +292,12 @@ static int exists_cur_fleet_config(struct flb_in_calyptia_fleet_config *ctx) static void *do_reload(void *data) { struct reload_ctx *reload = (struct reload_ctx *)data; + // avoid reloading the current configuration... just use our new one! flb_context_set(reload->flb); reload->flb->config->enable_hot_reload = FLB_TRUE; reload->flb->config->conf_path_file = reload->cfg_path; + sleep(5); kill(getpid(), SIGHUP); @@ -302,7 +307,7 @@ static void *do_reload(void *data) static int test_config_is_valid(flb_sds_t cfgpath) { struct flb_config *config; - struct flb_cf *cf; + struct flb_cf *conf; int ret = FLB_FALSE; @@ -312,19 +317,19 @@ static int test_config_is_valid(flb_sds_t cfgpath) goto config_init_error; } - cf = flb_cf_create(); + conf = flb_cf_create(); - if (cf == NULL) { + if (conf == NULL) { goto cf_create_error; } - cf = flb_cf_create_from_file(cf, cfgpath); + conf = flb_cf_create_from_file(conf, cfgpath); - if (cf == NULL) { + if (conf == NULL) { goto cf_create_from_file_error; } - if (flb_config_load_config_format(config, cf)) { + if (flb_config_load_config_format(config, conf)) { goto cf_load_config_format_error; } @@ -337,7 +342,7 @@ static int test_config_is_valid(flb_sds_t cfgpath) cf_property_check_error: cf_load_config_format_error: cf_create_from_file_error: - flb_cf_destroy(cf); + flb_cf_destroy(conf); cf_create_error: flb_config_exit(config); config_init_error: @@ -399,7 +404,7 @@ static flb_sds_t parse_api_key_json(struct flb_in_calyptia_fleet_config *ctx, msgpack_object_kv *cur; msgpack_object_str *key; flb_sds_t project_id; - int i = 0; + int idx = 0; /* Initialize packer */ flb_pack_state_init(&pack_state); @@ -426,8 +431,8 @@ static flb_sds_t parse_api_key_json(struct flb_in_calyptia_fleet_config *ctx, while (msgpack_unpack_next(&result, pack, out_size, &off) == MSGPACK_UNPACK_SUCCESS) { if (result.data.type == MSGPACK_OBJECT_MAP) { - for (i = 0; i < result.data.via.map.size; i++) { - cur = &result.data.via.map.ptr[i]; + for (idx = 0; idx < result.data.via.map.size; idx++) { + cur = &result.data.via.map.ptr[idx]; key = &cur->key.via.str; if (strncmp(key->ptr, "ProjectID", key->size) == 0) { @@ -437,10 +442,13 @@ static flb_sds_t parse_api_key_json(struct flb_in_calyptia_fleet_config *ctx, msgpack_unpacked_destroy(&result); return NULL; } + project_id = flb_sds_create_len(cur->val.via.str.ptr, cur->val.via.str.size); + msgpack_unpacked_destroy(&result); flb_free(pack); + return project_id; } } @@ -465,7 +473,7 @@ static ssize_t parse_fleet_search_json(struct flb_in_calyptia_fleet_config *ctx, msgpack_object_array *results; msgpack_object_kv *cur; msgpack_object_str *key; - int i = 0; + int idx = 0; /* Initialize packer */ flb_pack_state_init(&pack_state); @@ -495,8 +503,9 @@ static ssize_t parse_fleet_search_json(struct flb_in_calyptia_fleet_config *ctx, results = &result.data.via.array; if (results->ptr[0].type == MSGPACK_OBJECT_MAP) { - for (i = 0; i < results->ptr[0].via.map.size; i++) { - cur = &results->ptr[0].via.map.ptr[i]; + + for (idx = 0; idx < results->ptr[0].via.map.size; idx++) { + cur = &results->ptr[0].via.map.ptr[idx]; key = &cur->key.via.str; if (strncasecmp(key->ptr, "id", key->size) == 0) { @@ -506,6 +515,7 @@ static ssize_t parse_fleet_search_json(struct flb_in_calyptia_fleet_config *ctx, msgpack_unpacked_destroy(&result); return -1; } + ctx->fleet_id = flb_sds_create_len(cur->val.via.str.ptr, cur->val.via.str.size); break; @@ -796,7 +806,8 @@ static int in_calyptia_fleet_collect(struct flb_input_instance *ins, flb_sds_destroy(cfgcurname); flb_sds_destroy(cfgoldname); goto reload_error; - } else { + } + else { FLB_INPUT_RETURN(0); } } @@ -846,7 +857,8 @@ static void load_fleet_config(struct flb_in_calyptia_fleet_config *ctx) // check which one and load it if (exists_cur_fleet_config(ctx) == FLB_TRUE) { execute_reload(ctx, cur_fleet_config_filename(ctx)); - } else if (exists_new_fleet_config(ctx) == FLB_TRUE) { + } + else if (exists_new_fleet_config(ctx) == FLB_TRUE) { execute_reload(ctx, new_fleet_config_filename(ctx)); } } @@ -968,7 +980,7 @@ static void cb_in_calyptia_fleet_resume(void *data, struct flb_config *config) static int in_calyptia_fleet_exit(void *data, struct flb_config *config) { (void) *config; - struct flb_in_calyptia_fleet_config *ctx = data; + struct flb_in_calyptia_fleet_config *ctx = (struct flb_in_calyptia_fleet_config *)data; flb_input_collector_delete(ctx->collect_fd, ctx->ins); flb_upstream_destroy(ctx->u); From fb7e0c59e39a1b37771c5e6c9a04c35d97df4d4d Mon Sep 17 00:00:00 2001 From: Takahiro Yamashita Date: Sun, 13 Aug 2023 08:35:28 +0900 Subject: [PATCH 194/315] tests: internal: lua: add test for flb_lua_arraylength Signed-off-by: Takahiro Yamashita --- tests/internal/lua.c | 73 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/tests/internal/lua.c b/tests/internal/lua.c index d71b462fad2..79071ae1792 100644 --- a/tests/internal/lua.c +++ b/tests/internal/lua.c @@ -204,6 +204,77 @@ static void test_tompack() lua_close(l); } + +static void test_lua_arraylength() +{ + lua_State *l; + int i; + int len; + int size = 10; + + l = luaL_newstate(); + if (!TEST_CHECK(l != NULL)) { + TEST_MSG("luaL_newstate faild"); + return; + } + luaL_openlibs(l); + + /* create array. */ + lua_createtable(l, size, 0); + + for (i=1; i<=size; i++) { + lua_pushinteger(l, i); /* set an index of array */ + lua_pushinteger(l, 3+i); /* set a value */ + lua_settable(l, -3); /* points created table */ + } + + len = flb_lua_arraylength(l); + if (!TEST_CHECK(len == size)) { + TEST_MSG("size error. got=%d expect=%d", len, size); + } + lua_pop(l, 1); + + lua_close(l); +} + +static void test_lua_arraylength_for_array_contains_nil() +{ + lua_State *l; + int i; + int len; + int size = 10; + + l = luaL_newstate(); + if (!TEST_CHECK(l != NULL)) { + TEST_MSG("luaL_newstate faild"); + return; + } + luaL_openlibs(l); + + /* create array. */ + lua_createtable(l, size, 0); + + for (i=1; i<=size; i++) { + lua_pushinteger(l, i); /* set an index of array */ + if (i == 7) { + lua_pushnil(l); + } + else { + lua_pushinteger(l, 3+i); /* set a value */ + } + lua_settable(l, -3); /* points created table */ + } + + len = flb_lua_arraylength(l); + if (!TEST_CHECK(len == size)) { + TEST_MSG("size error. got=%d expect=%d", len, size); + } + lua_pop(l, 1); + + lua_close(l); +} + + TEST_LIST = { { "lua_is_valid_func" , test_is_valid_func}, { "lua_pushtimetable" , test_pushtimetable}, @@ -211,5 +282,7 @@ TEST_LIST = { { "lua_pushmpack" , test_pushmpack }, { "lua_tomsgpack" , test_tomsgpack }, { "lua_tompack" , test_tompack }, + { "lua_arraylength" , test_lua_arraylength }, + { "lua_arraylength_for_array_contains_nil", test_lua_arraylength_for_array_contains_nil}, { 0 } }; From c03ec4360c47c6c507b19650cb9291ce98808ef8 Mon Sep 17 00:00:00 2001 From: Takahiro Yamashita Date: Sun, 13 Aug 2023 09:51:13 +0900 Subject: [PATCH 195/315] lua: add flb_lua_dump_stack Signed-off-by: Takahiro Yamashita --- include/fluent-bit/flb_lua.h | 14 ++++++ src/flb_lua.c | 84 ++++++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+) diff --git a/include/fluent-bit/flb_lua.h b/include/fluent-bit/flb_lua.h index 390a3bcba10..5b9dfa7d573 100644 --- a/include/fluent-bit/flb_lua.h +++ b/include/fluent-bit/flb_lua.h @@ -47,6 +47,19 @@ struct flb_lua_l2c_config { struct mk_list l2c_types; /* data types (lua -> C) */ }; +/* convert from negative index to positive index */ +static inline int flb_lua_absindex(lua_State *l , int index) +{ +#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM < 520 + if (index < 0) { + index = lua_gettop(l) + index + 1; + } +#else + index = lua_absindex(l, index); +#endif + return index; +} + int flb_lua_arraylength(lua_State *l); void flb_lua_pushtimetable(lua_State *l, struct flb_time *tm); int flb_lua_is_valid_func(lua_State *l, flb_sds_t func); @@ -60,5 +73,6 @@ void flb_lua_tompack(lua_State *l, mpack_writer_t *writer, int index, struct flb_lua_l2c_config *l2cc); +void flb_lua_dump_stack(FILE *out, lua_State *l); #endif diff --git a/src/flb_lua.c b/src/flb_lua.c index c6badec16bc..cd0988b7d86 100644 --- a/src/flb_lua.c +++ b/src/flb_lua.c @@ -584,3 +584,87 @@ void flb_lua_tomsgpack(lua_State *l, break; } } + +static void print_lua_value(FILE *out, lua_State *l, int index, int depth) +{ + int i; + int i_depth; + int type; + size_t len_s; + double val_d; + int64_t val_i; + int len_t; + + index = flb_lua_absindex(l, index); + + type = lua_type(l, index); + fprintf(out, "%s:", lua_typename(l, type)); + switch(type){ + case LUA_TSTRING: + fprintf(out, " %s\n", lua_tolstring(l,index, &len_s)); + break; + case LUA_TBOOLEAN: + fprintf(out, " %s\n", lua_toboolean(l, index) ? "true":"false"); + break; + case LUA_TNUMBER: + val_i = lua_tointeger(l, index); + val_d = lua_tonumber(l, index); + fprintf(out, " d=%lf i=%ld\n", val_d, val_i); + break; + case LUA_TTABLE: + len_t = flb_lua_arraylength(l); + fprintf(out, " size=%d ", len_t); + if (len_t > 0) { + fprintf(out, "array\n"); + for (i=1; i<=len_t; i++) { + for (i_depth=0; i_depth=1; i--) { + fprintf(out, "%03d: ", i); + print_lua_value(out, l, i, 2); + } + fprintf(out, "======\n"); +} From f70fc975fd7e7018095b959a1e346ff7e4106435 Mon Sep 17 00:00:00 2001 From: Takahiro Yamashita Date: Sun, 13 Aug 2023 10:10:57 +0900 Subject: [PATCH 196/315] lua: pass index to lua_arraylength Signed-off-by: Takahiro Yamashita --- include/fluent-bit/flb_lua.h | 2 +- src/flb_lua.c | 25 ++++++++++++++----------- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/include/fluent-bit/flb_lua.h b/include/fluent-bit/flb_lua.h index 5b9dfa7d573..b2787430284 100644 --- a/include/fluent-bit/flb_lua.h +++ b/include/fluent-bit/flb_lua.h @@ -60,7 +60,7 @@ static inline int flb_lua_absindex(lua_State *l , int index) return index; } -int flb_lua_arraylength(lua_State *l); +int flb_lua_arraylength(lua_State *l, int index); void flb_lua_pushtimetable(lua_State *l, struct flb_time *tm); int flb_lua_is_valid_func(lua_State *l, flb_sds_t func); int flb_lua_pushmpack(lua_State *l, mpack_reader_t *reader); diff --git a/src/flb_lua.c b/src/flb_lua.c index cd0988b7d86..a374752326c 100644 --- a/src/flb_lua.c +++ b/src/flb_lua.c @@ -209,18 +209,18 @@ static int lua_isinteger(lua_State *L, int index) * If we update luajit which is based Lua 5.2+, * this function should be removed. */ -static int lua_table_maxn(lua_State *l) +static int lua_table_maxn(lua_State *l, int index) { #if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM < 520 int ret = -1; - if (lua_type(l, -1) != LUA_TTABLE) { + if (lua_type(l, index) != LUA_TTABLE) { return -1; } lua_getglobal(l, "table"); lua_getfield(l, -1, "maxn"); lua_remove(l, -2); /* remove table (lua_getglobal(L, "table")) */ - lua_pushvalue(l, -2); /* copy record to top of stack */ + lua_pushvalue(l, index); /* copy record to top of stack */ ret = lua_pcall(l, 1, 1, 0); if (ret < 0) { flb_error("[filter_lua] failed to exec table.maxn ret=%d", ret); @@ -239,24 +239,26 @@ static int lua_table_maxn(lua_State *l) return ret; #else - return (int)lua_rawlen(l, 1); + return (int)lua_rawlen(l, index); #endif } -int flb_lua_arraylength(lua_State *l) +int flb_lua_arraylength(lua_State *l, int index) { lua_Integer n; int count = 0; int max = 0; int ret = 0; - ret = lua_table_maxn(l); + index = flb_lua_absindex(l, index); + + ret = lua_table_maxn(l, index); if (ret > 0) { return ret; } lua_pushnil(l); - while (lua_next(l, -2) != 0) { + while (lua_next(l, index) != 0) { if (lua_type(l, -2) == LUA_TNUMBER) { n = lua_tonumber(l, -2); if (n > 0) { @@ -269,8 +271,9 @@ int flb_lua_arraylength(lua_State *l) lua_pop(l, 2); return -1; } - if (max != count) + if (max != count) { return -1; + } return max; } @@ -442,7 +445,7 @@ void flb_lua_tompack(lua_State *l, mpack_write_false(writer); break; case LUA_TTABLE: - len = flb_lua_arraylength(l); + len = flb_lua_arraylength(l, -1 + index); if (len > 0) { mpack_write_tag(writer, mpack_tag_array(len)); for (i = 1; i <= len; i++) { @@ -533,7 +536,7 @@ void flb_lua_tomsgpack(lua_State *l, msgpack_pack_false(pck); break; case LUA_TTABLE: - len = flb_lua_arraylength(l); + len = flb_lua_arraylength(l, -1 + index); if (len > 0) { msgpack_pack_array(pck, len); for (i = 1; i <= len; i++) { @@ -612,7 +615,7 @@ static void print_lua_value(FILE *out, lua_State *l, int index, int depth) fprintf(out, " d=%lf i=%ld\n", val_d, val_i); break; case LUA_TTABLE: - len_t = flb_lua_arraylength(l); + len_t = flb_lua_arraylength(l, index); fprintf(out, " size=%d ", len_t); if (len_t > 0) { fprintf(out, "array\n"); From 07d1932881cb0a7c1f7689ae21f0aea4dbfbbd61 Mon Sep 17 00:00:00 2001 From: Takahiro Yamashita Date: Sun, 13 Aug 2023 10:11:13 +0900 Subject: [PATCH 197/315] tests: internal: lua: pass index to lua_arraylength Signed-off-by: Takahiro Yamashita --- tests/internal/lua.c | 41 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/tests/internal/lua.c b/tests/internal/lua.c index 79071ae1792..122748fbacd 100644 --- a/tests/internal/lua.c +++ b/tests/internal/lua.c @@ -228,7 +228,43 @@ static void test_lua_arraylength() lua_settable(l, -3); /* points created table */ } - len = flb_lua_arraylength(l); + len = flb_lua_arraylength(l, -1); + if (!TEST_CHECK(len == size)) { + TEST_MSG("size error. got=%d expect=%d", len, size); + } + lua_pop(l, 1); + + lua_close(l); +} + +static void test_lua_arraylength_with_index() +{ + lua_State *l; + int i; + int len; + int size = 10; + + l = luaL_newstate(); + if (!TEST_CHECK(l != NULL)) { + TEST_MSG("luaL_newstate faild"); + return; + } + luaL_openlibs(l); + + /* create array. */ + lua_createtable(l, size, 0); + + for (i=1; i<=size; i++) { + lua_pushinteger(l, i); /* set an index of array */ + lua_pushinteger(l, 3+i); /* set a value */ + lua_settable(l, -3); /* points created table */ + } + + /* push 2 values */ + lua_pushinteger(l, 100); + lua_pushinteger(l, 101); + + len = flb_lua_arraylength(l, -3); /* points array. -1 points 101, -2 points 100 */ if (!TEST_CHECK(len == size)) { TEST_MSG("size error. got=%d expect=%d", len, size); } @@ -265,7 +301,7 @@ static void test_lua_arraylength_for_array_contains_nil() lua_settable(l, -3); /* points created table */ } - len = flb_lua_arraylength(l); + len = flb_lua_arraylength(l, -1); if (!TEST_CHECK(len == size)) { TEST_MSG("size error. got=%d expect=%d", len, size); } @@ -283,6 +319,7 @@ TEST_LIST = { { "lua_tomsgpack" , test_tomsgpack }, { "lua_tompack" , test_tompack }, { "lua_arraylength" , test_lua_arraylength }, + { "lua_arraylength_with_index" , test_lua_arraylength_with_index }, { "lua_arraylength_for_array_contains_nil", test_lua_arraylength_for_array_contains_nil}, { 0 } }; From c878c7d392e66e94ed86edc8189e60da885fe68e Mon Sep 17 00:00:00 2001 From: David Korczynski Date: Tue, 8 Aug 2023 11:34:30 -0700 Subject: [PATCH 198/315] in_exec_wasi: fix possible file descriptor leak Signed-off-by: David Korczynski --- plugins/in_exec_wasi/in_exec_wasi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/in_exec_wasi/in_exec_wasi.c b/plugins/in_exec_wasi/in_exec_wasi.c index 704af9037a6..bf765430ddb 100644 --- a/plugins/in_exec_wasi/in_exec_wasi.c +++ b/plugins/in_exec_wasi/in_exec_wasi.c @@ -68,6 +68,7 @@ static int in_exec_wasi_collect(struct flb_input_instance *ins, if (ctx->oneshot == FLB_TRUE) { ret = flb_pipe_r(ctx->ch_manager[0], &val, sizeof(val)); if (ret == -1) { + fclose(stdoutp); flb_errno(); return -1; } From 7302149f1da6d62b75e66618d22e43c4d85947b8 Mon Sep 17 00:00:00 2001 From: David Korczynski Date: Tue, 8 Aug 2023 10:51:20 -0700 Subject: [PATCH 199/315] out_s3: fix potential file descriptor leak Signed-off-by: David Korczynski --- plugins/out_s3/s3.c | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/out_s3/s3.c b/plugins/out_s3/s3.c index f938cdaf51e..1718cc735d4 100644 --- a/plugins/out_s3/s3.c +++ b/plugins/out_s3/s3.c @@ -294,6 +294,7 @@ static int read_seq_index(char *seq_index_file, uint64_t *seq_index) ret = fscanf(fp, "%"PRIu64, seq_index); if (ret != 1) { + fclose(fp); flb_errno(); return -1; } From c48590a39072f1990d050738aa2b42ddeab7012f Mon Sep 17 00:00:00 2001 From: David Korczynski Date: Tue, 8 Aug 2023 10:59:32 -0700 Subject: [PATCH 200/315] out_s3: fix file descriptor leak Signed-off-by: David Korczynski --- plugins/out_s3/s3.c | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/out_s3/s3.c b/plugins/out_s3/s3.c index 1718cc735d4..57e68e6ef90 100644 --- a/plugins/out_s3/s3.c +++ b/plugins/out_s3/s3.c @@ -317,6 +317,7 @@ static int write_seq_index(char *seq_index_file, uint64_t seq_index) ret = fprintf(fp, "%"PRIu64, seq_index); if (ret < 0) { + fclose(fp); flb_errno(); return -1; } From 6148f401ae137e2e882a7baa74629cde5db59cce Mon Sep 17 00:00:00 2001 From: Phillip Whelan Date: Wed, 23 Aug 2023 10:46:08 -0400 Subject: [PATCH 201/315] config_format: yaml: suppress debug messages. Signed-off-by: Phillip Whelan --- src/config_format/flb_cf_yaml.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/config_format/flb_cf_yaml.c b/src/config_format/flb_cf_yaml.c index f8807704644..6eab59dc086 100644 --- a/src/config_format/flb_cf_yaml.c +++ b/src/config_format/flb_cf_yaml.c @@ -546,7 +546,7 @@ static int read_glob(struct flb_cf *conf, struct local_ctx *ctx, static void print_current_state(struct local_ctx *ctx, struct parser_state *state, yaml_event_t *event) { - flb_error("%*s%s->%s", state->level*2, "", state_str(state->state), + flb_debug("%*s%s->%s", state->level*2, "", state_str(state->state), event_type_str(event)); } @@ -557,21 +557,21 @@ static void print_current_properties(struct parser_state *state) struct cfl_variant *var; int idx; - flb_error("%*s[%s] PROPERTIES:", state->level*2, "", section_names[state->section]); + flb_debug("%*s[%s] PROPERTIES:", state->level*2, "", section_names[state->section]); cfl_list_foreach(head, &state->keyvals->list) { prop = cfl_list_entry(head, struct cfl_kvpair, _head); switch (prop->val->type) { case CFL_VARIANT_STRING: - flb_error("%*s%s: %s", (state->level+2)*2, "", prop->key, prop->val->data.as_string); + flb_debug("%*s%s: %s", (state->level+2)*2, "", prop->key, prop->val->data.as_string); break; case CFL_VARIANT_ARRAY: - flb_error("%*s%s: [", (state->level+2)*2, "", prop->key); + flb_debug("%*s%s: [", (state->level+2)*2, "", prop->key); for (idx = 0; idx < prop->val->data.as_array->entry_count; idx++) { var = cfl_array_fetch_by_index(prop->val->data.as_array, idx); - flb_error("%*s%s", (state->level+3)*2, "", var->data.as_string); + flb_debug("%*s%s", (state->level+3)*2, "", var->data.as_string); } - flb_error("%*s]", (state->level+2)*2, ""); + flb_debug("%*s]", (state->level+2)*2, ""); break; } } @@ -1982,7 +1982,7 @@ static int read_config(struct flb_cf *conf, struct local_ctx *ctx, return -1; } - flb_error("============ %s ============", cfg_file); + flb_debug("============ %s ============", cfg_file); fh = fopen(include_file, "r"); if (!fh) { @@ -2031,7 +2031,7 @@ static int read_config(struct flb_cf *conf, struct local_ctx *ctx, } while (state->state != STATE_STOP); - flb_error("=============================="); + flb_debug("=============================="); done: if (code == -1) { From c62d4c88e9b00eefdb09ac09b22296a89afa0d16 Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Tue, 29 Aug 2023 22:50:00 -0600 Subject: [PATCH 202/315] config_format: yaml: add support for idiomatic Yaml camelCase (fix #7593) The current Yaml reader is agnostic from the keys format, it only cares to convert them to lower case so the backend layer can configure the properties properly. The following is an non-idiomatic example: env: flushInterval: 1 service: flush: ${flushInterval} pipeline: inputs: - name: random Interval_Sec: 1 filters: - name: record_modifier match: "*" record: powered_by calyptia uuid_key: abc outputs: - name: stdout match: "*" The following patch make the Yaml parser to be idiomatic by supporting a compatible layer with camelCase style for key names, e.g: env: flushInterval: 1 service: flush: ${flushInterval} pipeline: inputs: - name: random intervalSec: 1 filters: - name: record_modifier match: "*" record: powered_by calyptia uuidKey: abc outputs: - name: stdout match: "*" Signed-off-by: Eduardo Silva --- include/fluent-bit/config_format/flb_cf.h | 7 ++ src/config_format/flb_cf_fluentbit.c | 2 + src/config_format/flb_cf_yaml.c | 3 +- src/config_format/flb_config_format.c | 95 +++++++++++++++++++---- 4 files changed, 92 insertions(+), 15 deletions(-) diff --git a/include/fluent-bit/config_format/flb_cf.h b/include/fluent-bit/config_format/flb_cf.h index 4240f539930..752e333b4a3 100644 --- a/include/fluent-bit/config_format/flb_cf.h +++ b/include/fluent-bit/config_format/flb_cf.h @@ -50,6 +50,8 @@ enum cf_file_format { #endif }; +#define FLB_CF_CLASSIC FLB_CF_FLUENTBIT + enum section_type { FLB_CF_SERVICE = 0, /* [SERVICE] */ FLB_CF_PARSER, /* [PARSER] */ @@ -79,6 +81,9 @@ struct flb_cf_section { }; struct flb_cf { + /* origin format */ + int format; + /* global service */ struct flb_cf_section *service; @@ -117,9 +122,11 @@ struct flb_cf { struct flb_cf *flb_cf_create(); struct flb_cf *flb_cf_create_from_file(struct flb_cf *cf, char *file); +flb_sds_t flb_cf_key_translate(struct flb_cf *cf, char *key, int len); void flb_cf_destroy(struct flb_cf *cf); +int flb_cf_set_origin_format(struct flb_cf *cf, int format); void flb_cf_dump(struct flb_cf *cf); struct flb_kv *flb_cf_env_property_add(struct flb_cf *cf, diff --git a/src/config_format/flb_cf_fluentbit.c b/src/config_format/flb_cf_fluentbit.c index ac72f9425e4..a775fffe0b2 100644 --- a/src/config_format/flb_cf_fluentbit.c +++ b/src/config_format/flb_cf_fluentbit.c @@ -776,6 +776,8 @@ struct flb_cf *flb_cf_fluentbit_create(struct flb_cf *cf, if (!cf) { return NULL; } + + flb_cf_set_origin_format(cf, FLB_CF_CLASSIC); } ret = local_init(&ctx, file_path); diff --git a/src/config_format/flb_cf_yaml.c b/src/config_format/flb_cf_yaml.c index 6eab59dc086..4ef77a578a1 100644 --- a/src/config_format/flb_cf_yaml.c +++ b/src/config_format/flb_cf_yaml.c @@ -2074,10 +2074,11 @@ struct flb_cf *flb_cf_yaml_create(struct flb_cf *conf, char *file_path, if (!conf) { conf = flb_cf_create(); - if (!conf) { return NULL; } + + flb_cf_set_origin_format(conf, FLB_CF_YAML); } /* initialize the parser state */ diff --git a/src/config_format/flb_config_format.c b/src/config_format/flb_config_format.c index 8ae8477475e..fd008ec6546 100644 --- a/src/config_format/flb_config_format.c +++ b/src/config_format/flb_config_format.c @@ -34,6 +34,67 @@ int flb_cf_file_read() return 0; } +/* Retrieve the proper key name, it tries to auto-detect Yaml camelcase and convert it to snake_case */ +flb_sds_t flb_cf_key_translate(struct flb_cf *cf, char *key, int len) +{ + int i; + int x = 0; + int is_upper; + flb_sds_t out; + + if (!key || len <= 0) { + return NULL; + } + + /* If we got something in classic format, just convert it to lowercase and return */ + if (cf->format == FLB_CF_CLASSIC) { + out = flb_sds_create_len(key, len); + if (!out) { + return NULL; + } + + for (i = 0; i < len; i++) { + out[i] = tolower(key[i]); + } + flb_sds_len_set(out, len); + return out; + } + + /* + * First step is try to identify if the incoming key is a strict Yaml camelcase format + */ + + /* does it start with a lowercase character ? */ + if (!islower(key[0])) { + return flb_sds_create_len(key, len); + } + + /* copy content and check if we have underscores */ + out = flb_sds_create_len(key, len); + for (i = 0; i < len; i++) { + if (key[i] == '_') { + /* the config is classic mode, so it's safe to return the same copy of the content */ + for (i = 0; i < len; i++) { + out[i] = tolower(key[i]); + } + flb_sds_len_set(out, len); + return out; + } + } + + /* translate from camelCase to snake_case */ + for (i = 0; i < len; i++) { + is_upper = isupper(key[i]); + if (is_upper && i > 0) { + out[x++] = '_'; + } + out[x++] = tolower(key[i]); + + } + flb_sds_len_set(out, x); + return out; +} + struct flb_cf *flb_cf_create() { struct flb_cf *ctx; @@ -43,6 +104,7 @@ struct flb_cf *flb_cf_create() flb_errno(); return NULL; } + ctx->format = -1; /* env vars */ mk_list_init(&ctx->env); @@ -79,6 +141,16 @@ void flb_cf_destroy(struct flb_cf *cf) flb_free(cf); } +int flb_cf_set_origin_format(struct flb_cf *cf, int format) +{ + if (format != FLB_CF_CLASSIC && format != FLB_CF_YAML) { + return -1; + } + + cf->format = format; + return 0; +} + static enum section_type get_section_type(char *name, int len) { if (strncasecmp(name, "SERVICE", len) == 0) { @@ -126,7 +198,8 @@ int flb_cf_plugin_property_add(struct flb_cf *cf, v_len = strlen(v_buf); } - key = flb_sds_create_len(k_buf, k_len); + + key = flb_cf_key_translate(cf, k_buf, k_len); if (key == NULL) { return -1; } @@ -165,17 +238,16 @@ struct cfl_variant *flb_cf_section_property_add(struct flb_cf *cf, char *k_buf, size_t k_len, char *v_buf, size_t v_len) { - int i; int rc; flb_sds_t key; flb_sds_t val; struct cfl_variant *var; - if (k_len == 0) { k_len = strlen(k_buf); } - key = flb_sds_create_len(k_buf, k_len); + + key = flb_cf_key_translate(cf, k_buf, k_len); if (key == NULL) { goto key_error; } @@ -187,10 +259,6 @@ struct cfl_variant *flb_cf_section_property_add(struct flb_cf *cf, goto val_error; } - for (i = 0; i < flb_sds_len(key); i++) { - key[i] = tolower(key[i]); - } - if (v_len == 0) { v_len = strlen(v_buf); } @@ -241,7 +309,8 @@ struct cfl_array *flb_cf_section_property_add_list(struct flb_cf *cf, if (k_len == 0) { k_len = strlen(k_buf); } - key = flb_sds_create_len(k_buf, k_len); + + key = flb_cf_key_translate(cf, k_buf, k_len); if (key == NULL) { goto key_error; } @@ -284,12 +353,10 @@ flb_sds_t flb_cf_section_property_get_string(struct flb_cf *cf, struct flb_cf_se flb_sds_t ret = NULL; struct cfl_variant *entry; int i; + int len; - - tkey = flb_sds_create(key); - for (i = 0; i < strlen(key); i++) { - tkey[i] = tolower(key[i]); - } + len = strlen(key); + tkey = flb_cf_key_translate(cf, key, len); val = cfl_kvlist_fetch(s->properties, key); flb_sds_destroy(tkey); From ea49619556000fa2f6c71456afe6200caa8a51c4 Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Tue, 29 Aug 2023 22:58:09 -0600 Subject: [PATCH 203/315] tests: internal: config_format: yaml: add tests for idiomatic Yaml Signed-off-by: Eduardo Silva --- tests/internal/config_format_yaml.c | 54 ++++++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 5 deletions(-) diff --git a/tests/internal/config_format_yaml.c b/tests/internal/config_format_yaml.c index dac39f7d24c..33a4f783f92 100644 --- a/tests/internal/config_format_yaml.c +++ b/tests/internal/config_format_yaml.c @@ -29,7 +29,7 @@ */ /* data/config_format/fluent-bit.yaml */ -void test_basic() +static void test_basic() { struct mk_list *head; struct flb_cf *cf; @@ -141,7 +141,7 @@ void test_basic() } /* https://github.com/fluent/fluent-bit/issues/7559 */ -void test_customs_section() +static void test_customs_section() { struct flb_cf *cf; struct flb_cf_section *s; @@ -167,7 +167,7 @@ void test_customs_section() flb_cf_destroy(cf); } -void test_slist_even() +static void test_slist_even() { struct flb_cf *cf; struct flb_cf_section *s; @@ -200,7 +200,7 @@ void test_slist_even() flb_cf_destroy(cf); } -void test_slist_odd() +static void test_slist_odd() { struct flb_cf *cf; struct flb_cf_section *s; @@ -233,7 +233,8 @@ void test_slist_odd() flb_cf_destroy(cf); } -void test_parser_conf() + +static void test_parser_conf() { struct flb_cf *cf; struct flb_config *config; @@ -270,11 +271,54 @@ void test_parser_conf() flb_config_exit(config); } +static inline int check_camel_to_snake(char *input, char *output) +{ + int len; + int ret; + flb_sds_t out; + struct flb_cf *cf; + + + cf = flb_cf_create(); + flb_cf_set_origin_format(cf, FLB_CF_YAML); + + len = strlen(input); + out = flb_cf_key_translate(cf, input, len); + + ret = strcmp(out, output); + + flb_sds_destroy(out); + + if (ret == 0) { + return FLB_TRUE; + } + + return FLB_FALSE; +} + + +static void test_camel_case_key() +{ + /* normal conversion */ + TEST_CHECK(check_camel_to_snake("a", "a") == FLB_TRUE); + TEST_CHECK(check_camel_to_snake("aB", "a_b") == FLB_TRUE); + TEST_CHECK(check_camel_to_snake("aBc", "a_bc") == FLB_TRUE); + TEST_CHECK(check_camel_to_snake("aBcA", "a_bc_a") == FLB_TRUE); + TEST_CHECK(check_camel_to_snake("aBCD", "a_b_c_d") == FLB_TRUE); + TEST_CHECK(check_camel_to_snake("intervalSec", "interval_sec") == FLB_TRUE); + + /* unsupported conversion, we force lowercase in Yaml */ + TEST_CHECK(check_camel_to_snake("AA", "AA") == FLB_TRUE); + TEST_CHECK(check_camel_to_snake("Interval_Sec", "Interval_Sec") == FLB_TRUE); + +} + TEST_LIST = { { "basic" , test_basic}, { "customs section", test_customs_section}, { "slist odd", test_slist_odd}, { "slist even", test_slist_even}, { "parsers file conf", test_parser_conf}, + { "camel_case_key", test_camel_case_key}, { 0 } }; From 9b01b9c40fcdba69a7e66d04d4a80c980af2924a Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Tue, 29 Aug 2023 22:58:24 -0600 Subject: [PATCH 204/315] tests: internal: config_format: yaml: add tests for snake_case format Signed-off-by: Eduardo Silva --- tests/internal/config_format_fluentbit.c | 36 +++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/tests/internal/config_format_fluentbit.c b/tests/internal/config_format_fluentbit.c index 5104ae62032..ca6ad8ab995 100644 --- a/tests/internal/config_format_fluentbit.c +++ b/tests/internal/config_format_fluentbit.c @@ -262,7 +262,6 @@ void not_current_dir_files() /* data/config_format/nolimitline.conf */ void test_nolimit_line() { - struct mk_list *head; struct flb_cf *cf; struct flb_cf_section *s; struct cfl_list *p_head; @@ -306,6 +305,40 @@ void test_nolimit_line() flb_cf_destroy(cf); } +static inline int check_snake_case(char *input, char *output) +{ + int len; + int ret; + flb_sds_t out; + struct flb_cf *cf; + + + cf = flb_cf_create(); + flb_cf_set_origin_format(cf, FLB_CF_CLASSIC); + + len = strlen(input); + out = flb_cf_key_translate(cf, input, len); + + ret = strcmp(out, output); + + flb_sds_destroy(out); + + if (ret == 0) { + return FLB_TRUE; + } + + return FLB_FALSE; +} + +static void test_snake_case_key() +{ + /* normal conversion */ + TEST_CHECK(check_snake_case("a", "a") == FLB_TRUE); + TEST_CHECK(check_snake_case("aB", "ab") == FLB_TRUE); + TEST_CHECK(check_snake_case("aBc", "abc") == FLB_TRUE); + TEST_CHECK(check_snake_case("interval_Sec", "interval_sec") == FLB_TRUE); +} + TEST_LIST = { { "basic" , test_basic}, { "missing_value_issue5880" , missing_value}, @@ -313,5 +346,6 @@ TEST_LIST = { { "recursion" , recursion}, { "not_current_dir_files", not_current_dir_files}, { "no_limit_line", test_nolimit_line}, + { "snake_case_key", test_snake_case_key}, { 0 } }; From 6c76c022edcd92bd517fd37ab72a7406201dc490 Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Tue, 29 Aug 2023 23:21:04 -0600 Subject: [PATCH 205/315] config_format: initialize as classic mode Signed-off-by: Eduardo Silva --- src/config_format/flb_config_format.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config_format/flb_config_format.c b/src/config_format/flb_config_format.c index fd008ec6546..e5858a49d84 100644 --- a/src/config_format/flb_config_format.c +++ b/src/config_format/flb_config_format.c @@ -104,7 +104,7 @@ struct flb_cf *flb_cf_create() flb_errno(); return NULL; } - ctx->format = -1; + ctx->format = FLB_CF_CLASSIC; /* env vars */ mk_list_init(&ctx->env); From b1726462c24dfe4d908474d38825bf141964e75d Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Wed, 30 Aug 2023 08:42:32 -0600 Subject: [PATCH 206/315] config_format: allocate double space for camel conversion Signed-off-by: Eduardo Silva --- src/config_format/flb_config_format.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/config_format/flb_config_format.c b/src/config_format/flb_config_format.c index e5858a49d84..688e47a77b5 100644 --- a/src/config_format/flb_config_format.c +++ b/src/config_format/flb_config_format.c @@ -70,7 +70,9 @@ flb_sds_t flb_cf_key_translate(struct flb_cf *cf, char *key, int len) } /* copy content and check if we have underscores */ - out = flb_sds_create_len(key, len); + out = flb_sds_create_size(len * 2); + flb_sds_cat_safe(&out, key, len); + for (i = 0; i < len; i++) { if (key[i] == '_') { /* the config is classic mode, so it's safe to return the same copy of the content */ @@ -91,6 +93,7 @@ flb_sds_t flb_cf_key_translate(struct flb_cf *cf, char *key, int len) out[x++] = tolower(key[i]); } + out[x] = '\0'; flb_sds_len_set(out, x); return out; } From 0c0e6588c0f4eae69efd33e019f4351d147bad4f Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Wed, 30 Aug 2023 08:43:11 -0600 Subject: [PATCH 207/315] tests: internal: config_format: yaml: destroy context after test Signed-off-by: Eduardo Silva --- tests/internal/config_format_yaml.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/internal/config_format_yaml.c b/tests/internal/config_format_yaml.c index 33a4f783f92..3135022baa5 100644 --- a/tests/internal/config_format_yaml.c +++ b/tests/internal/config_format_yaml.c @@ -274,11 +274,10 @@ static void test_parser_conf() static inline int check_camel_to_snake(char *input, char *output) { int len; - int ret; + int ret = -1; flb_sds_t out; struct flb_cf *cf; - cf = flb_cf_create(); flb_cf_set_origin_format(cf, FLB_CF_YAML); @@ -286,9 +285,10 @@ static inline int check_camel_to_snake(char *input, char *output) out = flb_cf_key_translate(cf, input, len); ret = strcmp(out, output); - flb_sds_destroy(out); + flb_cf_destroy(cf); + if (ret == 0) { return FLB_TRUE; } From 1d62291f7ae436da11939e909b9cd073ec7ee5de Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Wed, 30 Aug 2023 08:43:27 -0600 Subject: [PATCH 208/315] tests: internal: config_format: fluentbit: destroy context after test Signed-off-by: Eduardo Silva --- tests/internal/config_format_fluentbit.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/internal/config_format_fluentbit.c b/tests/internal/config_format_fluentbit.c index ca6ad8ab995..3f158573963 100644 --- a/tests/internal/config_format_fluentbit.c +++ b/tests/internal/config_format_fluentbit.c @@ -323,6 +323,8 @@ static inline int check_snake_case(char *input, char *output) flb_sds_destroy(out); + flb_cf_destroy(cf); + if (ret == 0) { return FLB_TRUE; } From 91c1a9e613ff11151eb7d4f7ae62f0a6747229a7 Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Wed, 30 Aug 2023 10:29:42 -0600 Subject: [PATCH 209/315] config_format: check if Yaml support exists before using FLB_CF_YAML Signed-off-by: Eduardo Silva --- src/config_format/flb_config_format.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/config_format/flb_config_format.c b/src/config_format/flb_config_format.c index 688e47a77b5..3a62fc9e219 100644 --- a/src/config_format/flb_config_format.c +++ b/src/config_format/flb_config_format.c @@ -146,7 +146,11 @@ void flb_cf_destroy(struct flb_cf *cf) int flb_cf_set_origin_format(struct flb_cf *cf, int format) { +#ifdef FLB_HAVE_LIBYAML if (format != FLB_CF_CLASSIC && format != FLB_CF_YAML) { +#else + if (format != FLB_CF_CLASSIC) { +#endif return -1; } From 6b9d50e260ac18118b296613366704d388f9ad02 Mon Sep 17 00:00:00 2001 From: Leonardo Alminana Date: Thu, 31 Aug 2023 16:38:12 +0200 Subject: [PATCH 210/315] out_splunk: release flb_ra_translate result buffer on failure Signed-off-by: Leonardo Alminana --- plugins/out_splunk/splunk.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plugins/out_splunk/splunk.c b/plugins/out_splunk/splunk.c index e9ce5a1bc13..d9c28380ab0 100644 --- a/plugins/out_splunk/splunk.c +++ b/plugins/out_splunk/splunk.c @@ -268,6 +268,10 @@ static inline int pack_event_key(struct flb_splunk *ctx, msgpack_packer *mp_pck, t = flb_time_to_double(tm); val = flb_ra_translate(ctx->ra_event_key, tag, tag_len, map, NULL); if (!val || flb_sds_len(val) == 0) { + if (val != NULL) { + flb_sds_destroy(val); + } + return -1; } From 9c74f217a6cab8ed90752677fd5fb8517efbffbf Mon Sep 17 00:00:00 2001 From: David Korczynski Date: Mon, 28 Aug 2023 03:22:01 -0700 Subject: [PATCH 211/315] config_format: yaml: fix null dereference Signed-off-by: David Korczynski --- src/config_format/flb_cf_yaml.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/config_format/flb_cf_yaml.c b/src/config_format/flb_cf_yaml.c index 4ef77a578a1..5fc42bdcb1d 100644 --- a/src/config_format/flb_cf_yaml.c +++ b/src/config_format/flb_cf_yaml.c @@ -1285,13 +1285,13 @@ static int consume_event(struct flb_cf *conf, struct local_ctx *ctx, break; case YAML_SEQUENCE_START_EVENT: /* start a new group */ - if (strcmp(state->key, "processors") == 0) { - yaml_error_event(ctx, state, event); + if (state->key == NULL) { + flb_error("no key"); return YAML_FAILURE; } - if (state->key == NULL) { - flb_error("no key"); + if (strcmp(state->key, "processors") == 0) { + yaml_error_event(ctx, state, event); return YAML_FAILURE; } From c9f38e1f5b1f7698799ff281b454f9335c451b96 Mon Sep 17 00:00:00 2001 From: Hiroshi Hatake Date: Mon, 28 Aug 2023 15:59:06 +0900 Subject: [PATCH 212/315] in_node_exporter_metrics: Fix registering callback for systemd Signed-off-by: Hiroshi Hatake --- plugins/in_node_exporter_metrics/ne.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/plugins/in_node_exporter_metrics/ne.c b/plugins/in_node_exporter_metrics/ne.c index cc4fd9599db..d7781795788 100644 --- a/plugins/in_node_exporter_metrics/ne.c +++ b/plugins/in_node_exporter_metrics/ne.c @@ -391,6 +391,7 @@ static int in_ne_init(struct flb_input_instance *in, ctx->coll_netdev_fd = -1; ctx->coll_filefd_fd = -1; ctx->coll_textfile_fd = -1; + ctx->coll_systemd_fd = -1; ctx->callback = flb_callback_create(in->name); if (!ctx->callback) { @@ -680,12 +681,12 @@ static int in_ne_init(struct flb_input_instance *in, } ne_textfile_init(ctx); } - else if (strncmp(entry->str, "systemd", 8) == 0) { + else if (strncmp(entry->str, "systemd", 7) == 0) { if (ctx->systemd_scrape_interval == 0) { flb_plg_debug(ctx->ins, "enabled metrics %s", entry->str); metric_idx = 13; } - else if (ctx->textfile_scrape_interval > 0) { + else if (ctx->systemd_scrape_interval > 0) { /* Create the filefd collector */ ret = flb_input_set_collector_time(in, ne_timer_systemd_metrics_cb, @@ -782,7 +783,7 @@ static int in_ne_exit(void *data, struct flb_config *config) else if (strncmp(entry->str, "textfile", 8) == 0) { /* nop */ } - else if (strncmp(entry->str, "systemd", 8) == 0) { + else if (strncmp(entry->str, "systemd", 7) == 0) { ne_systemd_exit(ctx); } else { @@ -813,6 +814,9 @@ static int in_ne_exit(void *data, struct flb_config *config) if (ctx->coll_netdev_fd != -1) { ne_netdev_exit(ctx); } + if (ctx->coll_systemd_fd != -1) { + ne_systemd_exit(ctx); + } flb_ne_config_destroy(ctx); From 996d5697e77231f7436ae99be457cebb7590505f Mon Sep 17 00:00:00 2001 From: Hiroshi Hatake Date: Fri, 1 Sep 2023 04:00:20 +0900 Subject: [PATCH 213/315] in_windows_exporter_metrics: Implement WMI based process metrics (#7860) --------- Signed-off-by: Hiroshi Hatake --- .../CMakeLists.txt | 1 + plugins/in_windows_exporter_metrics/we.c | 82 +++- plugins/in_windows_exporter_metrics/we.h | 27 ++ .../in_windows_exporter_metrics/we_config.c | 19 + .../we_wmi_process.c | 417 ++++++++++++++++++ .../we_wmi_process.h | 29 ++ 6 files changed, 572 insertions(+), 3 deletions(-) create mode 100644 plugins/in_windows_exporter_metrics/we_wmi_process.c create mode 100644 plugins/in_windows_exporter_metrics/we_wmi_process.h diff --git a/plugins/in_windows_exporter_metrics/CMakeLists.txt b/plugins/in_windows_exporter_metrics/CMakeLists.txt index 4474e1ce166..8cc7fe70a90 100644 --- a/plugins/in_windows_exporter_metrics/CMakeLists.txt +++ b/plugins/in_windows_exporter_metrics/CMakeLists.txt @@ -17,6 +17,7 @@ set(src we_wmi_service.c we_wmi_memory.c we_wmi_paging_file.c + we_wmi_process.c ) set(libs diff --git a/plugins/in_windows_exporter_metrics/we.c b/plugins/in_windows_exporter_metrics/we.c index 5dd3631ec95..0f99fb83f45 100644 --- a/plugins/in_windows_exporter_metrics/we.c +++ b/plugins/in_windows_exporter_metrics/we.c @@ -43,6 +43,7 @@ #include "we_wmi_service.h" #include "we_wmi_memory.h" #include "we_wmi_paging_file.h" +#include "we_wmi_process.h" static int we_timer_cpu_metrics_cb(struct flb_input_instance *ins, struct flb_config *config, void *in_context) @@ -164,6 +165,16 @@ static int we_timer_wmi_paging_file_metrics_cb(struct flb_input_instance *ins, return 0; } +static int we_timer_wmi_process_metrics_cb(struct flb_input_instance *ins, + struct flb_config *config, void *in_context) +{ + struct flb_ne *ctx = in_context; + + we_wmi_process_update(ctx); + + return 0; +} + struct flb_we_callback { char *name; void (*func)(char *, void *, void *); @@ -300,6 +311,13 @@ static void we_wmi_paging_file_update_cb(char *name, void *p1, void *p2) we_wmi_paging_file_update(ctx); } +static void we_wmi_process_update_cb(char *name, void *p1, void *p2) +{ + struct flb_we *ctx = p1; + + we_wmi_process_update(ctx); +} + static int we_update_cb(struct flb_we *ctx, char *name) { int ret; @@ -325,6 +343,7 @@ struct flb_we_callback ne_callbacks[] = { { "service", we_wmi_service_update_cb }, { "memory", we_wmi_memory_update_cb }, { "paging_file", we_wmi_paging_file_update_cb }, + { "process", we_wmi_process_update_cb }, { 0 } }; @@ -361,6 +380,7 @@ static int in_we_init(struct flb_input_instance *in, ctx->coll_wmi_service_fd = -1; ctx->coll_wmi_memory_fd = -1; ctx->coll_wmi_paging_file_fd = -1; + ctx->coll_wmi_process_fd = -1; ctx->callback = flb_callback_create(in->name); if (!ctx->callback) { @@ -545,7 +565,8 @@ static int in_we_init(struct flb_input_instance *in, if (ctx->cs_scrape_interval == 0) { flb_plg_debug(ctx->ins, "enabled metrics %s", entry->str); metric_idx = 5; - } else { + } + else { /* Create the logical_disk collector */ ret = flb_input_set_collector_time(in, we_timer_cs_metrics_cb, @@ -669,7 +690,8 @@ static int in_we_init(struct flb_input_instance *in, if (ctx->wmi_memory_scrape_interval == 0) { flb_plg_debug(ctx->ins, "enabled metrics %s", entry->str); metric_idx = 10; - } else { + } + else { /* Create the memory collector */ ret = flb_input_set_collector_time(in, we_timer_wmi_memory_metrics_cb, @@ -693,7 +715,8 @@ static int in_we_init(struct flb_input_instance *in, if (ctx->wmi_paging_file_scrape_interval == 0) { flb_plg_debug(ctx->ins, "enabled metrics %s", entry->str); metric_idx = 11; - } else { + } + else { /* Create the paging_file collector */ ret = flb_input_set_collector_time(in, we_timer_wmi_paging_file_metrics_cb, @@ -713,6 +736,31 @@ static int in_we_init(struct flb_input_instance *in, return -1; } } + else if (strncmp(entry->str, "process", 7) == 0) { + if (ctx->wmi_process_scrape_interval == 0) { + flb_plg_debug(ctx->ins, "enabled metrics %s", entry->str); + metric_idx = 12; + } + else { + /* Create the process collector */ + ret = flb_input_set_collector_time(in, + we_timer_wmi_process_metrics_cb, + ctx->wmi_process_scrape_interval, 0, + config); + if (ret == -1) { + flb_plg_error(ctx->ins, + "could not set process collector for Windows Exporter Metrics plugin"); + return -1; + } + ctx->coll_wmi_process_fd = ret; + } + + /* Initialize paging_file metric collectors */ + ret = we_wmi_process_init(ctx); + if (ret) { + return -1; + } + } else { flb_plg_warn(ctx->ins, "Unknown metrics: %s", entry->str); metric_idx = -1; @@ -792,6 +840,9 @@ static int in_we_exit(void *data, struct flb_config *config) else if (strncmp(entry->str, "paging_file", 11) == 0) { we_wmi_paging_file_exit(ctx); } + else if (strncmp(entry->str, "process", 7) == 0) { + we_wmi_process_exit(ctx); + } else { flb_plg_warn(ctx->ins, "Unknown metrics: %s", entry->str); } @@ -838,6 +889,9 @@ static int in_we_exit(void *data, struct flb_config *config) if (ctx->coll_wmi_paging_file_fd != -1) { we_wmi_paging_file_exit(ctx); } + if (ctx->coll_wmi_process_fd != -1) { + we_wmi_process_exit(ctx); + } flb_we_config_destroy(ctx); @@ -887,6 +941,9 @@ static void in_we_pause(void *data, struct flb_config *config) if (ctx->coll_wmi_paging_file_fd != -1) { flb_input_collector_pause(ctx->coll_wmi_paging_file_fd, ctx->ins); } + if (ctx->coll_wmi_process_fd != -1) { + flb_input_collector_pause(ctx->coll_wmi_process_fd, ctx->ins); + } } static void in_we_resume(void *data, struct flb_config *config) @@ -905,6 +962,9 @@ static void in_we_resume(void *data, struct flb_config *config) if (ctx->coll_logical_disk_fd != -1) { flb_input_collector_resume(ctx->coll_logical_disk_fd, ctx->ins); } + if (ctx->coll_wmi_process_fd != -1) { + flb_input_collector_resume(ctx->coll_wmi_process_fd, ctx->ins); + } if (ctx->coll_cs_fd != -1) { flb_input_collector_resume(ctx->coll_cs_fd, ctx->ins); } @@ -1014,6 +1074,12 @@ static struct flb_config_map config_map[] = { "scrape interval to collect paging_file metrics from the node." }, + { + FLB_CONFIG_MAP_TIME, "collector.process.scrape_interval", "0", + 0, FLB_TRUE, offsetof(struct flb_we, wmi_process_scrape_interval), + "scrape interval to collect process metrics from the node." + }, + { FLB_CONFIG_MAP_CLIST, "metrics", "cpu,cpu_info,os,net,logical_disk,cs,thermalzone,logon,system,service", @@ -1050,6 +1116,16 @@ static struct flb_config_map config_map[] = { 0, FLB_TRUE, offsetof(struct flb_we, raw_service_exclude), "Specify the key value condition pairs for excludeing condition to construct where clause of service metrics." }, + { + FLB_CONFIG_MAP_STR, "we.process.allow_process_regex", "/.+/", + 0, FLB_TRUE, offsetof(struct flb_we, raw_allowing_process), + "Specify the regex covering the process metrics to collect." + }, + { + FLB_CONFIG_MAP_STR, "we.process.deny_process_regex", NULL, + 0, FLB_TRUE, offsetof(struct flb_we, raw_denying_process), + "Specify the regex for process metrics to prevent collection of/ignore." + }, /* EOF */ {0} }; diff --git a/plugins/in_windows_exporter_metrics/we.h b/plugins/in_windows_exporter_metrics/we.h index 08d14f9a580..1ec848893b9 100644 --- a/plugins/in_windows_exporter_metrics/we.h +++ b/plugins/in_windows_exporter_metrics/we.h @@ -199,6 +199,26 @@ struct we_wmi_paging_file_counters { int operational; }; +struct we_wmi_process_counters { + struct wmi_query_spec *info; + struct cmt_gauge *start_time; + struct cmt_gauge *handles; + struct cmt_gauge *cpu_time_total; + struct cmt_gauge *io_bytes_total; + struct cmt_gauge *io_operations_total; + struct cmt_gauge *page_faults_total; + struct cmt_gauge *page_file_bytes; + struct cmt_gauge *pool_bytes; + struct cmt_gauge *priority_base; + struct cmt_gauge *thread_count; + struct cmt_gauge *private_bytes; + struct cmt_gauge *virtual_bytes; + struct cmt_gauge *working_set_private_bytes; + struct cmt_gauge *working_set_peak_bytes; + struct cmt_gauge *working_set_bytes; + int operational; +}; + struct we_os_counters { struct cmt_gauge *info; struct cmt_gauge *users; @@ -235,6 +255,8 @@ struct flb_we { char *raw_where_clause; char *raw_service_include; char *raw_service_exclude; + char *raw_allowing_process; + char *raw_denying_process; char *service_include_buffer; int service_include_buffer_size; char *service_exclude_buffer; @@ -243,6 +265,8 @@ struct flb_we { struct flb_regex *allowing_disk_regex; struct flb_regex *denying_disk_regex; struct flb_regex *allowing_nic_regex; + struct flb_regex *allowing_process_regex; + struct flb_regex *denying_process_regex; struct we_perflib_context perflib_context; /* WMI locator and service contexts */ @@ -267,6 +291,7 @@ struct flb_we { int wmi_service_scrape_interval; int wmi_memory_scrape_interval; int wmi_paging_file_scrape_interval; + int wmi_process_scrape_interval; int coll_cpu_fd; /* collector fd (cpu) */ int coll_net_fd; /* collector fd (net) */ @@ -280,6 +305,7 @@ struct flb_we { int coll_wmi_service_fd; /* collector fd (wmi_service) */ int coll_wmi_memory_fd; /* collector fd (wmi_memory) */ int coll_wmi_paging_file_fd; /* collector fd (wmi_paging_file) */ + int coll_wmi_process_fd; /* collector fd (wmi_process) */ /* * Metrics Contexts @@ -298,6 +324,7 @@ struct flb_we { struct we_wmi_service_counters *wmi_service; struct we_wmi_memory_counters *wmi_memory; struct we_wmi_paging_file_counters *wmi_paging_file; + struct we_wmi_process_counters *wmi_process; }; typedef int (*collector_cb)(struct flb_we *); diff --git a/plugins/in_windows_exporter_metrics/we_config.c b/plugins/in_windows_exporter_metrics/we_config.c index c8f897042d3..14913b43312 100644 --- a/plugins/in_windows_exporter_metrics/we_config.c +++ b/plugins/in_windows_exporter_metrics/we_config.c @@ -42,6 +42,8 @@ struct flb_we *flb_we_config_create(struct flb_input_instance *ins, ctx->service_include_buffer_size = 0; ctx->service_exclude_buffer = NULL; ctx->service_exclude_buffer_size = 0; + ctx->allowing_process_regex = NULL; + ctx->denying_process_regex = NULL; /* Load the config map */ ret = flb_input_config_map_set(ins, (void *) ctx); @@ -91,6 +93,15 @@ struct flb_we *flb_we_config_create(struct flb_input_instance *ins, } } + /* Process allow/deny regex rules for process metrics */ + if (ctx->raw_allowing_process != NULL) { + ctx->allowing_process_regex = flb_regex_create(ctx->raw_allowing_process); + } + + if (ctx->raw_denying_process != NULL) { + ctx->denying_process_regex = flb_regex_create(ctx->raw_denying_process); + } + ctx->cmt = cmt_create(); if (!ctx->cmt) { flb_plg_error(ins, "could not initialize CMetrics"); @@ -127,6 +138,14 @@ void flb_we_config_destroy(struct flb_we *ctx) flb_free(ctx->service_exclude_buffer); } + if (ctx->allowing_process_regex != NULL) { + flb_regex_destroy(ctx->allowing_process_regex); + } + + if (ctx->denying_disk_regex != NULL) { + flb_regex_destroy(ctx->denying_disk_regex); + } + if (ctx->cmt) { cmt_destroy(ctx->cmt); } diff --git a/plugins/in_windows_exporter_metrics/we_wmi_process.c b/plugins/in_windows_exporter_metrics/we_wmi_process.c new file mode 100644 index 00000000000..97226c2749f --- /dev/null +++ b/plugins/in_windows_exporter_metrics/we_wmi_process.c @@ -0,0 +1,417 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Fluent Bit + * ========== + * Copyright (C) 2023 The Fluent Bit Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include + +#include "we.h" +#include "we_wmi.h" +#include "we_wmi_process.h" +#include "we_util.h" +#include "we_metric.h" + +static double nop_adjust(double value) +{ + return value; +} + +int we_wmi_process_init(struct flb_we *ctx) +{ + struct cmt_gauge *g; + + ctx->wmi_process = flb_calloc(1, sizeof(struct we_wmi_process_counters)); + if (!ctx->wmi_process) { + flb_errno(); + return -1; + } + ctx->wmi_process->operational = FLB_FALSE; + + g = cmt_gauge_create(ctx->cmt, "windows", "process", "start_time", + "Time of process start", + 3, (char *[]) {"process", "process_id", "creating_process_id"}); + + if (!g) { + return -1; + } + ctx->wmi_process->start_time = g; + + g = cmt_gauge_create(ctx->cmt, "windows", "process", "handles", + "Total number of handles the process has open. " \ + "This number is the sum of the handles currently " \ + "open by each thread in the process.", + 3, (char *[]) {"process", "process_id", "creating_process_id"}); + + if (!g) { + return -1; + } + ctx->wmi_process->handles = g; + + g = cmt_gauge_create(ctx->cmt, "windows", "process", "cpu_time_total", + "Returns elapsed time that all of the threads of this process " \ + "used the processor to execute instructions by mode " \ + "(privileged, user). An instruction is the basic unit " \ + "of execution in a computer, a thread is the object " \ + "that executes instructions, and a process is " \ + "the object created when a program is run. " \ + "Code executed to handle some hardware interrupts " \ + "and trap conditions is included in this count.", + 4, (char *[]) {"process", "process_id", "creating_process_id", "mode"}); + + if (!g) { + return -1; + } + ctx->wmi_process->cpu_time_total = g; + + g = cmt_gauge_create(ctx->cmt, "windows", "process", "io_bytes_total", + "Bytes issued to I/O operations in different modes "\ + "(read, write, other).", + 4, (char *[]) {"process", "process_id", "creating_process_id", "mode"}); + + if (!g) { + return -1; + } + ctx->wmi_process->io_bytes_total = g; + + g = cmt_gauge_create(ctx->cmt, "windows", "process", "io_operations_total", + "I/O operations issued in different modes (read, write, other).", + 4, (char *[]) {"process", "process_id", "creating_process_id", "mode"}); + + if (!g) { + return -1; + } + ctx->wmi_process->io_operations_total = g; + + g = cmt_gauge_create(ctx->cmt, "windows", "process", "page_faults_total", + "Page faults by the threads executing in this process.", + 3, (char *[]) {"process", "process_id", "creating_process_id"}); + + if (!g) { + return -1; + } + ctx->wmi_process->page_faults_total = g; + + g = cmt_gauge_create(ctx->cmt, "windows", "process", "page_file_bytes", + "Current number of bytes this process has used " \ + "in the paging file(s).", + 3, (char *[]) {"process", "process_id", "creating_process_id"}); + + if (!g) { + return -1; + } + ctx->wmi_process->page_file_bytes = g; + + g = cmt_gauge_create(ctx->cmt, "windows", "process", "pool_bytes", + "Pool Bytes is the last observed number of bytes " \ + "in the paged or nonpaged pool.", + 4, (char *[]) {"process", "process_id", "creating_process_id", "pool"}); + + if (!g) { + return -1; + } + ctx->wmi_process->pool_bytes = g; + + g = cmt_gauge_create(ctx->cmt, "windows", "process", "priority_base", + "Current base priority of this process. " \ + "Threads within a process can raise and " \ + "lower their own base priority relative to " \ + "the process base priority of the process.", + 3, (char *[]) {"process", "process_id", "creating_process_id"}); + + if (!g) { + return -1; + } + ctx->wmi_process->priority_base = g; + + g = cmt_gauge_create(ctx->cmt, "windows", "process", "private_bytes", + "Current number of bytes this process has allocated " \ + "that cannot be shared with other processes.", + 3, (char *[]) {"process", "process_id", "creating_process_id"}); + + if (!g) { + return -1; + } + ctx->wmi_process->private_bytes = g; + + g = cmt_gauge_create(ctx->cmt, "windows", "process", "thread_count", + "Number of threads currently active in this process.", + 3, (char *[]) {"process", "process_id", "creating_process_id"}); + + if (!g) { + return -1; + } + ctx->wmi_process->thread_count = g; + + g = cmt_gauge_create(ctx->cmt, "windows", "process", "virtual_bytes", + "Current size, in bytes, of the virtual address space " \ + "that the process is using.", + 3, (char *[]) {"process", "process_id", "creating_process_id"}); + + if (!g) { + return -1; + } + ctx->wmi_process->virtual_bytes = g; + + g = cmt_gauge_create(ctx->cmt, "windows", "process", "working_set_private_bytes", + "Size of the working set, in bytes, that is " \ + "use for this process only and not shared nor " \ + "shareable by other processes.", + 3, (char *[]) {"process", "process_id", "creating_process_id"}); + + if (!g) { + return -1; + } + ctx->wmi_process->working_set_private_bytes = g; + + g = cmt_gauge_create(ctx->cmt, "windows", "process", "working_set_peak_bytes", + "Maximum size, in bytes, of the Working Set of " \ + "this process at any point in time. " \ + "The Working Set is the set of memory pages touched recently " \ + "by the threads in the process.", + 3, (char *[]) {"process", "process_id", "creating_process_id"}); + + if (!g) { + return -1; + } + ctx->wmi_process->working_set_peak_bytes = g; + + g = cmt_gauge_create(ctx->cmt, "windows", "process", "working_set_bytes", + "Maximum number of bytes in the working set of " \ + "this process at any point in time. " \ + "The working set is the set of memory pages touched recently " \ + "by the threads in the process.", + 3, (char *[]) {"process", "process_id", "creating_process_id"}); + + if (!g) { + return -1; + } + ctx->wmi_process->working_set_bytes = g; + + ctx->wmi_process->info = flb_calloc(1, sizeof(struct wmi_query_spec)); + if (!ctx->wmi_process->info) { + flb_errno(); + return -1; + } + ctx->wmi_process->info->metric_instance = (void *)g; + ctx->wmi_process->info->type = CMT_GAUGE; + ctx->wmi_process->info->value_adjuster = nop_adjust; + ctx->wmi_process->info->wmi_counter = "Win32_PerfRawData_PerfProc_Process"; + ctx->wmi_process->info->wmi_property = ""; + ctx->wmi_process->info->label_property_count = 0; + ctx->wmi_process->info->label_property_keys = NULL; + ctx->wmi_process->info->where_clause = NULL; + + ctx->wmi_process->operational = FLB_TRUE; + + return 0; +} + +int we_wmi_process_exit(struct flb_we *ctx) +{ + ctx->wmi_process->operational = FLB_FALSE; + + flb_free(ctx->wmi_process->info); + flb_free(ctx->wmi_process); + + return 0; +} + +static int wmi_process_regex_match(struct flb_regex *regex, char *name) +{ + if (regex == NULL) { + return 0; + } + + if (name == NULL) { + return 0; + } + + return flb_regex_match(regex, name, strlen(name)); +} + +int we_wmi_process_filter(char *name, struct flb_we *ctx) +{ + if (strcasestr(name, "_Total") != NULL) { + return 1; + } + + if (wmi_process_regex_match(ctx->denying_process_regex, name) || + !wmi_process_regex_match(ctx->allowing_process_regex, name)) { + return 1; + } + + return 0; +} + +int we_wmi_process_update(struct flb_we *ctx) +{ + uint64_t timestamp = 0; + IEnumWbemClassObject* enumerator = NULL; + HRESULT hr; + + IWbemClassObject *class_obj = NULL; + ULONG ret = 0; + double val = 0; + char *name = NULL; + char *process_name = NULL; + char *process_id = NULL; + char *creating_process_id = NULL; + double freq = 0; + double ticks_to_seconds = 1 / 1e7; + char *state; + + if (!ctx->wmi_process->operational) { + flb_plg_error(ctx->ins, "process collector not yet in operational state"); + + return -1; + } + + if (FAILED(we_wmi_coinitialize(ctx))) { + return -1; + } + + timestamp = cfl_time_now(); + + if (FAILED(we_wmi_execute_query(ctx, ctx->wmi_process->info, &enumerator))) { + return -1; + } + + while(enumerator) { + hr = enumerator->lpVtbl->Next(enumerator, WBEM_INFINITE, 1, &class_obj, &ret); + + if(ret == 0) { + break; + } + + name = we_wmi_get_property_str_value(ctx, "Name", class_obj); + if (!name) { + continue; + } + /* Remove # from the duplicated process names */ + process_name = strtok_s(name, "#", &state); + if (we_wmi_process_filter(process_name, ctx) == 1) { + flb_free(name); + + continue; + } + + process_id = we_wmi_get_property_str_value(ctx, "IDProcess", class_obj); + creating_process_id = we_wmi_get_property_str_value(ctx, "CreatingProcessID", class_obj); + freq = we_wmi_get_property_value(ctx, "Frequency_Object", class_obj); + + val = we_wmi_get_property_value(ctx, "ElapsedTime", class_obj); + cmt_gauge_set(ctx->wmi_process->start_time, timestamp, + (double)((val-116444736000000000)/freq), + 3, (char *[]) {process_name, process_id, creating_process_id}); + + val = we_wmi_get_property_value(ctx, "HandleCount", class_obj); + cmt_gauge_set(ctx->wmi_process->handles, timestamp, val, + 3, (char *[]) {process_name, process_id, creating_process_id}); + + val = we_wmi_get_property_value(ctx, "PercentUserTime", class_obj); + cmt_gauge_set(ctx->wmi_process->cpu_time_total, timestamp, val * ticks_to_seconds, + 4, (char *[]) {process_name, process_id, creating_process_id, "user"}); + + val = we_wmi_get_property_value(ctx, "PercentPrivilegedTime", class_obj); + cmt_gauge_set(ctx->wmi_process->cpu_time_total, timestamp, val * ticks_to_seconds, + 4, (char *[]) {process_name, process_id, creating_process_id, "privileged"}); + + val = we_wmi_get_property_value(ctx, "IOOtherBytesPersec", class_obj); + cmt_gauge_set(ctx->wmi_process->io_bytes_total, timestamp, val, + 4, (char *[]) {process_name, process_id, creating_process_id, "other"}); + + val = we_wmi_get_property_value(ctx, "IOOtherOperationsPersec", class_obj); + cmt_gauge_set(ctx->wmi_process->io_operations_total, timestamp, val, + 4, (char *[]) {process_name, process_id, creating_process_id, "other"}); + + val = we_wmi_get_property_value(ctx, "IOReadBytesPersec", class_obj); + cmt_gauge_set(ctx->wmi_process->io_bytes_total, timestamp, val, + 4, (char *[]) {process_name, process_id, creating_process_id, "read"}); + + val = we_wmi_get_property_value(ctx, "IOReadOperationsPersec", class_obj); + cmt_gauge_set(ctx->wmi_process->io_operations_total, timestamp, val, + 4, (char *[]) {process_name, process_id, creating_process_id, "read"}); + + val = we_wmi_get_property_value(ctx, "IOWriteBytesPersec", class_obj); + cmt_gauge_set(ctx->wmi_process->io_bytes_total, timestamp, val, + 4, (char *[]) {process_name, process_id, creating_process_id, "write"}); + + val = we_wmi_get_property_value(ctx, "IOWriteOperationsPersec", class_obj); + cmt_gauge_set(ctx->wmi_process->io_operations_total, timestamp, val, + 4, (char *[]) {process_name, process_id, creating_process_id, "write"}); + + val = we_wmi_get_property_value(ctx, "PageFaultsPersec", class_obj); + cmt_gauge_set(ctx->wmi_process->page_faults_total, timestamp, val, + 3, (char *[]) {process_name, process_id, creating_process_id}); + + val = we_wmi_get_property_value(ctx, "PageFileBytes", class_obj); + cmt_gauge_set(ctx->wmi_process->page_file_bytes, timestamp, val, + 3, (char *[]) {process_name, process_id, creating_process_id}); + + val = we_wmi_get_property_value(ctx, "PoolNonpagedBytes", class_obj); + cmt_gauge_set(ctx->wmi_process->pool_bytes, timestamp, val, + 4, (char *[]) {process_name, process_id, creating_process_id, "nonpaged"}); + + val = we_wmi_get_property_value(ctx, "PoolPagedBytes", class_obj); + cmt_gauge_set(ctx->wmi_process->pool_bytes, timestamp, val, + 4, (char *[]) {process_name, process_id, creating_process_id, "paged"}); + + val = we_wmi_get_property_value(ctx, "PriorityBase", class_obj); + cmt_gauge_set(ctx->wmi_process->priority_base, timestamp, val, + 3, (char *[]) {process_name, process_id, creating_process_id}); + + val = we_wmi_get_property_value(ctx, "ThreadCount", class_obj); + cmt_gauge_set(ctx->wmi_process->thread_count, timestamp, val, + 3, (char *[]) {process_name, process_id, creating_process_id}); + + val = we_wmi_get_property_value(ctx, "PrivateBytes", class_obj); + cmt_gauge_set(ctx->wmi_process->private_bytes, timestamp, val, + 3, (char *[]) {process_name, process_id, creating_process_id}); + + val = we_wmi_get_property_value(ctx, "VirtualBytes", class_obj); + cmt_gauge_set(ctx->wmi_process->virtual_bytes, timestamp, val, + 3, (char *[]) {process_name, process_id, creating_process_id}); + + val = we_wmi_get_property_value(ctx, "WorkingSetPrivate", class_obj); + cmt_gauge_set(ctx->wmi_process->working_set_private_bytes, timestamp, val, + 3, (char *[]) {process_name, process_id, creating_process_id}); + + val = we_wmi_get_property_value(ctx, "WorkingSetPeak", class_obj); + cmt_gauge_set(ctx->wmi_process->working_set_peak_bytes, timestamp, val, + 3, (char *[]) {process_name, process_id, creating_process_id}); + + val = we_wmi_get_property_value(ctx, "WorkingSet", class_obj); + cmt_gauge_set(ctx->wmi_process->working_set_bytes, timestamp, val, + 3, (char *[]) {process_name, process_id, creating_process_id}); + + class_obj->lpVtbl->Release(class_obj); + + flb_free(name); + flb_free(process_id); + flb_free(creating_process_id); + } + + enumerator->lpVtbl->Release(enumerator); + + we_wmi_cleanup(ctx); + + return 0; +} diff --git a/plugins/in_windows_exporter_metrics/we_wmi_process.h b/plugins/in_windows_exporter_metrics/we_wmi_process.h new file mode 100644 index 00000000000..0ad921ea6c5 --- /dev/null +++ b/plugins/in_windows_exporter_metrics/we_wmi_process.h @@ -0,0 +1,29 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Fluent Bit + * ========== + * Copyright (C) 2023 The Fluent Bit Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLB_WE_WMI_PROCESS_INFO_H +#define FLB_WE_WMI_PROCESS_INFO_H + +#include "we.h" + +int we_wmi_process_info_init(struct flb_we *ctx); +int we_wmi_process_info_exit(struct flb_we *ctx); +int we_wmi_process_info_update(struct flb_we *ctx); + +#endif From 9763d0b53aaa8901c10b2f6f528b29e7cab8cf9c Mon Sep 17 00:00:00 2001 From: Hiroshi Hatake Date: Fri, 1 Sep 2023 04:02:31 +0900 Subject: [PATCH 214/315] in_udp: Add a capability to inject source IP (#7673) --------- Signed-off-by: Hiroshi Hatake --- plugins/in_udp/udp.c | 5 + plugins/in_udp/udp.h | 1 + plugins/in_udp/udp_conn.c | 128 +++++++++- plugins/in_udp/udp_conn.h | 4 + tests/runtime/CMakeLists.txt | 1 + tests/runtime/in_udp.c | 440 +++++++++++++++++++++++++++++++++++ 6 files changed, 576 insertions(+), 3 deletions(-) create mode 100644 tests/runtime/in_udp.c diff --git a/plugins/in_udp/udp.c b/plugins/in_udp/udp.c index 2395d5ec407..ad5a28497ee 100644 --- a/plugins/in_udp/udp.c +++ b/plugins/in_udp/udp.c @@ -174,6 +174,11 @@ static struct flb_config_map config_map[] = { 0, FLB_TRUE, offsetof(struct flb_in_udp_config, buffer_size_str), "Set the buffer size" }, + { + FLB_CONFIG_MAP_STR, "source_address_key", (char *) NULL, + 0, FLB_TRUE, offsetof(struct flb_in_udp_config, source_address_key), + "Key where the source address will be injected" + }, /* EOF */ {0} }; diff --git a/plugins/in_udp/udp.h b/plugins/in_udp/udp.h index f4b37f6c4c5..1a7bfce3056 100644 --- a/plugins/in_udp/udp.h +++ b/plugins/in_udp/udp.h @@ -43,6 +43,7 @@ struct flb_in_udp_config { char *port; /* Port */ flb_sds_t raw_separator; /* Unescaped string delimiterr */ flb_sds_t separator; /* String delimiter */ + flb_sds_t source_address_key; /* Source IP address */ int collector_id; /* Listener collector id */ struct flb_downstream *downstream; /* Client manager */ struct udp_conn *dummy_conn; /* Datagram dummy connection */ diff --git a/plugins/in_udp/udp_conn.c b/plugins/in_udp/udp_conn.c index a18f74158b3..d8cc4d5e620 100644 --- a/plugins/in_udp/udp_conn.c +++ b/plugins/in_udp/udp_conn.c @@ -32,6 +32,68 @@ static inline void consume_bytes(char *buf, int bytes, int length) memmove(buf, buf + bytes, length - bytes); } +static int append_message_to_record_data(char **result_buffer, + size_t *result_size, + flb_sds_t message_key_name, + char *base_object_buffer, + size_t base_object_size, + char *message_buffer, + size_t message_size, + int message_type) +{ + int result = FLB_MAP_NOT_MODIFIED; + char *modified_data_buffer; + int modified_data_size; + msgpack_object_kv *new_map_entries[1]; + msgpack_object_kv message_entry; + *result_buffer = NULL; + *result_size = 0; + modified_data_buffer = NULL; + + if (message_key_name != NULL) { + new_map_entries[0] = &message_entry; + + message_entry.key.type = MSGPACK_OBJECT_STR; + message_entry.key.via.str.size = flb_sds_len(message_key_name); + message_entry.key.via.str.ptr = message_key_name; + + if (message_type == MSGPACK_OBJECT_BIN) { + message_entry.val.type = MSGPACK_OBJECT_BIN; + message_entry.val.via.bin.size = message_size; + message_entry.val.via.bin.ptr = message_buffer; + } + else if (message_type == MSGPACK_OBJECT_STR) { + message_entry.val.type = MSGPACK_OBJECT_STR; + message_entry.val.via.str.size = message_size; + message_entry.val.via.str.ptr = message_buffer; + } + else { + result = FLB_MAP_EXPANSION_INVALID_VALUE_TYPE; + } + + if (result == FLB_MAP_NOT_MODIFIED) { + result = flb_msgpack_expand_map(base_object_buffer, + base_object_size, + new_map_entries, 1, + &modified_data_buffer, + &modified_data_size); + if (result == 0) { + result = FLB_MAP_EXPAND_SUCCESS; + } + else { + result = FLB_MAP_EXPANSION_ERROR; + } + } + } + + if (result == FLB_MAP_EXPAND_SUCCESS) { + *result_buffer = modified_data_buffer; + *result_size = modified_data_size; + } + + return result; +} + static inline int process_pack(struct udp_conn *conn, char *pack, size_t size) { @@ -39,7 +101,14 @@ static inline int process_pack(struct udp_conn *conn, size_t off = 0; msgpack_unpacked result; msgpack_object entry; + msgpack_sbuffer sbuf; + msgpack_packer pck; struct flb_in_udp_config *ctx; + char *appended_address_buffer; + size_t appended_address_size; + char *source_address; + int i; + int len; ctx = conn->ctx; @@ -50,6 +119,8 @@ static inline int process_pack(struct udp_conn *conn, while (msgpack_unpack_next(&result, pack, size, &off) == MSGPACK_UNPACK_SUCCESS) { entry = result.data; + appended_address_buffer = NULL; + source_address = NULL; ret = flb_log_event_encoder_begin_record(ctx->log_encoder); @@ -57,16 +128,63 @@ static inline int process_pack(struct udp_conn *conn, ret = flb_log_event_encoder_set_current_timestamp(ctx->log_encoder); } + if (ctx->source_address_key != NULL) { + source_address = flb_connection_get_remote_address(conn->connection); + } + if (ret == FLB_EVENT_ENCODER_SUCCESS) { if (entry.type == MSGPACK_OBJECT_MAP) { - ret = flb_log_event_encoder_set_body_from_msgpack_object( - ctx->log_encoder, &entry); + if (source_address != NULL) { + msgpack_sbuffer_init(&sbuf); + msgpack_packer_init(&pck, &sbuf, msgpack_sbuffer_write); + + len = entry.via.map.size; + msgpack_pack_map(&pck, len); + + for (i=0; isource_address_key, + sbuf.data, + sbuf.size, + source_address, + strlen(source_address), + MSGPACK_OBJECT_STR); + msgpack_sbuffer_destroy(&sbuf); + } + + if (ret == FLB_MAP_EXPANSION_ERROR) { + flb_plg_debug(ctx->ins, "error expanding source_address : %d", ret); + } + + if (appended_address_buffer != NULL) { + ret = flb_log_event_encoder_set_body_from_raw_msgpack( + ctx->log_encoder, appended_address_buffer, appended_address_size); + } + else { + ret = flb_log_event_encoder_set_body_from_msgpack_object( + ctx->log_encoder, &entry); + } } else if (entry.type == MSGPACK_OBJECT_ARRAY) { - ret = flb_log_event_encoder_append_body_values( + if (source_address != NULL) { + ret = flb_log_event_encoder_append_body_values( + ctx->log_encoder, + FLB_LOG_EVENT_CSTRING_VALUE("msg"), + FLB_LOG_EVENT_MSGPACK_OBJECT_VALUE(&entry), + FLB_LOG_EVENT_CSTRING_VALUE(ctx->source_address_key), + FLB_LOG_EVENT_CSTRING_VALUE(source_address)); + } + else { + ret = flb_log_event_encoder_append_body_values( ctx->log_encoder, FLB_LOG_EVENT_CSTRING_VALUE("msg"), FLB_LOG_EVENT_MSGPACK_OBJECT_VALUE(&entry)); + } } else { ret = FLB_EVENT_ENCODER_ERROR_INVALID_VALUE_TYPE; @@ -76,6 +194,10 @@ static inline int process_pack(struct udp_conn *conn, ret = flb_log_event_encoder_commit_record(ctx->log_encoder); } + if (appended_address_buffer != NULL) { + flb_free(appended_address_buffer); + } + if (ret != FLB_EVENT_ENCODER_SUCCESS) { break; } diff --git a/plugins/in_udp/udp_conn.h b/plugins/in_udp/udp_conn.h index 96dbf14eb37..25b8ef3ef87 100644 --- a/plugins/in_udp/udp_conn.h +++ b/plugins/in_udp/udp_conn.h @@ -25,6 +25,10 @@ #define FLB_IN_UDP_CHUNK "32768" +#define FLB_MAP_EXPAND_SUCCESS 0 +#define FLB_MAP_NOT_MODIFIED -1 +#define FLB_MAP_EXPANSION_ERROR -2 +#define FLB_MAP_EXPANSION_INVALID_VALUE_TYPE -3 struct udp_conn_stream { char *tag; diff --git a/tests/runtime/CMakeLists.txt b/tests/runtime/CMakeLists.txt index 4c0637c6416..d6d3e710153 100644 --- a/tests/runtime/CMakeLists.txt +++ b/tests/runtime/CMakeLists.txt @@ -52,6 +52,7 @@ if(FLB_OUT_LIB) FLB_RT_TEST(FLB_IN_SPLUNK "in_splunk.c") FLB_RT_TEST(FLB_IN_SYSLOG "in_syslog.c") FLB_RT_TEST(FLB_IN_TAIL "in_tail.c") + FLB_RT_TEST(FLB_IN_UDP "in_udp.c") FLB_RT_TEST(FLB_IN_TCP "in_tcp.c") FLB_RT_TEST(FLB_IN_FORWARD "in_forward.c") FLB_RT_TEST(FLB_IN_FLUENTBIT_METRICS "in_fluentbit_metrics.c") diff --git a/tests/runtime/in_udp.c b/tests/runtime/in_udp.c new file mode 100644 index 00000000000..df60c923fad --- /dev/null +++ b/tests/runtime/in_udp.c @@ -0,0 +1,440 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Fluent Bit + * ========== + * Copyright (C) 2019-2022 The Fluent Bit Authors + * Copyright (C) 2015-2018 Treasure Data Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "flb_tests_runtime.h" + +#define DEFAULT_IO_TIMEOUT 10 +#define DEFAULT_HOST "127.0.0.1" +#define DEFAULT_PORT 5180 + +#define TLS_CERTIFICATE_HOSTNAME "leo.vcap.me" +#define TLS_CERTIFICATE_FILENAME FLB_TESTS_DATA_PATH "/data/tls/certificate.pem" +#define TLS_PRIVATE_KEY_FILENAME FLB_TESTS_DATA_PATH "/data/tls/private_key.pem" + +struct test_ctx { + flb_ctx_t *flb; /* Fluent Bit library context */ + int i_ffd; /* Input fd */ + int f_ffd; /* Filter fd (unused) */ + int o_ffd; /* Output fd */ +}; + +pthread_mutex_t result_mutex = PTHREAD_MUTEX_INITIALIZER; +int num_output = 0; +static int get_output_num() +{ + int ret; + pthread_mutex_lock(&result_mutex); + ret = num_output; + pthread_mutex_unlock(&result_mutex); + + return ret; +} + +static void set_output_num(int num) +{ + pthread_mutex_lock(&result_mutex); + num_output = num; + pthread_mutex_unlock(&result_mutex); +} + +static void clear_output_num() +{ + set_output_num(0); +} + +/* Callback to check expected results */ +static int cb_check_result_json(void *record, size_t size, void *data) +{ + char *p; + char *expected; + char *result; + int num = get_output_num(); + + set_output_num(num+1); + + expected = (char *) data; + result = (char *) record; + + p = strstr(result, expected); + TEST_CHECK(p != NULL); + + if (p==NULL) { + flb_error("Expected to find: '%s' in result '%s'", + expected, result); + } + /* + * If you want to debug your test + * + * printf("Expect: '%s' in result '%s'", expected, result); + */ + flb_free(record); + return 0; +} + +static struct test_ctx *test_ctx_create(struct flb_lib_out_cb *data) +{ + int ret; + int i_ffd; + int o_ffd; + struct test_ctx *ctx = NULL; + char sport[8]; + + ctx = flb_malloc(sizeof(struct test_ctx)); + if (!TEST_CHECK(ctx != NULL)) { + TEST_MSG("malloc failed"); + flb_errno(); + return NULL; + } + + /* Service config */ + ctx->flb = flb_create(); + flb_service_set(ctx->flb, + "Flush", "0.200000000", + "Grace", "1", + "Log_Level", "error", + NULL); + + /* Input */ + i_ffd = flb_input(ctx->flb, (char *) "udp", NULL); + TEST_CHECK(i_ffd >= 0); + ctx->i_ffd = i_ffd; + + /* Avoid to port collisions for default port of in_tcp */ + snprintf(sport, 8, "%d", DEFAULT_PORT); + ret = flb_input_set(ctx->flb, ctx->i_ffd, + "port", sport, + NULL); + TEST_CHECK(ret == 0); + + /* Output */ + o_ffd = flb_output(ctx->flb, (char *) "lib", (void *) data); + ctx->o_ffd = o_ffd; + + return ctx; +} + +static void test_ctx_destroy(struct test_ctx *ctx) +{ + TEST_CHECK(ctx != NULL); + + sleep(1); + flb_stop(ctx->flb); + flb_destroy(ctx->flb); + flb_free(ctx); +} + +static int init_udp(char *in_host, int in_port, struct sockaddr_in *addr) +{ + int port = in_port; + char *host = in_host; + flb_sockfd_t fd; + + if (host == NULL) { + host = DEFAULT_HOST; + } + if (port < 0) { + port = DEFAULT_PORT; + } + + memset(addr, 0, sizeof(struct sockaddr_in)); + fd = socket(AF_INET, SOCK_DGRAM, 0); + if (!TEST_CHECK(fd >= 0)) { + TEST_MSG("failed to socket. host=%s port=%d errno=%d", host, port, errno); + return -1; + } + + addr->sin_family = AF_INET; + addr->sin_addr.s_addr = inet_addr(host); + addr->sin_port = htons(port); + + return fd; +} + +void flb_test_udp() +{ + struct flb_lib_out_cb cb_data; + struct test_ctx *ctx; + struct sockaddr_in addr; + flb_sockfd_t fd; + int ret; + int num; + ssize_t w_size; + + char *buf = "{\"test\":\"msg\"}"; + size_t size = strlen(buf); + + clear_output_num(); + + cb_data.cb = cb_check_result_json; + cb_data.data = "\"test\":\"msg\""; + + ctx = test_ctx_create(&cb_data); + if (!TEST_CHECK(ctx != NULL)) { + TEST_MSG("test_ctx_create failed"); + exit(EXIT_FAILURE); + } + + ret = flb_output_set(ctx->flb, ctx->o_ffd, + "match", "*", + "format", "json", + NULL); + TEST_CHECK(ret == 0); + + /* Start the engine */ + ret = flb_start(ctx->flb); + TEST_CHECK(ret == 0); + + /* use default host/port */ + fd = init_udp(NULL, -1, &addr); + if (!TEST_CHECK(fd >= 0)) { + exit(EXIT_FAILURE); + } + + w_size = sendto(fd, buf, size, 0, (const struct sockaddr *)&addr, sizeof(addr)); + if (!TEST_CHECK(w_size == size)) { + TEST_MSG("failed to send, errno=%d", errno); + flb_socket_close(fd); + test_ctx_destroy(ctx); + exit(EXIT_FAILURE); + } + + /* waiting to flush */ + flb_time_msleep(1500); + + num = get_output_num(); + if (!TEST_CHECK(num > 0)) { + TEST_MSG("no outputs"); + } + + flb_socket_close(fd); + test_ctx_destroy(ctx); +} + +void flb_test_udp_with_source_address() +{ + struct flb_lib_out_cb cb_data; + struct test_ctx *ctx; + struct sockaddr_in addr; + flb_sockfd_t fd; + int ret; + int num; + ssize_t w_size; + + char *buf = "{\"test\":\"msg\"}"; + size_t size = strlen(buf); + + clear_output_num(); + + cb_data.cb = cb_check_result_json; + cb_data.data = "\"test\":\"msg\",\"source_host\":\"udp://"; + + ctx = test_ctx_create(&cb_data); + if (!TEST_CHECK(ctx != NULL)) { + TEST_MSG("test_ctx_create failed"); + exit(EXIT_FAILURE); + } + + ret = flb_input_set(ctx->flb, ctx->i_ffd, + "source_address_key", "source_host", + NULL); + TEST_CHECK(ret == 0); + + ret = flb_output_set(ctx->flb, ctx->o_ffd, + "match", "*", + "format", "json", + NULL); + TEST_CHECK(ret == 0); + + /* Start the engine */ + ret = flb_start(ctx->flb); + TEST_CHECK(ret == 0); + + /* use default host/port */ + fd = init_udp(NULL, -1, &addr); + if (!TEST_CHECK(fd >= 0)) { + exit(EXIT_FAILURE); + } + + w_size = sendto(fd, buf, size, 0, (const struct sockaddr *)&addr, sizeof(addr)); + if (!TEST_CHECK(w_size == size)) { + TEST_MSG("failed to send, errno=%d", errno); + flb_socket_close(fd); + test_ctx_destroy(ctx); + exit(EXIT_FAILURE); + } + + /* waiting to flush */ + flb_time_msleep(1500); + + num = get_output_num(); + if (!TEST_CHECK(num > 0)) { + TEST_MSG("no outputs"); + } + + flb_socket_close(fd); + test_ctx_destroy(ctx); +} + +void flb_test_format_none() +{ + struct flb_lib_out_cb cb_data; + struct test_ctx *ctx; + struct sockaddr_in addr; + flb_sockfd_t fd; + int ret; + int num; + ssize_t w_size; + + char *buf = "message\n"; + size_t size = strlen(buf); + + clear_output_num(); + + cb_data.cb = cb_check_result_json; + cb_data.data = "\"log\":\"message\""; + + ctx = test_ctx_create(&cb_data); + if (!TEST_CHECK(ctx != NULL)) { + TEST_MSG("test_ctx_create failed"); + exit(EXIT_FAILURE); + } + + ret = flb_output_set(ctx->flb, ctx->o_ffd, + "match", "*", + "format", "json", + NULL); + TEST_CHECK(ret == 0); + + ret = flb_input_set(ctx->flb, ctx->i_ffd, + "format", "none", + NULL); + TEST_CHECK(ret == 0); + + /* Start the engine */ + ret = flb_start(ctx->flb); + TEST_CHECK(ret == 0); + + /* use default host/port */ + fd = init_udp(NULL, -1, &addr); + if (!TEST_CHECK(fd >= 0)) { + exit(EXIT_FAILURE); + } + + w_size = sendto(fd, buf, size, 0, (const struct sockaddr *)&addr, sizeof(addr)); + if (!TEST_CHECK(w_size == size)) { + TEST_MSG("failed to send, errno=%d", errno); + flb_socket_close(fd); + test_ctx_destroy(ctx); + exit(EXIT_FAILURE); + } + + /* waiting to flush */ + flb_time_msleep(1500); + + num = get_output_num(); + if (!TEST_CHECK(num > 0)) { + TEST_MSG("no outputs"); + } + + flb_socket_close(fd); + test_ctx_destroy(ctx); +} + +void flb_test_format_none_separator() +{ + struct flb_lib_out_cb cb_data; + struct test_ctx *ctx; + struct sockaddr_in addr; + flb_sockfd_t fd; + int ret; + int num; + ssize_t w_size; + + char *buf = "message:message:"; + size_t size = strlen(buf); + + clear_output_num(); + + cb_data.cb = cb_check_result_json; + cb_data.data = "\"log\":\"message\""; + + ctx = test_ctx_create(&cb_data); + if (!TEST_CHECK(ctx != NULL)) { + TEST_MSG("test_ctx_create failed"); + exit(EXIT_FAILURE); + } + + ret = flb_output_set(ctx->flb, ctx->o_ffd, + "match", "*", + "format", "json", + NULL); + TEST_CHECK(ret == 0); + + ret = flb_input_set(ctx->flb, ctx->i_ffd, + "format", "none", + "separator", ":", + NULL); + TEST_CHECK(ret == 0); + + /* Start the engine */ + ret = flb_start(ctx->flb); + TEST_CHECK(ret == 0); + + /* use default host/port */ + fd = init_udp(NULL, -1, &addr); + if (!TEST_CHECK(fd >= 0)) { + exit(EXIT_FAILURE); + } + + w_size = sendto(fd, buf, size, 0, (const struct sockaddr *)&addr, sizeof(addr)); + if (!TEST_CHECK(w_size == size)) { + TEST_MSG("failed to send, errno=%d", errno); + flb_socket_close(fd); + test_ctx_destroy(ctx); + exit(EXIT_FAILURE); + } + + /* waiting to flush */ + flb_time_msleep(1500); + + num = get_output_num(); + if (!TEST_CHECK(num == 2)) { + TEST_MSG("no outputs"); + } + + flb_socket_close(fd); + test_ctx_destroy(ctx); +} + +TEST_LIST = { + {"udp", flb_test_udp}, + {"udp_with_source_address", flb_test_udp_with_source_address}, + {"format_none", flb_test_format_none}, + {"format_none_separator", flb_test_format_none_separator}, + {NULL, NULL} +}; From d1134e30242613cfa715e5009354020b6bab2053 Mon Sep 17 00:00:00 2001 From: Leonardo Alminana Date: Wed, 9 Aug 2023 18:33:55 +0200 Subject: [PATCH 215/315] in_tail: removed ignore_older enforcement on files that are being ingested This was feature was meant to ignore files whoses modification time exceeds the limit specified in ignore_older, however, when a file is deemed acceptable it should be discarded if the system took more than expected to ingest it. Signed-off-by: Leonardo Alminana --- plugins/in_tail/tail_file.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/plugins/in_tail/tail_file.c b/plugins/in_tail/tail_file.c index d2694d5a744..797270b171c 100644 --- a/plugins/in_tail/tail_file.c +++ b/plugins/in_tail/tail_file.c @@ -1669,8 +1669,12 @@ static int check_purge_deleted_file(struct flb_tail_config *ctx, struct flb_tail_file *file, time_t ts) { int ret; +<<<<<<< HEAD int64_t mtime; struct flb_file_stat st; +======= + struct stat st; +>>>>>>> 3ab27eff5 (in_tail: removed ignore_older enforcement on files that are being ingested) ret = flb_file_fstat(file->fd, &st); if (ret == -1) { @@ -1693,6 +1697,7 @@ static int check_purge_deleted_file(struct flb_tail_config *ctx, return FLB_TRUE; } +<<<<<<< HEAD if (ctx->ignore_older > 0) { mtime = st.modification_time; @@ -1706,6 +1711,8 @@ static int check_purge_deleted_file(struct flb_tail_config *ctx, } } +======= +>>>>>>> 3ab27eff5 (in_tail: removed ignore_older enforcement on files that are being ingested) return FLB_FALSE; } From 58ac7b7203d67db0acc642fdffbfa3dc8434f9f3 Mon Sep 17 00:00:00 2001 From: Leonardo Alminana Date: Wed, 9 Aug 2023 18:36:51 +0200 Subject: [PATCH 216/315] in_tail: refactored the progress check to signal the event based collector A side effect of the progress check callback directly ingesting data is that the ingestion rate is capped to the timer frequency multipled by the buffer size. The right approach is to signal the event based pending collector so it continuously runs until the file is completely ingested (which is handled by the controlled consumption of the signal from the channel). Signed-off-by: Leonardo Alminana --- plugins/in_tail/tail_fs_inotify.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/plugins/in_tail/tail_fs_inotify.c b/plugins/in_tail/tail_fs_inotify.c index b2b36744536..d819618d76a 100644 --- a/plugins/in_tail/tail_fs_inotify.c +++ b/plugins/in_tail/tail_fs_inotify.c @@ -306,29 +306,42 @@ static int in_tail_progress_check_callback(struct flb_input_instance *ins, struct mk_list *head; struct flb_tail_config *ctx = context; struct flb_tail_file *file; + int pending_data_detected; struct stat st; + (void) config; + pending_data_detected = FLB_FALSE; + mk_list_foreach_safe(head, tmp, &ctx->files_event) { file = mk_list_entry(head, struct flb_tail_file, _head); - // skip fstat if we know there is still data left to read. if (file->offset < file->size) { - flb_tail_file_chunk(file); + pending_data_detected = FLB_TRUE; + continue; } ret = fstat(file->fd, &st); if (ret == -1) { + flb_errno(); flb_plg_error(ins, "fstat error"); + continue; } if (file->offset < st.st_size) { file->size = st.st_size; - flb_tail_file_chunk(file); + file->pending_bytes = (file->size - file->offset); + + pending_data_detected = FLB_TRUE; } } + + if (pending_data_detected) { + tail_signal_pending(ctx); + } + return 0; } From 22bf26763187487dfa5e3058fa280af6c9c88a77 Mon Sep 17 00:00:00 2001 From: Takahiro Yamashita Date: Sun, 9 Jul 2023 07:09:06 +0900 Subject: [PATCH 217/315] in_lib: fix error handling after flb_log_event_decoder_next Signed-off-by: Takahiro Yamashita --- plugins/in_lib/in_lib.c | 90 +++++++++++++++++++++++++++-------------- 1 file changed, 60 insertions(+), 30 deletions(-) diff --git a/plugins/in_lib/in_lib.c b/plugins/in_lib/in_lib.c index bc72d642f93..466f1afe876 100644 --- a/plugins/in_lib/in_lib.c +++ b/plugins/in_lib/in_lib.c @@ -36,6 +36,8 @@ static int in_lib_collect(struct flb_input_instance *ins, struct flb_config *config, void *in_context) { int ret; + int dec_ret; + int enc_ret; int bytes; int out_size; int capacity; @@ -89,47 +91,74 @@ static int in_lib_collect(struct flb_input_instance *ins, } ctx->buf_len = 0; - ret = flb_log_event_decoder_init(&decoder, pack, out_size); + dec_ret = flb_log_event_decoder_init(&decoder, pack, out_size); + if (dec_ret != FLB_EVENT_DECODER_SUCCESS) { + flb_plg_error(ctx->ins, + "Log event decoder initialization error : %s", + flb_log_event_decoder_get_error_description(dec_ret)); + flb_free(pack); + flb_pack_state_reset(&ctx->state); + flb_pack_state_init(&ctx->state); + return -1; + } - while ((ret = flb_log_event_decoder_next( - &decoder, - &record)) == FLB_EVENT_DECODER_SUCCESS) { - if (ret == FLB_EVENT_DECODER_SUCCESS) { - ret = flb_log_event_encoder_begin_record(&ctx->log_encoder); + while ((dec_ret = flb_log_event_decoder_next( + &decoder, + &record)) == FLB_EVENT_DECODER_SUCCESS) { + enc_ret = flb_log_event_encoder_begin_record(&ctx->log_encoder); + if (enc_ret != FLB_EVENT_ENCODER_SUCCESS) { + flb_plg_error(ctx->ins, + "flb_log_event_encoder_begin_record error : %s", + flb_log_event_encoder_get_error_description(enc_ret)); + flb_log_event_encoder_rollback_record(&ctx->log_encoder); + continue; } - if (ret == FLB_EVENT_ENCODER_SUCCESS) { - ret = flb_log_event_encoder_set_timestamp( - &ctx->log_encoder, - &record.timestamp); + enc_ret = flb_log_event_encoder_set_timestamp( + &ctx->log_encoder, + &record.timestamp); + if (enc_ret != FLB_EVENT_ENCODER_SUCCESS) { + flb_plg_error(ctx->ins, + "flb_log_event_encoder_set_timestamp error : %s", + flb_log_event_encoder_get_error_description(enc_ret)); + flb_log_event_encoder_rollback_record(&ctx->log_encoder); + continue; } - if (ret == FLB_EVENT_ENCODER_SUCCESS) { - ret = flb_log_event_encoder_set_metadata_from_msgpack_object( - &ctx->log_encoder, - record.metadata); + enc_ret = flb_log_event_encoder_set_metadata_from_msgpack_object( + &ctx->log_encoder, + record.metadata); + if (enc_ret != FLB_EVENT_ENCODER_SUCCESS) { + flb_plg_error(ctx->ins, + "flb_log_event_encoder_set_metadata_from_msgpack_object error : %s", + flb_log_event_encoder_get_error_description(enc_ret)); + flb_log_event_encoder_rollback_record(&ctx->log_encoder); + continue; } - if (ret == FLB_EVENT_ENCODER_SUCCESS) { - ret = flb_log_event_encoder_set_body_from_msgpack_object( - &ctx->log_encoder, - record.body); + enc_ret = flb_log_event_encoder_set_body_from_msgpack_object( + &ctx->log_encoder, + record.body); + if (enc_ret != FLB_EVENT_ENCODER_SUCCESS) { + flb_plg_error(ctx->ins, + "flb_log_event_encoder_set_body_from_msgpack_object error : %s", + flb_log_event_encoder_get_error_description(enc_ret)); + flb_log_event_encoder_rollback_record(&ctx->log_encoder); + continue; } - if (ret == FLB_EVENT_ENCODER_SUCCESS) { - ret = flb_log_event_encoder_commit_record(&ctx->log_encoder); - } - else { + enc_ret = flb_log_event_encoder_commit_record(&ctx->log_encoder); + if (enc_ret != FLB_EVENT_ENCODER_SUCCESS) { + flb_plg_error(ctx->ins, + "flb_log_event_encoder_commit_record error : %s", + flb_log_event_encoder_get_error_description(enc_ret)); flb_log_event_encoder_rollback_record(&ctx->log_encoder); + continue; } } - if (ret == FLB_EVENT_DECODER_ERROR_INSUFFICIENT_DATA && - decoder.offset == out_size) { - ret = FLB_EVENT_ENCODER_SUCCESS; - } - - if (ret == FLB_EVENT_ENCODER_SUCCESS) { + dec_ret = flb_log_event_decoder_get_last_result(&decoder); + if (dec_ret == FLB_EVENT_DECODER_SUCCESS) { flb_input_log_append(ctx->ins, NULL, 0, ctx->log_encoder.output_buffer, ctx->log_encoder.output_length); @@ -137,8 +166,9 @@ static int in_lib_collect(struct flb_input_instance *ins, ret = 0; } else { - flb_plg_error(ctx->ins, "Error encoding record : %d", ret); - + flb_plg_error(ctx->ins, + "flb_log_event_decoder_get_last_result error : %s", + flb_log_event_decoder_get_error_description(dec_ret)); ret = -1; } From fdcf2998b3f2684f0b7a82fa08b3e6e9163036c9 Mon Sep 17 00:00:00 2001 From: Leonardo Alminana Date: Thu, 3 Aug 2023 16:44:51 +0200 Subject: [PATCH 218/315] tls: openssl: added code to propagate syscall errors Signed-off-by: Leonardo Alminana --- src/tls/openssl.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/tls/openssl.c b/src/tls/openssl.c index cdd8953bacf..0d5d60bb658 100644 --- a/src/tls/openssl.c +++ b/src/tls/openssl.c @@ -434,6 +434,13 @@ static int tls_net_read(struct flb_tls_session *session, ERR_error_string_n(ret, err_buf, sizeof(err_buf)-1); flb_error("[tls] syscall error: %s", err_buf); + /* According to the documentation these are non-recoverable + * errors so we don't need to screen them before saving them + * to the net_error field. + */ + + session->connection->net_error = errno; + ret = -1; } else if (ret < 0) { @@ -489,6 +496,13 @@ static int tls_net_write(struct flb_tls_session *session, ERR_error_string_n(ret, err_buf, sizeof(err_buf)-1); flb_error("[tls] syscall error: %s", err_buf); + /* According to the documentation these are non-recoverable + * errors so we don't need to screen them before saving them + * to the net_error field. + */ + + session->connection->net_error = errno; + ret = -1; } else { From 2ccb996c83ab0ab27c8fd3d95c310bc49b2c53f0 Mon Sep 17 00:00:00 2001 From: Leonardo Alminana Date: Thu, 3 Aug 2023 16:48:53 +0200 Subject: [PATCH 219/315] upstream: added code to discard failed connections Signed-off-by: Leonardo Alminana --- src/flb_upstream.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/flb_upstream.c b/src/flb_upstream.c index 142f9680396..30c82b7ee11 100644 --- a/src/flb_upstream.c +++ b/src/flb_upstream.c @@ -726,9 +726,6 @@ struct flb_connection *flb_upstream_conn_get(struct flb_upstream *u) flb_stream_release_lock(&u->base); - /* Reset errno */ - conn->net_error = -1; - err = flb_socket_error(conn->fd); if (!FLB_EINPROGRESS(err) && err != 0) { @@ -740,6 +737,9 @@ struct flb_connection *flb_upstream_conn_get(struct flb_upstream *u) continue; } + /* Reset errno */ + conn->net_error = -1; + /* Connect timeout */ conn->ts_assigned = time(NULL); flb_debug("[upstream] KA connection #%i to %s:%i has been assigned (recycled)", @@ -803,7 +803,8 @@ int flb_upstream_conn_release(struct flb_connection *conn) /* If this is a valid KA connection just recycle */ if (u->base.net.keepalive == FLB_TRUE && conn->recycle == FLB_TRUE && - conn->fd > -1) { + conn->fd > -1 && + conn->net_error == -1) { /* * This connection is still useful, move it to the 'available' queue and * initialize variables. From 59ce85abf439ab6adb13a320342d5b337ff63da1 Mon Sep 17 00:00:00 2001 From: Leonardo Alminana Date: Thu, 3 Aug 2023 15:21:01 +0200 Subject: [PATCH 220/315] io: added code to detect non-recoverable connection errors Signed-off-by: Leonardo Alminana --- src/flb_io.c | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/flb_io.c b/src/flb_io.c index 9802eac3111..40a45c0fda8 100644 --- a/src/flb_io.c +++ b/src/flb_io.c @@ -174,6 +174,23 @@ int flb_io_net_connect(struct flb_connection *connection, return 0; } +static void net_io_propagate_critical_error( + struct flb_connection *connection) +{ + switch (errno) { + case EBADF: + case ECONNRESET: + case EDESTADDRREQ: + case ENOTCONN: + case EPIPE: + case EACCES: + case EIO: + case ENETDOWN: + case ENETUNREACH: + connection->net_error = errno; + } +} + static int fd_io_write(int fd, struct sockaddr_storage *address, const void *data, size_t len, size_t *out_len); static int net_io_write(struct flb_connection *connection, @@ -204,7 +221,13 @@ static int net_io_write(struct flb_connection *connection, } } - return fd_io_write(connection->fd, address, data, len, out_len); + ret = fd_io_write(connection->fd, address, data, len, out_len); + + if (ret == -1) { + net_io_propagate_critical_error(connection); + } + + return ret; } static int fd_io_write(int fd, struct sockaddr_storage *address, @@ -430,6 +453,7 @@ static FLB_INLINE int net_io_write_async(struct flb_coro *co, *out_len = total; net_io_restore_event(connection, &event_backup); + net_io_propagate_critical_error(connection); return -1; } @@ -519,6 +543,9 @@ static ssize_t net_io_read(struct flb_connection *connection, connection->net->io_timeout, flb_connection_get_remote_address(connection)); } + else { + net_io_propagate_critical_error(connection); + } return -1; } From ee834c510a92232a1d45b996d06109c57c449035 Mon Sep 17 00:00:00 2001 From: Leonardo Alminana Date: Thu, 3 Aug 2023 16:55:42 +0200 Subject: [PATCH 221/315] io: added code to detect non-recoverable connection errors Signed-off-by: Leonardo Alminana --- src/flb_io.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/flb_io.c b/src/flb_io.c index 40a45c0fda8..dbcfa607330 100644 --- a/src/flb_io.c +++ b/src/flb_io.c @@ -624,6 +624,9 @@ static FLB_INLINE ssize_t net_io_read_async(struct flb_coro *co, goto retry_read; } + else { + net_io_propagate_critical_error(connection); + } ret = -1; } From 2774e6c9ff7aace8cadbdd9d400856782c654d47 Mon Sep 17 00:00:00 2001 From: Leonardo Alminana Date: Wed, 9 Aug 2023 18:50:33 +0200 Subject: [PATCH 222/315] io: changed some codes in net_io_propagate_critical_error EIO was removed because it was too broad and ENOTTY was added because it seems to happen in some deployments even though it doesn't make a lot of sense. Signed-off-by: Leonardo Alminana --- src/flb_io.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/flb_io.c b/src/flb_io.c index dbcfa607330..81303459cf0 100644 --- a/src/flb_io.c +++ b/src/flb_io.c @@ -184,7 +184,7 @@ static void net_io_propagate_critical_error( case ENOTCONN: case EPIPE: case EACCES: - case EIO: + case ENOTTY: case ENETDOWN: case ENETUNREACH: connection->net_error = errno; From 748aac08271032606dfb9c1e358fc0bae7818df5 Mon Sep 17 00:00:00 2001 From: Takahiro Yamashita Date: Sun, 27 Aug 2023 20:39:05 +0900 Subject: [PATCH 223/315] in_nginx_exporter_metrics: add missing release function Signed-off-by: Takahiro Yamashita --- plugins/in_nginx_exporter_metrics/nginx.c | 130 ++++++++++++---------- 1 file changed, 70 insertions(+), 60 deletions(-) diff --git a/plugins/in_nginx_exporter_metrics/nginx.c b/plugins/in_nginx_exporter_metrics/nginx.c index 9645fca8e75..bee495e23f8 100644 --- a/plugins/in_nginx_exporter_metrics/nginx.c +++ b/plugins/in_nginx_exporter_metrics/nginx.c @@ -1550,6 +1550,8 @@ struct nginx_ctx *nginx_ctx_init(struct flb_input_instance *ins, if (!upstream) { flb_plg_error(ins, "upstream initialization error"); + cmt_destroy(ctx->cmt); + flb_free(ctx); return NULL; } ctx->upstream = upstream; @@ -1570,6 +1572,7 @@ static int nginx_collect(struct flb_input_instance *ins, FLB_INPUT_RETURN(rc); } +static int nginx_ctx_destroy(struct nginx_ctx *ctx); /** * Callback function to initialize nginx metrics plugin * @@ -1585,6 +1588,7 @@ static int nginx_init(struct flb_input_instance *ins, struct nginx_ctx *ctx = NULL; struct cmt_counter *c; struct cmt_gauge *g; + int ret = -1; /* Allocate space for the configuration */ ctx = nginx_ctx_init(ins, config); @@ -1604,7 +1608,7 @@ static int nginx_init(struct flb_input_instance *ins, "Accepted client connections", 0, NULL); if (ctx->connections_accepted == NULL) { - return -1; + goto nginx_init_end; } cmt_counter_allow_reset(ctx->connections_accepted); @@ -1612,7 +1616,7 @@ static int nginx_init(struct flb_input_instance *ins, "active", "active client connections", 0, NULL); if (ctx->connections_active == NULL) { - return -1; + goto nginx_init_end; } ctx->connections_handled = cmt_counter_create(ctx->cmt, "nginx", "connections", @@ -1620,7 +1624,7 @@ static int nginx_init(struct flb_input_instance *ins, "Handled client connections", 0, NULL); if (ctx->connections_handled == NULL) { - return -1; + goto nginx_init_end; } cmt_counter_allow_reset(ctx->connections_handled); @@ -1629,7 +1633,7 @@ static int nginx_init(struct flb_input_instance *ins, "reading client connections", 0, NULL); if (ctx->connections_reading == NULL) { - return -1; + goto nginx_init_end; } ctx->connections_writing = cmt_gauge_create(ctx->cmt, "nginx", "connections", @@ -1637,7 +1641,7 @@ static int nginx_init(struct flb_input_instance *ins, "writing client connections", 0, NULL); if (ctx->connections_writing == NULL) { - return -1; + goto nginx_init_end; } ctx->connections_waiting = cmt_gauge_create(ctx->cmt, "nginx", "connections", @@ -1645,14 +1649,14 @@ static int nginx_init(struct flb_input_instance *ins, "waiting client connections", 0, NULL); if (ctx->connections_waiting == NULL) { - return -1; + goto nginx_init_end; } ctx->connections_total = cmt_counter_create(ctx->cmt, "nginx", "http", "requests_total", "Total http requests", 0, NULL); if (ctx->connections_total == NULL) { - return -1; + goto nginx_init_end; } cmt_counter_allow_reset(ctx->connections_total); @@ -1678,7 +1682,7 @@ static int nginx_init(struct flb_input_instance *ins, "1 for a successful scrape and 0 for a failed " "one", 0, NULL); if (g == NULL) { - return -1; + goto nginx_init_end; } ctx->connection_up = g; @@ -1687,7 +1691,7 @@ static int nginx_init(struct flb_input_instance *ins, "NGINX Plus Total Connections", 0, NULL); if (c == NULL) { - return -1; + goto nginx_init_end; } cmt_counter_allow_reset(c); ctx->plus_connections->connections_accepted = c; @@ -1698,7 +1702,7 @@ static int nginx_init(struct flb_input_instance *ins, "NGINX Plus Total Connections", 0, NULL); if (c == NULL) { - return -1; + goto nginx_init_end; } cmt_counter_allow_reset(c); ctx->plus_connections->connections_dropped = c; @@ -1708,7 +1712,7 @@ static int nginx_init(struct flb_input_instance *ins, "NGINX Plus Total Connections", 0, NULL); if (c == NULL) { - return -1; + goto nginx_init_end; } cmt_counter_allow_reset(c); ctx->plus_connections->connections_active = c; @@ -1718,7 +1722,7 @@ static int nginx_init(struct flb_input_instance *ins, "NGINX Plus Total Connections", 0, NULL); if (c == NULL) { - return -1; + goto nginx_init_end; } cmt_counter_allow_reset(c); ctx->plus_connections->connections_idle = c; @@ -1728,7 +1732,7 @@ static int nginx_init(struct flb_input_instance *ins, "NGINX Plus Total Connections", 0, NULL); if (c == NULL) { - return -1; + goto nginx_init_end; } cmt_counter_allow_reset(c); ctx->plus_ssl->handshakes = c; @@ -1738,7 +1742,7 @@ static int nginx_init(struct flb_input_instance *ins, "NGINX Plus Total Connections", 0, NULL); if (c == NULL) { - return -1; + goto nginx_init_end; } cmt_counter_allow_reset(c); ctx->plus_ssl->handshakes_failed = c; @@ -1748,7 +1752,7 @@ static int nginx_init(struct flb_input_instance *ins, "NGINX Plus Total Connections", 0, NULL); if (c == NULL) { - return -1; + goto nginx_init_end; } cmt_counter_allow_reset(c); ctx->plus_ssl->session_reuses = c; @@ -1758,7 +1762,7 @@ static int nginx_init(struct flb_input_instance *ins, "NGINX Plus Total Connections", 0, NULL); if (c == NULL) { - return -1; + goto nginx_init_end; } cmt_counter_allow_reset(c); ctx->plus_http_requests->total = c; @@ -1768,7 +1772,7 @@ static int nginx_init(struct flb_input_instance *ins, "NGINX Plus Total Connections", 0, NULL); if (c == NULL) { - return -1; + goto nginx_init_end; } cmt_counter_allow_reset(c); ctx->plus_http_requests->current = c; @@ -1780,7 +1784,7 @@ static int nginx_init(struct flb_input_instance *ins, "NGINX Server Zone discarded", 1, (char *[]){"server_zone"}); if (c == NULL) { - return -1; + goto nginx_init_end; } cmt_counter_allow_reset(c); ctx->server_zones->discarded = c; @@ -1792,7 +1796,7 @@ static int nginx_init(struct flb_input_instance *ins, "NGINX Server Zone processing", 1, (char *[]){"server_zone"}); if (c == NULL) { - return -1; + goto nginx_init_end; } cmt_counter_allow_reset(c); ctx->server_zones->processing = c; @@ -1804,7 +1808,7 @@ static int nginx_init(struct flb_input_instance *ins, "NGINX Server Zone received", 1, (char *[]){"server_zone"}); if (c == NULL) { - return -1; + goto nginx_init_end; } cmt_counter_allow_reset(c); ctx->server_zones->received = c; @@ -1816,7 +1820,7 @@ static int nginx_init(struct flb_input_instance *ins, "NGINX Server Zone requests", 1, (char *[]){"server_zone"}); if (c == NULL) { - return -1; + goto nginx_init_end; } cmt_counter_allow_reset(c); ctx->server_zones->requests = c; @@ -1828,7 +1832,7 @@ static int nginx_init(struct flb_input_instance *ins, "NGINX Server Zone responses", 2, (char *[]){"server_zone", "code"}); if (c == NULL) { - return -1; + goto nginx_init_end; } cmt_counter_allow_reset(c); ctx->server_zones->responses = c; @@ -1840,7 +1844,7 @@ static int nginx_init(struct flb_input_instance *ins, "NGINX Server Zone sent", 1, (char *[]){"server_zone"}); if (c == NULL) { - return -1; + goto nginx_init_end; } cmt_counter_allow_reset(c); ctx->server_zones->sent = c; @@ -1852,7 +1856,7 @@ static int nginx_init(struct flb_input_instance *ins, "NGINX Server Zone discarded", 1, (char *[]){"location_zone"}); if (c == NULL) { - return -1; + goto nginx_init_end; } cmt_counter_allow_reset(c); ctx->location_zones->discarded = c; @@ -1864,7 +1868,7 @@ static int nginx_init(struct flb_input_instance *ins, "NGINX Server Zone received", 1, (char *[]){"location_zone"}); if (c == NULL) { - return -1; + goto nginx_init_end; } cmt_counter_allow_reset(c); ctx->location_zones->received = c; @@ -1876,7 +1880,7 @@ static int nginx_init(struct flb_input_instance *ins, "NGINX Server Zone requests", 1, (char *[]){"location_zone"}); if (c == NULL) { - return -1; + goto nginx_init_end; } cmt_counter_allow_reset(c); ctx->location_zones->requests = c; @@ -1888,7 +1892,7 @@ static int nginx_init(struct flb_input_instance *ins, "NGINX Server Zone responses", 2, (char *[]){"location_zone", "code"}); if (c == NULL) { - return -1; + goto nginx_init_end; } cmt_counter_allow_reset(c); ctx->location_zones->responses = c; @@ -1900,7 +1904,7 @@ static int nginx_init(struct flb_input_instance *ins, "NGINX Server Zone sent", 1, (char *[]){"location_zone"}); if (c == NULL) { - return -1; + goto nginx_init_end; } cmt_counter_allow_reset(c); ctx->location_zones->sent = c; @@ -1912,7 +1916,7 @@ static int nginx_init(struct flb_input_instance *ins, "NGINX Upstream Keepalives", 1, (char *[]){"upstream"}); if (g == NULL) { - return -1; + goto nginx_init_end; } ctx->upstreams->keepalives = g; @@ -1923,7 +1927,7 @@ static int nginx_init(struct flb_input_instance *ins, "NGINX Upstream Zombies", 1, (char *[]){"upstream"}); if (g == NULL) { - return -1; + goto nginx_init_end; } ctx->upstreams->zombies = g; @@ -1934,7 +1938,7 @@ static int nginx_init(struct flb_input_instance *ins, "NGINX Upstream Active", 2, (char *[]){"upstream","server"}); if (g == NULL) { - return -1; + goto nginx_init_end; } ctx->upstreams->active = g; @@ -1945,7 +1949,7 @@ static int nginx_init(struct flb_input_instance *ins, "NGINX Upstream Fails", 2, (char *[]){"upstream","server"}); if (c == NULL) { - return -1; + goto nginx_init_end; } cmt_counter_allow_reset(c); ctx->upstreams->fails = c; @@ -1957,7 +1961,7 @@ static int nginx_init(struct flb_input_instance *ins, "NGINX Upstream Header Time", 2, (char *[]){"upstream","server"}); if (g == NULL) { - return -1; + goto nginx_init_end; } ctx->upstreams->header_time = g; @@ -1968,7 +1972,7 @@ static int nginx_init(struct flb_input_instance *ins, "NGINX Upstream Limit", 2, (char *[]){"upstream","server"}); if (g == NULL) { - return -1; + goto nginx_init_end; } ctx->upstreams->limit = g; @@ -1979,7 +1983,7 @@ static int nginx_init(struct flb_input_instance *ins, "NGINX Upstream Received", 2, (char *[]){"upstream","server"}); if (c == NULL) { - return -1; + goto nginx_init_end; } cmt_counter_allow_reset(c); ctx->upstreams->received = c; @@ -1991,7 +1995,7 @@ static int nginx_init(struct flb_input_instance *ins, "NGINX Upstream Requests", 2, (char *[]){"upstream","server"}); if (c == NULL) { - return -1; + goto nginx_init_end; } cmt_counter_allow_reset(c); ctx->upstreams->requests = c; @@ -2003,7 +2007,7 @@ static int nginx_init(struct flb_input_instance *ins, "NGINX Upstream Responses", 3, (char *[]){"code", "upstream","server"}); if (c == NULL) { - return -1; + goto nginx_init_end; } cmt_counter_allow_reset(c); ctx->upstreams->responses = c; @@ -2015,7 +2019,7 @@ static int nginx_init(struct flb_input_instance *ins, "NGINX Upstream Response Time", 2, (char *[]){"upstream","server"}); if (g == NULL) { - return -1; + goto nginx_init_end; } ctx->upstreams->response_time = g; @@ -2026,7 +2030,7 @@ static int nginx_init(struct flb_input_instance *ins, "NGINX Upstream Sent", 2, (char *[]){"upstream","server"}); if (c == NULL) { - return -1; + goto nginx_init_end; } cmt_counter_allow_reset(c); ctx->upstreams->sent = c; @@ -2038,7 +2042,7 @@ static int nginx_init(struct flb_input_instance *ins, "NGINX Upstream State", 2, (char *[]){"upstream","server"}); if (g == NULL) { - return -1; + goto nginx_init_end; } ctx->upstreams->state = g; @@ -2049,7 +2053,7 @@ static int nginx_init(struct flb_input_instance *ins, "NGINX Upstream Unavailable", 2, (char *[]){"upstream","server"}); if (c == NULL) { - return -1; + goto nginx_init_end; } cmt_counter_allow_reset(c); ctx->upstreams->unavail = c; @@ -2061,7 +2065,7 @@ static int nginx_init(struct flb_input_instance *ins, "NGINX Stream Server Zone connections", 1, (char *[]){"server_zone"}); if (c == NULL) { - return -1; + goto nginx_init_end; } cmt_counter_allow_reset(c); ctx->streams->connections = c; @@ -2073,7 +2077,7 @@ static int nginx_init(struct flb_input_instance *ins, "NGINX Stream Server Zone discarded", 1, (char *[]){"server_zone"}); if (c == NULL) { - return -1; + goto nginx_init_end; } cmt_counter_allow_reset(c); ctx->streams->discarded = c; @@ -2086,7 +2090,7 @@ static int nginx_init(struct flb_input_instance *ins, "processing", 1, (char *[]){"server_zone"}); if (c == NULL) { - return -1; + goto nginx_init_end; } cmt_counter_allow_reset(c); ctx->streams->processing = c; @@ -2098,7 +2102,7 @@ static int nginx_init(struct flb_input_instance *ins, "NGINX Stream Server Zone received", 1, (char *[]){"server_zone"}); if (c == NULL) { - return -1; + goto nginx_init_end; } cmt_counter_allow_reset(c); ctx->streams->received = c; @@ -2110,7 +2114,7 @@ static int nginx_init(struct flb_input_instance *ins, "NGINX Stream Server Zone sent", 1, (char *[]){"server_zone"}); if (c == NULL) { - return -1; + goto nginx_init_end; } cmt_counter_allow_reset(c); ctx->streams->sent = c; @@ -2122,7 +2126,7 @@ static int nginx_init(struct flb_input_instance *ins, "NGINX Stream Server Zone Sessions", 2, (char *[]){"server_zone", "code"}); if (c == NULL) { - return -1; + goto nginx_init_end; } cmt_counter_allow_reset(c); ctx->streams->sessions = c; @@ -2134,7 +2138,7 @@ static int nginx_init(struct flb_input_instance *ins, "NGINX Upstream Zombies", 1, (char *[]){"upstream"}); if (g == NULL) { - return -1; + goto nginx_init_end; } ctx->stream_upstreams->zombies = g; @@ -2145,7 +2149,7 @@ static int nginx_init(struct flb_input_instance *ins, "NGINX Upstream Active", 2, (char *[]){"upstream","server"}); if (g == NULL) { - return -1; + goto nginx_init_end; } ctx->stream_upstreams->active = g; @@ -2156,7 +2160,7 @@ static int nginx_init(struct flb_input_instance *ins, "NGINX Upstream Fails", 2, (char *[]){"upstream","server"}); if (c == NULL) { - return -1; + goto nginx_init_end; } cmt_counter_allow_reset(c); ctx->stream_upstreams->fails = c; @@ -2168,7 +2172,7 @@ static int nginx_init(struct flb_input_instance *ins, "NGINX Upstream Limit", 2, (char *[]){"upstream","server"}); if (g == NULL) { - return -1; + goto nginx_init_end; } ctx->stream_upstreams->limit = g; @@ -2179,7 +2183,7 @@ static int nginx_init(struct flb_input_instance *ins, "NGINX Upstream Received", 2, (char *[]){"upstream","server"}); if (c == NULL) { - return -1; + goto nginx_init_end; } cmt_counter_allow_reset(c); ctx->stream_upstreams->received = c; @@ -2191,7 +2195,7 @@ static int nginx_init(struct flb_input_instance *ins, "NGINX Upstream Header Time", 2, (char *[]){"upstream", "server"}); if (g == NULL) { - return -1; + goto nginx_init_end; } ctx->stream_upstreams->connect_time = g; @@ -2202,7 +2206,7 @@ static int nginx_init(struct flb_input_instance *ins, "NGINX Upstream Header Time", 2, (char *[]){"upstream", "server"}); if (g == NULL) { - return -1; + goto nginx_init_end; } ctx->stream_upstreams->first_byte_time = g; @@ -2213,7 +2217,7 @@ static int nginx_init(struct flb_input_instance *ins, "NGINX Upstream Requests", 2, (char *[]){"upstream","server"}); if (c == NULL) { - return -1; + goto nginx_init_end; } cmt_counter_allow_reset(c); ctx->stream_upstreams->connections = c; @@ -2225,7 +2229,7 @@ static int nginx_init(struct flb_input_instance *ins, "NGINX Upstream Response Time", 2, (char *[]){"upstream","server"}); if (g == NULL) { - return -1; + goto nginx_init_end; } ctx->stream_upstreams->response_time = g; @@ -2236,7 +2240,7 @@ static int nginx_init(struct flb_input_instance *ins, "NGINX Upstream Sent", 2, (char *[]){"upstream","server"}); if (c == NULL) { - return -1; + goto nginx_init_end; } cmt_counter_allow_reset(c); ctx->stream_upstreams->sent = c; @@ -2248,7 +2252,7 @@ static int nginx_init(struct flb_input_instance *ins, "NGINX Upstream State", 2, (char *[]){"upstream","server"}); if (g == NULL) { - return -1; + goto nginx_init_end; } ctx->stream_upstreams->state = g; @@ -2259,7 +2263,7 @@ static int nginx_init(struct flb_input_instance *ins, "NGINX Upstream Unavailable", 2, (char *[]){"upstream","server"}); if (c == NULL) { - return -1; + goto nginx_init_end; } cmt_counter_allow_reset(c); ctx->stream_upstreams->unavail = c; @@ -2269,7 +2273,13 @@ static int nginx_init(struct flb_input_instance *ins, nginx_collect, 1, 0, config); - return 0; + ret = 0; + nginx_init_end: + if (ret < 0) { + nginx_ctx_destroy(ctx); + } + + return ret; } From 065be87100631558772226674d351a03d1d18736 Mon Sep 17 00:00:00 2001 From: Phillip Whelan Date: Mon, 4 Sep 2023 13:33:26 -0300 Subject: [PATCH 224/315] custom_calyptia: generate the default machine_id in custom_calyptia. Generate the default machine_id inside the custom_calyptia plugin instead of in the out_calyptia plugin. This same machine_id then gets set for the out_calyptia and in_calyptia_fleet plugin when relevant. Signed-off-by: Phillip Whelan --- plugins/custom_calyptia/calyptia.c | 74 +++++++++++++++++ plugins/in_calyptia_fleet/in_calyptia_fleet.c | 38 ++++++--- plugins/out_calyptia/calyptia.c | 80 +------------------ 3 files changed, 105 insertions(+), 87 deletions(-) diff --git a/plugins/custom_calyptia/calyptia.c b/plugins/custom_calyptia/calyptia.c index 50158ca0b68..76bea66d0cc 100644 --- a/plugins/custom_calyptia/calyptia.c +++ b/plugins/custom_calyptia/calyptia.c @@ -28,6 +28,8 @@ #include #include +#include + struct calyptia { /* config map options */ flb_sds_t api_key; @@ -316,6 +318,63 @@ static struct flb_output_instance *setup_cloud_output(struct flb_config *config, return cloud; } +static flb_sds_t sha256_to_hex(unsigned char *sha256) +{ + int idx; + flb_sds_t hex; + flb_sds_t tmp; + + hex = flb_sds_create_size(64); + + if (!hex) { + return NULL; + } + + for (idx = 0; idx < 32; idx++) { + tmp = flb_sds_printf(&hex, "%02x", sha256[idx]); + + if (!tmp) { + flb_sds_destroy(hex); + return NULL; + } + + hex = tmp; + } + + flb_sds_len_set(hex, 64); + return hex; +} + +static flb_sds_t get_machine_id(struct calyptia *ctx) +{ + int ret; + char *buf; + size_t blen; + unsigned char sha256_buf[64] = {0}; + + /* retrieve raw machine id */ + ret = flb_utils_get_machine_id(&buf, &blen); + + if (ret == -1) { + flb_plg_error(ctx->ins, "could not obtain machine id"); + return NULL; + } + + ret = flb_hash_simple(FLB_HASH_SHA256, + (unsigned char *) buf, + blen, + sha256_buf, + sizeof(sha256_buf)); + flb_free(buf); + + if (ret != FLB_CRYPTO_SUCCESS) { + return NULL; + } + + /* convert to hex */ + return sha256_to_hex(sha256_buf); +} + static int cb_calyptia_init(struct flb_custom_instance *ins, struct flb_config *config, void *data) @@ -344,6 +403,17 @@ static int cb_calyptia_init(struct flb_custom_instance *ins, /* map instance and local context */ flb_custom_set_context(ins, ctx); + /* If no machine_id has been provided via a configuration option get it from the local machine-id. */ + if (!ctx->machine_id) { + /* machine id */ + ctx->machine_id = get_machine_id(ctx); + + if (ctx->machine_id == NULL) { + flb_plg_error(ctx->ins, "unable to retrieve machine_id"); + return -1; + } + } + /* input collector */ ctx->i = flb_input_new(config, "fluentbit_metrics", NULL, FLB_TRUE); @@ -412,6 +482,10 @@ static int cb_calyptia_init(struct flb_custom_instance *ins, if (ctx->fleet_config_dir) { flb_input_set_property(ctx->fleet, "config_dir", ctx->fleet_config_dir); } + + if (ctx->machine_id) { + flb_input_set_property(ctx->fleet, "machine_id", ctx->machine_id); + } } if (ctx->o) { diff --git a/plugins/in_calyptia_fleet/in_calyptia_fleet.c b/plugins/in_calyptia_fleet/in_calyptia_fleet.c index fc5d0addbde..281d052daf6 100644 --- a/plugins/in_calyptia_fleet/in_calyptia_fleet.c +++ b/plugins/in_calyptia_fleet/in_calyptia_fleet.c @@ -64,6 +64,7 @@ struct flb_in_calyptia_fleet_config { flb_sds_t api_key; flb_sds_t fleet_id; flb_sds_t fleet_name; + flb_sds_t machine_id; flb_sds_t config_dir; flb_sds_t cloud_host; flb_sds_t cloud_port; @@ -641,6 +642,7 @@ static int in_calyptia_fleet_collect(struct flb_input_instance *ins, flb_sds_t cfgoldname; flb_sds_t cfgcurname; flb_sds_t header; + flb_sds_t hdr; FILE *cfgfp; const char *fbit_last_modified; int fbit_last_modified_len; @@ -737,16 +739,16 @@ static int in_calyptia_fleet_collect(struct flb_input_instance *ins, header = flb_sds_create_size(4096); if (ctx->fleet_name == NULL) { - flb_sds_printf(&header, + hdr = flb_sds_printf(&header, "[CUSTOM]\n" - " Name calyptia\n" - " api_key %s\n" - " fleet_id %s\n" - " add_label fleet_id %s\n" - " fleet.config_dir %s\n" - " calyptia_host %s\n" - " calyptia_port %d\n" - " calyptia_tls %s\n", + " Name calyptia\n" + " api_key %s\n" + " fleet_id %s\n" + " add_label fleet_id %s\n" + " fleet.config_dir %s\n" + " calyptia_host %s\n" + " calyptia_port %d\n" + " calyptia_tls %s\n", ctx->api_key, ctx->fleet_id, ctx->fleet_id, @@ -757,7 +759,7 @@ static int in_calyptia_fleet_collect(struct flb_input_instance *ins, ); } else { - flb_sds_printf(&header, + hdr = flb_sds_printf(&header, "[CUSTOM]\n" " Name calyptia\n" " api_key %s\n" @@ -778,6 +780,17 @@ static int in_calyptia_fleet_collect(struct flb_input_instance *ins, tls_setting_string(ctx->ins->use_tls) ); } + if (hdr == NULL) { + fclose(cfgfp); + goto http_error; + } + if (ctx->machine_id) { + hdr = flb_sds_printf(&header, " machine_id %s\n", ctx->machine_id); + if (hdr == NULL) { + fclose(cfgfp); + goto http_error; + } + } fwrite(header, strlen(header), 1, cfgfp); flb_sds_destroy(header); fwrite(data, client->resp.payload_size, 1, cfgfp); @@ -1010,6 +1023,11 @@ static struct flb_config_map config_map[] = { 0, FLB_TRUE, offsetof(struct flb_in_calyptia_fleet_config, fleet_name), "Calyptia Fleet Name (used to lookup the fleet ID via the cloud API)." }, + { + FLB_CONFIG_MAP_STR, "machine_id", NULL, + 0, FLB_TRUE, offsetof(struct flb_in_calyptia_fleet_config, machine_id), + "Agent Machine ID." + }, { FLB_CONFIG_MAP_INT, "event_fd", "-1", 0, FLB_TRUE, offsetof(struct flb_in_calyptia_fleet_config, event_fd), diff --git a/plugins/out_calyptia/calyptia.c b/plugins/out_calyptia/calyptia.c index a09cee0b702..19811dcc908 100644 --- a/plugins/out_calyptia/calyptia.c +++ b/plugins/out_calyptia/calyptia.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -94,69 +93,6 @@ static void append_labels(struct flb_calyptia *ctx, struct cmt *cmt) } } -static flb_sds_t sha256_to_hex(unsigned char *sha256) -{ - int i; - flb_sds_t hex; - flb_sds_t tmp; - - hex = flb_sds_create_size(64); - if (!hex) { - return NULL; - } - - for (i = 0; i < 32; i++) { - tmp = flb_sds_printf(&hex, "%02x", sha256[i]); - if (!tmp) { - flb_sds_destroy(hex); - return NULL; - } - hex = tmp; - } - - flb_sds_len_set(hex, 64); - return hex; -} - -static int get_machine_id(struct flb_calyptia *ctx, char **out_buf, size_t *out_size) -{ - int ret; - char *buf; - flb_sds_t s_buf; - size_t s; - unsigned char sha256_buf[64] = {0}; - - /* retrieve raw machine id */ - ret = flb_utils_get_machine_id(&buf, &s); - if (ret == -1) { - flb_plg_error(ctx->ins, "could not obtain machine id"); - return -1; - } - - ret = flb_hash_simple(FLB_HASH_SHA256, - (unsigned char *) buf, - s, - sha256_buf, - sizeof(sha256_buf)); - - flb_free(buf); - - if (ret != FLB_CRYPTO_SUCCESS) { - return -1; - } - - /* convert to hex */ - s_buf = sha256_to_hex(sha256_buf); - if (!s_buf) { - return -1; - } - - *out_buf = s_buf; - *out_size = flb_sds_len(s_buf); - - return 0; -} - static void pack_str(msgpack_packer *mp_pck, char *str) { int len; @@ -720,8 +656,6 @@ static struct flb_calyptia *config_init(struct flb_output_instance *ins, { int ret; int flags; - size_t size; - char *machine_id; struct flb_calyptia *ctx; /* Calyptia plugin context */ @@ -768,14 +702,10 @@ static struct flb_calyptia *config_init(struct flb_output_instance *ins, } } - /* If no machine_id has been provided via a configuration option get it from the local machine-id. */ + /* the machine-id is provided by custom calyptia, which invokes this plugin. */ if (!ctx->machine_id) { - /* machine id */ - ret = get_machine_id(ctx, &machine_id, &size); - if (ret == -1) { - return NULL; - } - ctx->machine_id = (flb_sds_t) machine_id; + flb_plg_error(ctx->ins, "machine_id has not been set"); + return NULL; } flb_plg_debug(ctx->ins, "machine_id=%s", ctx->machine_id); @@ -1005,10 +935,6 @@ static int cb_calyptia_exit(void *data, struct flb_config *config) flb_sds_destroy(ctx->agent_token); } - if (ctx->machine_id) { - flb_sds_destroy(ctx->machine_id); - } - if (ctx->env) { flb_env_destroy(ctx->env); } From fd8ba53c37a5d6bd56c2eb8fb9a2e23fcc52c098 Mon Sep 17 00:00:00 2001 From: Phillip Whelan Date: Mon, 4 Sep 2023 13:36:24 -0300 Subject: [PATCH 225/315] in_calyptia_fleet: use the machine_id in the fleet configuration directory. Signed-off-by: Phillip Whelan --- plugins/in_calyptia_fleet/in_calyptia_fleet.c | 76 +++++++++++++++---- 1 file changed, 62 insertions(+), 14 deletions(-) diff --git a/plugins/in_calyptia_fleet/in_calyptia_fleet.c b/plugins/in_calyptia_fleet/in_calyptia_fleet.c index 281d052daf6..caca271e857 100644 --- a/plugins/in_calyptia_fleet/in_calyptia_fleet.c +++ b/plugins/in_calyptia_fleet/in_calyptia_fleet.c @@ -179,12 +179,14 @@ static flb_sds_t fleet_config_filename(struct flb_in_calyptia_fleet_config *ctx, cfgname = flb_sds_create_size(4096); if (ctx->fleet_name != NULL) { - flb_sds_printf(&cfgname, "%s" PATH_SEPARATOR "%s" PATH_SEPARATOR "%s.ini", - ctx->config_dir, ctx->fleet_name, fname); + flb_sds_printf(&cfgname, + "%s" PATH_SEPARATOR "%s" PATH_SEPARATOR "%s" PATH_SEPARATOR "%s.ini", + ctx->config_dir, ctx->machine_id, ctx->fleet_name, fname); } else { - flb_sds_printf(&cfgname, "%s" PATH_SEPARATOR "%s" PATH_SEPARATOR "%s.ini", - ctx->config_dir, ctx->fleet_id, fname); + flb_sds_printf(&cfgname, + "%s" PATH_SEPARATOR "%s" PATH_SEPARATOR "%s" PATH_SEPARATOR "%s.ini", + ctx->config_dir, ctx->machine_id, ctx->fleet_id, fname); } return cfgname; @@ -836,34 +838,80 @@ static int in_calyptia_fleet_collect(struct flb_input_instance *ins, FLB_INPUT_RETURN(ret); } -static void create_fleet_directory(struct flb_in_calyptia_fleet_config *ctx) +// recursively create directories, based on: +// https://stackoverflow.com/a/2336245 +// who found it at: +// http://nion.modprobe.de/blog/archives/357-Recursive-directory-creation.html +static int _mkdir(const char *dir, int perms) { + char tmp[255]; + char *ptr = NULL; + size_t len; + int ret; + + ret = snprintf(tmp, sizeof(tmp),"%s",dir); + if (ret > sizeof(tmp)) { + return -1; + } + + len = strlen(tmp); + if (tmp[len - 1] == '/') { + tmp[len - 1] = 0; + } + + for (ptr = tmp + 1; *ptr; ptr++) { + if (*ptr == '/') { + *ptr = 0; + if (access(tmp, F_OK) != 0) { + ret = mkdir(tmp, perms); + if (ret != 0) { + return ret; + } + } + *ptr = '/'; + } + } + return mkdir(tmp, perms); +} + +static int create_fleet_directory(struct flb_in_calyptia_fleet_config *ctx) { flb_sds_t myfleetdir; - if (access(ctx->config_dir, F_OK)) { - mkdir(ctx->config_dir, 0700); + if (access(ctx->config_dir, F_OK) != 0) { + if (_mkdir(ctx->config_dir, 0700) != 0) { + return -1; + } } myfleetdir = flb_sds_create_size(256); if (ctx->fleet_name != NULL) { - flb_sds_printf(&myfleetdir, "%s" PATH_SEPARATOR "%s", ctx->config_dir, ctx->fleet_name); + flb_sds_printf(&myfleetdir, "%s" PATH_SEPARATOR "%s" PATH_SEPARATOR "%s", + ctx->config_dir, ctx->machine_id, ctx->fleet_name); } else { - flb_sds_printf(&myfleetdir, "%s" PATH_SEPARATOR "%s", ctx->config_dir, ctx->fleet_id); + flb_sds_printf(&myfleetdir, "%s" PATH_SEPARATOR "%s" PATH_SEPARATOR "%s", + ctx->config_dir, ctx->machine_id, ctx->fleet_id); } - if (access(myfleetdir, F_OK)) { - mkdir(myfleetdir, 0700); + if (access(myfleetdir, F_OK) != 0) { + if (_mkdir(myfleetdir, 0700) !=0) { + return -1; + } } + + flb_sds_destroy(myfleetdir); + return 0; } -static void load_fleet_config(struct flb_in_calyptia_fleet_config *ctx) +static int load_fleet_config(struct flb_in_calyptia_fleet_config *ctx) { flb_ctx_t *flb_ctx = flb_context_get(); - create_fleet_directory(ctx); + if (create_fleet_directory(ctx) != 0) { + return -1; + } // check if we are already using the fleet configuration file. if (is_fleet_config(ctx, flb_ctx->config) == FLB_FALSE) { @@ -875,6 +923,7 @@ static void load_fleet_config(struct flb_in_calyptia_fleet_config *ctx) execute_reload(ctx, new_fleet_config_filename(ctx)); } } + return 0; } static int in_calyptia_fleet_init(struct flb_input_instance *in, @@ -974,7 +1023,6 @@ static int in_calyptia_fleet_init(struct flb_input_instance *in, ctx->collect_fd = ret; load_fleet_config(ctx); - return 0; } From 65170877c82b2d04b3cf01e72fbd9afb68515092 Mon Sep 17 00:00:00 2001 From: Phillip Whelan Date: Thu, 17 Aug 2023 12:08:18 -0400 Subject: [PATCH 226/315] utils: suppress errno when file is empty but readable. Suppress a false error log when flb_utils_read_file reads empty files. Signed-off-by: Phillip Whelan --- src/flb_utils.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/flb_utils.c b/src/flb_utils.c index ac876175a56..d0864d4d9f1 100644 --- a/src/flb_utils.c +++ b/src/flb_utils.c @@ -1303,7 +1303,9 @@ int flb_utils_read_file(char *path, char **out_buf, size_t *out_size) bytes = fread(buf, st.st_size, 1, fp); if (bytes < 1) { - flb_errno(); + if (bytes < 0) { + flb_errno(); + } flb_free(buf); fclose(fp); return -1; From 569f8972ad8e7e56c0666a7167608d7e5d883c87 Mon Sep 17 00:00:00 2001 From: Phillip Whelan Date: Tue, 29 Aug 2023 11:16:09 -0400 Subject: [PATCH 227/315] utils: use ferror and not math to check file handler for error. Signed-off-by: Phillip Whelan --- src/flb_utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/flb_utils.c b/src/flb_utils.c index d0864d4d9f1..c2b2f58a6f7 100644 --- a/src/flb_utils.c +++ b/src/flb_utils.c @@ -1303,7 +1303,7 @@ int flb_utils_read_file(char *path, char **out_buf, size_t *out_size) bytes = fread(buf, st.st_size, 1, fp); if (bytes < 1) { - if (bytes < 0) { + if (ferror(fp)) { flb_errno(); } flb_free(buf); From 0b122350ea3f8141aaaed04a542d02b5a12ea36f Mon Sep 17 00:00:00 2001 From: Phillip Whelan Date: Mon, 4 Sep 2023 12:52:19 -0300 Subject: [PATCH 228/315] custom_calyptia: pass the fleet_id parameter and label to out_calyptia. Signed-off-by: Phillip Whelan --- plugins/custom_calyptia/calyptia.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/plugins/custom_calyptia/calyptia.c b/plugins/custom_calyptia/calyptia.c index 76bea66d0cc..1cfbbd5ce75 100644 --- a/plugins/custom_calyptia/calyptia.c +++ b/plugins/custom_calyptia/calyptia.c @@ -266,7 +266,7 @@ static struct flb_output_instance *setup_cloud_output(struct flb_config *config, label = flb_sds_create_size(strlen(key->str) + strlen(val->str) + 1); - if(!label) { + if (!label) { flb_free(ctx); return NULL; } @@ -311,6 +311,20 @@ static struct flb_output_instance *setup_cloud_output(struct flb_config *config, flb_output_set_property(cloud, "tls.verify", "false"); } + if (ctx->fleet_id) { + flb_output_set_property(cloud, "fleet_id", ctx->fleet_id); + label = flb_sds_create_size(strlen("fleet_id") + strlen(ctx->fleet_id) + 1); + + if (!label) { + flb_free(ctx); + return NULL; + } + + flb_sds_printf(&label, "fleet_id %s", ctx->fleet_id); + flb_output_set_property(cloud, "add_label", label); + flb_sds_destroy(label); + } + #ifdef FLB_HAVE_CHUNK_TRACE flb_output_set_property(cloud, "pipeline_id", ctx->pipeline_id); #endif /* FLB_HAVE_CHUNK_TRACE */ From 5ac90a4c9ee8275b0a57516ef78626fea0e5dd69 Mon Sep 17 00:00:00 2001 From: Daniel Lenar Date: Mon, 4 Sep 2023 13:36:34 -0500 Subject: [PATCH 229/315] input: apply back pressure if input threaded plugin is paused (#7847) Signed-off-by: Daniel Lenar --- src/flb_input_chunk.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/flb_input_chunk.c b/src/flb_input_chunk.c index 284a7f708e1..53ddb6c2905 100644 --- a/src/flb_input_chunk.c +++ b/src/flb_input_chunk.c @@ -1766,9 +1766,18 @@ void flb_input_chunk_ring_buffer_collector(struct flb_config *ctx, void *data) ins = mk_list_entry(head, struct flb_input_instance, _head); cr = NULL; - while ((ret = flb_ring_buffer_read(ins->rb, - (void *) &cr, - sizeof(cr))) == 0) { + while (1) { + if (flb_input_buf_paused(ins) == FLB_TRUE) { + break; + } + + ret = flb_ring_buffer_read(ins->rb, + (void *) &cr, + sizeof(cr)); + if (ret != 0) { + break; + } + if (cr) { if (cr->tag) { tag_len = flb_sds_len(cr->tag); From dd64971e4fed018ff04cfd4aef8d9171cfcfcc0e Mon Sep 17 00:00:00 2001 From: Phillip Whelan Date: Thu, 24 Aug 2023 11:24:02 -0400 Subject: [PATCH 230/315] tests: internal: stream_processor: fix when test path is too long. Signed-off-by: Phillip Whelan --- tests/internal/stream_processor.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/tests/internal/stream_processor.c b/tests/internal/stream_processor.c index 1d77edf9cce..20edb74cdb9 100644 --- a/tests/internal/stream_processor.c +++ b/tests/internal/stream_processor.c @@ -446,7 +446,7 @@ static void test_window() int t; int checks; int ret; - char datafile[100]; + char datafile[PATH_MAX]; struct sp_buffer data_buf; struct sp_buffer out_buf; struct task_check *check; @@ -529,8 +529,13 @@ static void test_window() task->window.fd_hop = 1; double record_timestamp = 1.0; for (t = 0; t < check->window_size_sec + check->window_hop_sec; t++) { - sprintf(datafile, "%s%d.mp", + ret = snprintf(datafile, sizeof(datafile)-1, "%s%d.mp", DATA_SAMPLES_HOPPING_WINDOW_PATH, t + 1); + TEST_CHECK(ret <= sizeof(datafile)-1); + + if (ret > sizeof(datafile)-1) { + exit(1); + } ret = file_to_buf(datafile, &data_buf); if (ret == -1) { flb_error("[sp test] cannot open DATA_SAMPLES file %s", datafile); @@ -592,7 +597,7 @@ static void test_snapshot() int t; int checks; int ret; - char datafile[100]; + char datafile[PATH_MAX]; char stream_name[100]; char window_val[3]; struct sp_buffer data_buf; @@ -666,8 +671,14 @@ static void test_snapshot() /* Read 1.mp -> 5.mp message pack buffers created for window tests */ for (t = 0; t < 5; t++) { - sprintf(datafile, "%s%d.mp", + + ret = snprintf(datafile, sizeof(datafile)-1, "%s%d.mp", DATA_SAMPLES_HOPPING_WINDOW_PATH, t + 1); + TEST_CHECK(ret <= sizeof(datafile)-1); + + if (ret > sizeof(datafile)-1) { + exit(1); + } if (data_buf.buffer) { flb_free(data_buf.buffer); From 20393d5e08812918314e6965ffdda8e88c4690d4 Mon Sep 17 00:00:00 2001 From: Phillip Whelan Date: Mon, 28 Aug 2023 10:49:50 -0400 Subject: [PATCH 231/315] tests: internal: stream_processor: use more succint check for TEST_CHECK. Signed-off-by: Phillip Whelan --- tests/internal/stream_processor.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/tests/internal/stream_processor.c b/tests/internal/stream_processor.c index 20edb74cdb9..64679027862 100644 --- a/tests/internal/stream_processor.c +++ b/tests/internal/stream_processor.c @@ -531,9 +531,7 @@ static void test_window() for (t = 0; t < check->window_size_sec + check->window_hop_sec; t++) { ret = snprintf(datafile, sizeof(datafile)-1, "%s%d.mp", DATA_SAMPLES_HOPPING_WINDOW_PATH, t + 1); - TEST_CHECK(ret <= sizeof(datafile)-1); - - if (ret > sizeof(datafile)-1) { + if (!TEST_CHECK(ret <= sizeof(datafile)-1)) { exit(1); } ret = file_to_buf(datafile, &data_buf); @@ -674,9 +672,7 @@ static void test_snapshot() ret = snprintf(datafile, sizeof(datafile)-1, "%s%d.mp", DATA_SAMPLES_HOPPING_WINDOW_PATH, t + 1); - TEST_CHECK(ret <= sizeof(datafile)-1); - - if (ret > sizeof(datafile)-1) { + if (!TEST_CHECK(ret <= sizeof(datafile)-1)) { exit(1); } From 605b74b957e7a0565aaa637c35f735c2f3fab78c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Sep 2023 09:43:08 +0100 Subject: [PATCH 232/315] workflows: bump actions/checkout from 3 to 4 (#7894) Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build-legacy-branch.yaml | 4 ++-- .github/workflows/call-build-images.yaml | 6 ++--- .../workflows/call-build-linux-packages.yaml | 10 ++++----- .github/workflows/call-build-macos.yaml | 6 ++--- .github/workflows/call-build-windows.yaml | 6 ++--- .../call-integration-image-build.yaml | 4 ++-- .../workflows/call-run-integration-test.yaml | 6 ++--- .github/workflows/call-test-images.yaml | 4 ++-- .github/workflows/call-test-packages.yaml | 2 +- .../workflows/cron-scorecards-analysis.yaml | 2 +- .github/workflows/cron-unstable-build.yaml | 4 ++-- .github/workflows/pr-compile-check.yaml | 2 +- .github/workflows/pr-image-tests.yaml | 6 ++--- .github/workflows/pr-install-script.yaml | 2 +- .github/workflows/pr-lint.yaml | 6 ++--- .github/workflows/pr-package-tests.yaml | 2 +- .github/workflows/staging-build.yaml | 2 +- .github/workflows/staging-release.yaml | 22 +++++++++---------- .github/workflows/unit-tests.yaml | 8 +++---- .github/workflows/update-dockerhub.yaml | 2 +- 20 files changed, 53 insertions(+), 53 deletions(-) diff --git a/.github/workflows/build-legacy-branch.yaml b/.github/workflows/build-legacy-branch.yaml index df1832f0859..435fb9af804 100644 --- a/.github/workflows/build-legacy-branch.yaml +++ b/.github/workflows/build-legacy-branch.yaml @@ -17,7 +17,7 @@ jobs: contents: read steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: ${{ inputs.ref }} @@ -53,7 +53,7 @@ jobs: packages: write steps: - name: Checkout the docker build repo for legacy builds - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: repository: fluent/fluent-bit-docker-image ref: "1.8" # Fixed to this branch diff --git a/.github/workflows/call-build-images.yaml b/.github/workflows/call-build-images.yaml index d231283e86b..1a696fd9401 100644 --- a/.github/workflows/call-build-images.yaml +++ b/.github/workflows/call-build-images.yaml @@ -54,7 +54,7 @@ jobs: contents: read steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: ${{ inputs.ref }} @@ -85,7 +85,7 @@ jobs: debug-digest: ${{ steps.debug_build_push.outputs.digest }} steps: - name: Checkout code for modern style builds - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: ${{ inputs.ref }} @@ -297,7 +297,7 @@ jobs: packages: write steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: ${{ inputs.ref }} diff --git a/.github/workflows/call-build-linux-packages.yaml b/.github/workflows/call-build-linux-packages.yaml index c38d3112a7d..f7f58fc9522 100644 --- a/.github/workflows/call-build-linux-packages.yaml +++ b/.github/workflows/call-build-linux-packages.yaml @@ -60,7 +60,7 @@ jobs: contents: read steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: ${{ inputs.ref }} path: source @@ -87,7 +87,7 @@ jobs: # Pick up latest master version - name: Checkout code for action if: inputs.environment == 'staging' - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: path: action-support @@ -116,7 +116,7 @@ jobs: continue-on-error: ${{ inputs.ignore_failing_targets || false }} steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: ${{ inputs.ref }} @@ -193,7 +193,7 @@ jobs: # Pick up latest master version - name: Checkout code for action if: inputs.environment == 'staging' - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: path: action-support @@ -224,7 +224,7 @@ jobs: sudo apt-get install -y createrepo-c aptly awscli - name: Checkout code for repo metadata construction - always latest - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Import GPG key for signing id: import_gpg diff --git a/.github/workflows/call-build-macos.yaml b/.github/workflows/call-build-macos.yaml index 456ead45274..c97ee83866d 100644 --- a/.github/workflows/call-build-macos.yaml +++ b/.github/workflows/call-build-macos.yaml @@ -47,7 +47,7 @@ jobs: contents: read steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: ${{ inputs.ref }} @@ -72,7 +72,7 @@ jobs: contents: read steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: ${{ inputs.ref }} @@ -110,7 +110,7 @@ jobs: contents: read steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: ${{ inputs.ref }} diff --git a/.github/workflows/call-build-windows.yaml b/.github/workflows/call-build-windows.yaml index 3acb055feff..911f24d3972 100644 --- a/.github/workflows/call-build-windows.yaml +++ b/.github/workflows/call-build-windows.yaml @@ -46,7 +46,7 @@ jobs: armSupported: ${{ steps.armcheck.outputs.armSupported }} steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: ${{ inputs.ref }} @@ -92,7 +92,7 @@ jobs: PATH: C:\ProgramData\Chocolatey\bin;c:/Program Files/Git/cmd;c:/Windows/system32;C:/Windows/System32/WindowsPowerShell/v1.0;$ENV:WIX/bin;C:/Program Files/CMake/bin;C:\vcpkg; steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: ${{ inputs.ref }} @@ -189,7 +189,7 @@ jobs: contents: read steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: # Need latest for checksum packaging script ref: master diff --git a/.github/workflows/call-integration-image-build.yaml b/.github/workflows/call-integration-image-build.yaml index c312f1919df..5e62c813d3a 100644 --- a/.github/workflows/call-integration-image-build.yaml +++ b/.github/workflows/call-integration-image-build.yaml @@ -39,7 +39,7 @@ jobs: contents: read packages: write steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: ref: ${{ inputs.ref }} @@ -120,7 +120,7 @@ jobs: packages: read steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: ${{ inputs.ref }} diff --git a/.github/workflows/call-run-integration-test.yaml b/.github/workflows/call-run-integration-test.yaml index c65b000ef89..47f44a9bf09 100644 --- a/.github/workflows/call-run-integration-test.yaml +++ b/.github/workflows/call-run-integration-test.yaml @@ -46,7 +46,7 @@ jobs: gke-cluster-region: ${{ steps.gke-cluster-region.outputs.stdout }} gke-cluster-zone: ${{ steps.gke-cluster-zone.outputs.stdout }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: ref: ${{ inputs.ref }} repository: fluent/fluent-bit-ci @@ -175,7 +175,7 @@ jobs: - name: Test image exists and cache locally run: docker pull ${{ inputs.image_name }}:${{ inputs.image_tag }} - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: ref: ${{ inputs.ref }} repository: fluent/fluent-bit-ci @@ -234,7 +234,7 @@ jobs: env: USE_GKE_GCLOUD_AUTH_PLUGIN: true steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: ref: ${{ inputs.ref }} repository: fluent/fluent-bit-ci diff --git a/.github/workflows/call-test-images.yaml b/.github/workflows/call-test-images.yaml index 61a78cbc188..22a90cbe6ad 100644 --- a/.github/workflows/call-test-images.yaml +++ b/.github/workflows/call-test-images.yaml @@ -131,7 +131,7 @@ jobs: arch: [ linux/amd64, linux/arm64, linux/arm/v7 ] steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: ${{ inputs.ref }} @@ -177,7 +177,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: ${{ inputs.ref }} diff --git a/.github/workflows/call-test-packages.yaml b/.github/workflows/call-test-packages.yaml index 8092b9882f9..90b8414cee7 100644 --- a/.github/workflows/call-test-packages.yaml +++ b/.github/workflows/call-test-packages.yaml @@ -37,7 +37,7 @@ jobs: distro: [ amazonlinux2022, amazonlinux2, centos7, centos8, debian10, debian11, ubuntu1804, ubuntu2004, ubuntu2204 ] steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Get the version id: get_version diff --git a/.github/workflows/cron-scorecards-analysis.yaml b/.github/workflows/cron-scorecards-analysis.yaml index 7f274b8efe0..065afdfd003 100644 --- a/.github/workflows/cron-scorecards-analysis.yaml +++ b/.github/workflows/cron-scorecards-analysis.yaml @@ -24,7 +24,7 @@ jobs: id-token: write steps: - name: "Checkout code" - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: persist-credentials: false diff --git a/.github/workflows/cron-unstable-build.yaml b/.github/workflows/cron-unstable-build.yaml index 7ca581deab1..29c87b9811f 100644 --- a/.github/workflows/cron-unstable-build.yaml +++ b/.github/workflows/cron-unstable-build.yaml @@ -94,7 +94,7 @@ jobs: contents: read steps: - name: Checkout repository, always latest for action - uses: actions/checkout@v3 + uses: actions/checkout@v4 # Set up the list of target to build so we can pass the JSON to the reusable job - uses: ./.github/actions/generate-package-build-matrix @@ -156,7 +156,7 @@ jobs: steps: # Required to make a release later - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Download all artefacts continue-on-error: true diff --git a/.github/workflows/pr-compile-check.yaml b/.github/workflows/pr-compile-check.yaml index b7ff250aef8..3aaee5ac4ab 100644 --- a/.github/workflows/pr-compile-check.yaml +++ b/.github/workflows/pr-compile-check.yaml @@ -16,7 +16,7 @@ jobs: timeout-minutes: 30 steps: - name: Checkout Fluent Bit code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v2 diff --git a/.github/workflows/pr-image-tests.yaml b/.github/workflows/pr-image-tests.yaml index e3c869168fa..0c37ac951e6 100644 --- a/.github/workflows/pr-image-tests.yaml +++ b/.github/workflows/pr-image-tests.yaml @@ -21,7 +21,7 @@ jobs: # We do not push and this allows simpler workflow running for forks too steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v2 @@ -72,7 +72,7 @@ jobs: contents: read steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Build the classic test image # We only want to confirm it builds with classic mode, nothing else @@ -96,7 +96,7 @@ jobs: contents: read steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Extract metadata from Github id: meta diff --git a/.github/workflows/pr-install-script.yaml b/.github/workflows/pr-install-script.yaml index 097fec69c6a..0eeeed658df 100644 --- a/.github/workflows/pr-install-script.yaml +++ b/.github/workflows/pr-install-script.yaml @@ -19,7 +19,7 @@ jobs: timeout-minutes: 30 steps: - name: Checkout Fluent Bit code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Run install tests run: | diff --git a/.github/workflows/pr-lint.yaml b/.github/workflows/pr-lint.yaml index 156843d3fe6..f8af79bb9ad 100644 --- a/.github/workflows/pr-lint.yaml +++ b/.github/workflows/pr-lint.yaml @@ -8,7 +8,7 @@ jobs: runs-on: ubuntu-latest name: PR - Hadolint steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # Ignores do not work: https://github.com/reviewdog/action-hadolint/issues/35 is resolved - uses: reviewdog/action-hadolint@v1 with: @@ -19,7 +19,7 @@ jobs: runs-on: ubuntu-latest name: PR - Shellcheck steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: ludeeus/action-shellcheck@master with: ignore_paths: cmake/sanitizers-cmake lib plugins tests @@ -28,7 +28,7 @@ jobs: runs-on: ubuntu-latest name: PR - Actionlint steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - run: | echo "::add-matcher::.github/actionlint-matcher.json" bash <(curl https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash) diff --git a/.github/workflows/pr-package-tests.yaml b/.github/workflows/pr-package-tests.yaml index 7589f5ff068..b461ac4dac1 100644 --- a/.github/workflows/pr-package-tests.yaml +++ b/.github/workflows/pr-package-tests.yaml @@ -45,7 +45,7 @@ jobs: contents: read steps: - name: Checkout repository, always latest for action - uses: actions/checkout@v3 + uses: actions/checkout@v4 # Set up the list of target to build so we can pass the JSON to the reusable job - uses: ./.github/actions/generate-package-build-matrix diff --git a/.github/workflows/staging-build.yaml b/.github/workflows/staging-build.yaml index 3b40808f3e0..2bf6524fe56 100644 --- a/.github/workflows/staging-build.yaml +++ b/.github/workflows/staging-build.yaml @@ -123,7 +123,7 @@ jobs: build-matrix: ${{ steps.set-matrix.outputs.build-matrix }} steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 # Set up the list of target to build so we can pass the JSON to the reusable job - uses: ./.github/actions/generate-package-build-matrix id: set-matrix diff --git a/.github/workflows/staging-release.yaml b/.github/workflows/staging-release.yaml index 0eb0936561e..5496785f80d 100644 --- a/.github/workflows/staging-release.yaml +++ b/.github/workflows/staging-release.yaml @@ -65,7 +65,7 @@ jobs: RELEASE_VERSION: ${{ github.event.inputs.version }} - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 # Check we can download the AppVeyor build which confirms it matches the version to release as well as being a successful build - name: Get Appveyor binaries @@ -83,7 +83,7 @@ jobs: rpm-build-matrix: ${{ steps.get-matrix.outputs.rpm-build-matrix }} steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup runner run: | @@ -119,7 +119,7 @@ jobs: fail-fast: false steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup runner run: | @@ -192,7 +192,7 @@ jobs: fail-fast: false steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup runner run: | @@ -348,7 +348,7 @@ jobs: windows-zip64-hash: ${{ steps.windows.outputs.WIN_64_ZIP_HASH }} steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Sync packages from buckets on S3 run: | @@ -768,7 +768,7 @@ jobs: - staging-release-yum-packages steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Test release packages run: | @@ -790,7 +790,7 @@ jobs: - staging-release-images steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Test containers run: | @@ -843,7 +843,7 @@ jobs: steps: - name: Release 2.0 - not latest if: startsWith(inputs.version, '2.0') - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: repository: fluent/fluent-bit-docs ref: 2.0 @@ -851,7 +851,7 @@ jobs: - name: Release 2.1 and latest if: startsWith(inputs.version, '2.1') - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: repository: fluent/fluent-bit-docs token: ${{ secrets.GH_PA_TOKEN }} @@ -910,13 +910,13 @@ jobs: steps: - name: Release 2.0 if: startsWith(inputs.version, '2.0') - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: 2.0 - name: Release 2.1 and latest if: startsWith(inputs.version, '2.1') - uses: actions/checkout@v3 + uses: actions/checkout@v4 # Get the new version to use - name: 'Get next minor version' diff --git a/.github/workflows/unit-tests.yaml b/.github/workflows/unit-tests.yaml index 09146703eec..282879c5f51 100644 --- a/.github/workflows/unit-tests.yaml +++ b/.github/workflows/unit-tests.yaml @@ -55,9 +55,9 @@ jobs: sudo apt-get install -y gcc-7 g++-7 clang-6.0 libsystemd-dev gcovr libyaml-dev sudo ln -s /usr/bin/llvm-symbolizer-6.0 /usr/bin/llvm-symbolizer || true - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: repository: calyptia/fluent-bit-ci path: ci @@ -91,8 +91,8 @@ jobs: permissions: contents: read steps: - - uses: actions/checkout@v3 - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 + - uses: actions/checkout@v4 with: repository: calyptia/fluent-bit-ci path: ci diff --git a/.github/workflows/update-dockerhub.yaml b/.github/workflows/update-dockerhub.yaml index 3b2e932449a..cdd5dbe16de 100644 --- a/.github/workflows/update-dockerhub.yaml +++ b/.github/workflows/update-dockerhub.yaml @@ -11,7 +11,7 @@ jobs: contents: read runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Docker Hub Description uses: peter-evans/dockerhub-description@v3 From e6c95d9c157065c10c0ed5cee950c8d5a063f87c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 5 Sep 2023 11:14:33 +0100 Subject: [PATCH 233/315] release: update to 2.1.10 (#7895) * release: update to 2.1.10 Signed-off-by: GitHub * Update dockerfiles/Dockerfile Signed-off-by: Pat --------- Signed-off-by: GitHub Signed-off-by: Pat Co-authored-by: celalettin1286 Co-authored-by: Pat --- CMakeLists.txt | 2 +- dockerfiles/Dockerfile | 2 +- fluent-bit-2.1.9.bb => fluent-bit-2.1.10.bb | 2 +- snap/snapcraft.yaml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) rename fluent-bit-2.1.9.bb => fluent-bit-2.1.10.bb (99%) diff --git a/CMakeLists.txt b/CMakeLists.txt index a0369817cce..ca0a4683a6b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,7 @@ set(CMAKE_POLICY_DEFAULT_CMP0069 NEW) # Fluent Bit Version set(FLB_VERSION_MAJOR 2) set(FLB_VERSION_MINOR 1) -set(FLB_VERSION_PATCH 9) +set(FLB_VERSION_PATCH 10) set(FLB_VERSION_STR "${FLB_VERSION_MAJOR}.${FLB_VERSION_MINOR}.${FLB_VERSION_PATCH}") set(CMAKE_POSITION_INDEPENDENT_CODE ON) diff --git a/dockerfiles/Dockerfile b/dockerfiles/Dockerfile index 64f3adac364..bc0c06c5517 100644 --- a/dockerfiles/Dockerfile +++ b/dockerfiles/Dockerfile @@ -11,7 +11,7 @@ # docker buildx build --platform "linux/amd64,linux/arm64,linux/arm/v7" -f ./dockerfiles/Dockerfile.multiarch --build-arg FLB_TARBALL=https://github.com/fluent/fluent-bit/archive/v1.8.11.tar.gz ./dockerfiles/ # Set this to the current release version: it gets done so as part of the release. -ARG RELEASE_VERSION=2.1.9 +ARG RELEASE_VERSION=2.1.10 # For multi-arch builds - assumption is running on an AMD64 host FROM multiarch/qemu-user-static:x86_64-arm as qemu-arm32 diff --git a/fluent-bit-2.1.9.bb b/fluent-bit-2.1.10.bb similarity index 99% rename from fluent-bit-2.1.9.bb rename to fluent-bit-2.1.10.bb index 5b9f999f52c..dd445340652 100644 --- a/fluent-bit-2.1.9.bb +++ b/fluent-bit-2.1.10.bb @@ -16,7 +16,7 @@ LIC_FILES_CHKSUM = "file://LICENSE;md5=2ee41112a44fe7014dce33e26468ba93" SECTION = "net" PR = "r0" -PV = "2.1.9" +PV = "2.1.10" SRCREV = "v${PV}" SRC_URI = "git://github.com/fluent/fluent-bit.git;nobranch=1" diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 46d477a12c8..6b5e42d0a19 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -1,6 +1,6 @@ name: fluent-bit base: core18 -version: '2.1.9' +version: '2.1.10' summary: High performance logs and stream processor description: | Fluent Bit is a high performance log processor and stream processor for Linux. From 15b99e26ba738615c03b8b54172aff25c5396685 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Sep 2023 10:15:08 +0100 Subject: [PATCH 234/315] workflows: bump crazy-max/ghaction-chocolatey from 2 to 3 (#7909) Bumps [crazy-max/ghaction-chocolatey](https://github.com/crazy-max/ghaction-chocolatey) from 2 to 3. - [Release notes](https://github.com/crazy-max/ghaction-chocolatey/releases) - [Commits](https://github.com/crazy-max/ghaction-chocolatey/compare/v2...v3) --- updated-dependencies: - dependency-name: crazy-max/ghaction-chocolatey dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/call-build-windows.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/call-build-windows.yaml b/.github/workflows/call-build-windows.yaml index 911f24d3972..7adc229a7ac 100644 --- a/.github/workflows/call-build-windows.yaml +++ b/.github/workflows/call-build-windows.yaml @@ -113,7 +113,7 @@ jobs: arch: ${{ matrix.config.arch }} - name: Get gzip command w/ chocolatey - uses: crazy-max/ghaction-chocolatey@v2 + uses: crazy-max/ghaction-chocolatey@v3 with: args: install gzip -y From 13afb9ebb809f2f87b084f70a77fe2d02484b2be Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Sep 2023 10:15:37 +0100 Subject: [PATCH 235/315] workflows: bump crazy-max/ghaction-import-gpg from 5 to 6 (#7908) Bumps [crazy-max/ghaction-import-gpg](https://github.com/crazy-max/ghaction-import-gpg) from 5 to 6. - [Release notes](https://github.com/crazy-max/ghaction-import-gpg/releases) - [Commits](https://github.com/crazy-max/ghaction-import-gpg/compare/v5...v6) --- updated-dependencies: - dependency-name: crazy-max/ghaction-import-gpg dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/call-build-linux-packages.yaml | 2 +- .github/workflows/staging-release.yaml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/call-build-linux-packages.yaml b/.github/workflows/call-build-linux-packages.yaml index f7f58fc9522..8b5545d1560 100644 --- a/.github/workflows/call-build-linux-packages.yaml +++ b/.github/workflows/call-build-linux-packages.yaml @@ -228,7 +228,7 @@ jobs: - name: Import GPG key for signing id: import_gpg - uses: crazy-max/ghaction-import-gpg@v5 + uses: crazy-max/ghaction-import-gpg@v6 with: gpg_private_key: ${{ secrets.gpg_private_key }} passphrase: ${{ secrets.gpg_private_key_passphrase }} diff --git a/.github/workflows/staging-release.yaml b/.github/workflows/staging-release.yaml index 5496785f80d..b8a9eee1be7 100644 --- a/.github/workflows/staging-release.yaml +++ b/.github/workflows/staging-release.yaml @@ -129,7 +129,7 @@ jobs: - name: Import GPG key for signing id: import_gpg - uses: crazy-max/ghaction-import-gpg@v5 + uses: crazy-max/ghaction-import-gpg@v6 with: gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }} passphrase: ${{ secrets.GPG_PRIVATE_KEY_PASSPHRASE }} @@ -218,7 +218,7 @@ jobs: - name: Import GPG key for signing id: import_gpg - uses: crazy-max/ghaction-import-gpg@v5 + uses: crazy-max/ghaction-import-gpg@v6 with: gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }} passphrase: ${{ secrets.GPG_PRIVATE_KEY_PASSPHRASE }} @@ -305,7 +305,7 @@ jobs: steps: - name: Import GPG key for signing id: import_gpg - uses: crazy-max/ghaction-import-gpg@v5 + uses: crazy-max/ghaction-import-gpg@v6 with: gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }} passphrase: ${{ secrets.GPG_PRIVATE_KEY_PASSPHRASE }} From 643e5c5bbd4c43e526e59180e54bd3838a201757 Mon Sep 17 00:00:00 2001 From: Takahiro Yamashita Date: Sun, 10 Sep 2023 11:06:46 +0900 Subject: [PATCH 236/315] tests: internal: log_event_decoder: add test for log_event_decoder Signed-off-by: Takahiro Yamashita --- tests/internal/CMakeLists.txt | 1 + tests/internal/log_event_decoder.c | 281 +++++++++++++++++++++++++++++ 2 files changed, 282 insertions(+) create mode 100644 tests/internal/log_event_decoder.c diff --git a/tests/internal/CMakeLists.txt b/tests/internal/CMakeLists.txt index b92b999cec3..2838e0cd90e 100644 --- a/tests/internal/CMakeLists.txt +++ b/tests/internal/CMakeLists.txt @@ -38,6 +38,7 @@ set(UNIT_TESTS_FILES parser_logfmt.c env.c log.c + log_event_decoder.c processor.c ) diff --git a/tests/internal/log_event_decoder.c b/tests/internal/log_event_decoder.c new file mode 100644 index 00000000000..6f93edcfb77 --- /dev/null +++ b/tests/internal/log_event_decoder.c @@ -0,0 +1,281 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Fluent Bit + * ========== + * Copyright (C) 2015-2023 The Fluent Bit Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include + +#include "flb_tests_internal.h" + +static int pack_event_time(msgpack_packer *pck, struct flb_time *tm) +{ + char ext_data[8] = {0}; + uint32_t tmp; + + /* event time */ + tmp = htonl((uint32_t)tm->tm.tv_sec); /* second from epoch */ + memcpy(&ext_data, &tmp, 4); + tmp = htonl((uint32_t)tm->tm.tv_nsec);/* nanosecond */ + memcpy(&ext_data[4], &tmp, 4); + + msgpack_pack_ext(pck, 8, 0); + msgpack_pack_ext_body(pck, ext_data, sizeof(ext_data)); + + return 0; +} + +void create_destroy() +{ + struct flb_log_event_decoder *dec = NULL; + char buf[256] = {0}; + + dec = flb_log_event_decoder_create(&buf[0], sizeof(buf)); + if (!TEST_CHECK(dec != NULL)) { + TEST_MSG("flb_log_event_decoder_create failed"); + return; + } + + flb_log_event_decoder_destroy(dec); +} + +void init_destroy() +{ + struct flb_log_event_decoder dec; + char buf[256] = {0}; + int ret; + + ret = flb_log_event_decoder_init(&dec, &buf[0], sizeof(buf)); + if (!TEST_CHECK(ret == FLB_EVENT_DECODER_SUCCESS)) { + TEST_MSG("flb_log_event_decoder_init failed. ret=%s", + flb_log_event_decoder_get_error_description(ret)); + return; + } + + flb_log_event_decoder_destroy(&dec); +} + +void decode_timestamp() +{ + struct flb_time tm; + msgpack_sbuffer sbuf; + msgpack_packer pck; + msgpack_unpacked result; + size_t offset = 0; + + int ret; + + msgpack_sbuffer_init(&sbuf); + msgpack_packer_init(&pck, &sbuf, msgpack_sbuffer_write); + msgpack_pack_int64(&pck, 123456); + + msgpack_unpacked_init(&result); + msgpack_unpack_next(&result, sbuf.data, sbuf.size, &offset); + + ret = flb_log_event_decoder_decode_timestamp(&result.data, &tm); + if (!TEST_CHECK(ret == FLB_EVENT_DECODER_SUCCESS)) { + TEST_MSG("flb_log_event_decoder_timestamp failed. ret=%s", + flb_log_event_decoder_get_error_description(ret)); + return; + } + if (!TEST_CHECK(tm.tm.tv_sec == 123456 && tm.tm.tv_nsec == 0)) { + TEST_MSG("timestamp error. tv_sec=%ld tv_nsec=%lu", tm.tm.tv_sec, tm.tm.tv_nsec); + return; + } + + msgpack_unpacked_init(&result); + msgpack_sbuffer_clear(&sbuf); + + /* event time */ + flb_time_set(&tm, 123456, 123456); + pack_event_time(&pck, &tm); + + offset = 0; + msgpack_unpack_next(&result, sbuf.data, sbuf.size, &offset); + + flb_time_zero(&tm); + ret = flb_log_event_decoder_decode_timestamp(&result.data, &tm); + if (!TEST_CHECK(ret == FLB_EVENT_DECODER_SUCCESS)) { + TEST_MSG("flb_log_event_decoder_timestamp failed. ret=%s", + flb_log_event_decoder_get_error_description(ret)); + return; + } + if (!TEST_CHECK(tm.tm.tv_sec == 123456 && tm.tm.tv_nsec == 123456)) { + TEST_MSG("timestamp error. tv_sec=%ld tv_nsec=%lu", tm.tm.tv_sec, tm.tm.tv_nsec); + return; + } + + msgpack_unpacked_destroy(&result); + msgpack_sbuffer_destroy(&sbuf); +} + +void decode_object() +{ + struct flb_log_event_decoder dec; + struct flb_log_event event; + int ret; + struct flb_time tm; + msgpack_sbuffer sbuf; + msgpack_packer pck; + msgpack_unpacked result; + size_t offset = 0; + char *json = NULL; + + flb_time_set(&tm, 123456, 123456); + + msgpack_sbuffer_init(&sbuf); + msgpack_packer_init(&pck, &sbuf, msgpack_sbuffer_write); + + /* [[123456.123456, {}], {"key1":"val1", "key2":"val2"}] */ + msgpack_pack_array(&pck, 2); + msgpack_pack_array(&pck, 2); + pack_event_time(&pck, &tm); + msgpack_pack_map(&pck, 0); + msgpack_pack_map(&pck, 2); + + msgpack_pack_str(&pck, 4); + msgpack_pack_str_body(&pck, "key1", 4); + msgpack_pack_str(&pck, 4); + msgpack_pack_str_body(&pck, "val1", 4); + + msgpack_pack_str(&pck, 4); + msgpack_pack_str_body(&pck, "key2", 4); + msgpack_pack_str(&pck, 4); + msgpack_pack_str_body(&pck, "val2", 4); + + msgpack_unpacked_init(&result); + ret = msgpack_unpack_next(&result, sbuf.data, sbuf.size, &offset); + if (!TEST_CHECK(ret == MSGPACK_UNPACK_SUCCESS)) { + TEST_MSG("msgpack_unpack_next failed"); + return; + } + + ret = flb_event_decoder_decode_object(&dec, &event, &result.data); + if (!TEST_CHECK(ret == FLB_EVENT_DECODER_SUCCESS)) { + TEST_MSG("flb_log_event_decoder_decode_object failed. ret=%s", + flb_log_event_decoder_get_error_description(ret)); + return; + } + + if (!TEST_CHECK(flb_time_equal(&tm, &event.timestamp))) { + TEST_MSG("timestamp mismatch"); + return; + } + + json = flb_msgpack_to_json_str(4096, event.body); + if (!TEST_CHECK(json != NULL)) { + TEST_MSG("flb_msgpack_to_json_str error"); + return; + } + if (!TEST_CHECK(strstr(json, "\"key1\":\"val1\"") != NULL)) { + TEST_MSG("\"key1\":\"val1\" is missing. json=%s", json); + return; + } + if (!TEST_CHECK(strstr(json, "\"key2\":\"val2\"") != NULL)) { + TEST_MSG("\"key2\":\"val2\" is missing. json=%s", json); + return; + } + + flb_free(json); + msgpack_unpacked_destroy(&result); + msgpack_sbuffer_destroy(&sbuf); +} + +void decoder_next() +{ + struct flb_log_event_decoder dec; + struct flb_log_event event; + int ret; + struct flb_time tm; + msgpack_sbuffer sbuf; + msgpack_packer pck; + char *json = NULL; + + flb_time_set(&tm, 123456, 123456); + + msgpack_sbuffer_init(&sbuf); + msgpack_packer_init(&pck, &sbuf, msgpack_sbuffer_write); + + /* [[123456.123456, {}], {"key1":"val1", "key2":"val2"}] */ + msgpack_pack_array(&pck, 2); + msgpack_pack_array(&pck, 2); + pack_event_time(&pck, &tm); + msgpack_pack_map(&pck, 0); + msgpack_pack_map(&pck, 2); + + msgpack_pack_str(&pck, 4); + msgpack_pack_str_body(&pck, "key1", 4); + msgpack_pack_str(&pck, 4); + msgpack_pack_str_body(&pck, "val1", 4); + + msgpack_pack_str(&pck, 4); + msgpack_pack_str_body(&pck, "key2", 4); + msgpack_pack_str(&pck, 4); + msgpack_pack_str_body(&pck, "val2", 4); + + + ret = flb_log_event_decoder_init(&dec, (char *)sbuf.data, sbuf.size); + if (!TEST_CHECK(ret == FLB_EVENT_DECODER_SUCCESS)) { + TEST_MSG("flb_log_event_decoder_init failed. ret=%s", + flb_log_event_decoder_get_error_description(ret)); + return; + } + + ret = flb_log_event_decoder_next(&dec, &event); + if (!TEST_CHECK(ret == FLB_EVENT_DECODER_SUCCESS)) { + TEST_MSG("flb_log_event_decoder_next failed. ret=%s", + flb_log_event_decoder_get_error_description(ret)); + return; + } + if (!TEST_CHECK(flb_time_equal(&tm, &event.timestamp))) { + TEST_MSG("timestamp mismatch"); + return; + } + + json = flb_msgpack_to_json_str(4096, event.body); + if (!TEST_CHECK(json != NULL)) { + TEST_MSG("flb_msgpack_to_json_str error"); + return; + } + if (!TEST_CHECK(strstr(json, "\"key1\":\"val1\"") != NULL)) { + TEST_MSG("\"key1\":\"val1\" is missing. json=%s", json); + return; + } + if (!TEST_CHECK(strstr(json, "\"key2\":\"val2\"") != NULL)) { + TEST_MSG("\"key2\":\"val2\" is missing. json=%s", json); + return; + } + + flb_free(json); + flb_log_event_decoder_destroy(&dec); + msgpack_sbuffer_destroy(&sbuf); +} + + + +TEST_LIST = { + { "create_destroy", create_destroy }, + { "init_destroy", init_destroy }, + { "decode_timestamp", decode_timestamp }, + { "decode_object", decode_object }, + { "decoder_next", decoder_next }, + { 0 } +}; From 8b0e4fa23c40538083da7301be554072c378e2fb Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Tue, 5 Sep 2023 14:28:57 -0500 Subject: [PATCH 237/315] out_forward: add new 'add_option' configuration property Forward protocol supports metadata through the 'options' feature. This information is appended to the whole payload and normally is handled only by the Forward plugin implementation. This plugin extends Fluent Bit Forward configuration where now is possible to set arbitrary options key/value pairs (strings) for very advanced use cases. Usage: [OUTPUT] name forward match * add_option key1 val1 add_option key2 val2 Signed-off-by: Eduardo Silva --- plugins/out_forward/forward.c | 16 +++++++++++++++- plugins/out_forward/forward.h | 4 ++++ plugins/out_forward/forward_format.c | 18 ++++++++++++++++++ 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/plugins/out_forward/forward.c b/plugins/out_forward/forward.c index 885b420effe..8cc2ca2cc76 100644 --- a/plugins/out_forward/forward.c +++ b/plugins/out_forward/forward.c @@ -839,6 +839,13 @@ static int config_set_properties(struct flb_upstream_node *node, fc->send_options = flb_utils_bool(tmp); } + /* add_option -> extra_options: if the user has defined 'add_option' + * we need to enable the 'send_options' flag + */ + if (fc->extra_options && mk_list_size(fc->extra_options) > 0) { + fc->send_options = FLB_TRUE; + } + /* require ack response (implies send_options) */ tmp = config_get_property("require_ack_response", node, ctx); if (tmp) { @@ -1785,7 +1792,14 @@ static struct flb_config_map config_map[] = { { FLB_CONFIG_MAP_BOOL, "fluentd_compat", "false", 0, FLB_TRUE, offsetof(struct flb_forward_config, fluentd_compat), - "Send cmetrics and ctreaces with Fluentd compatible format" + "Send metrics and traces with Fluentd compatible format" + }, + + { + FLB_CONFIG_MAP_SLIST_2, "add_option", NULL, + FLB_CONFIG_MAP_MULT, FLB_TRUE, offsetof(struct flb_forward_config, extra_options), + "Set an extra Forward protocol option. This is an advance feature, use it only for " + "very specific use-cases." }, /* EOF */ diff --git a/plugins/out_forward/forward.h b/plugins/out_forward/forward.h index f0abcfcd9b2..8e77e6e111d 100644 --- a/plugins/out_forward/forward.h +++ b/plugins/out_forward/forward.h @@ -73,6 +73,10 @@ struct flb_forward_config { int time_as_integer; /* Use backward compatible timestamp ? */ int fluentd_compat; /* Use Fluentd compatible payload for * metrics and ctraces */ + + /* add extra options to the Forward payload (advanced) */ + struct mk_list *extra_options; + int fwd_retain_metadata; /* Do not drop metadata in forward mode */ /* config */ diff --git a/plugins/out_forward/forward_format.c b/plugins/out_forward/forward_format.c index 85a9c5d3f09..48dedd862d6 100644 --- a/plugins/out_forward/forward_format.c +++ b/plugins/out_forward/forward_format.c @@ -93,7 +93,11 @@ static int append_options(struct flb_forward *ctx, char *chunk = NULL; uint8_t checksum[64]; int result; + struct mk_list *head; + struct flb_config_map_val *mv; struct flb_mp_map_header mh; + struct flb_slist_entry *eopt_key; + struct flb_slist_entry *eopt_val; /* options is map, use the dynamic map type */ flb_mp_map_header_init(&mh, mp_pck); @@ -152,6 +156,20 @@ static int append_options(struct flb_forward *ctx, msgpack_pack_str_body(mp_pck, "fluent_signal", 13); msgpack_pack_int64(mp_pck, event_type); + /* process 'extra_option(s)' */ + if (fc->extra_options) { + flb_config_map_foreach(head, mv, fc->extra_options) { + eopt_key = mk_list_entry_first(mv->val.list, struct flb_slist_entry, _head); + eopt_val = mk_list_entry_last(mv->val.list, struct flb_slist_entry, _head); + + flb_mp_map_header_append(&mh); + msgpack_pack_str(mp_pck, flb_sds_len(eopt_key->str)); + msgpack_pack_str_body(mp_pck, eopt_key->str, flb_sds_len(eopt_key->str)); + msgpack_pack_str(mp_pck, flb_sds_len(eopt_val->str)); + msgpack_pack_str_body(mp_pck, eopt_val->str, flb_sds_len(eopt_val->str)); + } + } + if (metadata != NULL && metadata->type == MSGPACK_OBJECT_MAP && metadata->via.map.size > 0) { From ccbe5693ab8d4d9f0c4f3341a2cd468977428269 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 13 Sep 2023 10:03:07 +0100 Subject: [PATCH 238/315] workflows: bump docker/metadata-action from 4 to 5 (#7916) Bumps [docker/metadata-action](https://github.com/docker/metadata-action) from 4 to 5. - [Release notes](https://github.com/docker/metadata-action/releases) - [Upgrade guide](https://github.com/docker/metadata-action/blob/master/UPGRADE.md) - [Commits](https://github.com/docker/metadata-action/compare/v4...v5) --- updated-dependencies: - dependency-name: docker/metadata-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build-legacy-branch.yaml | 4 ++-- .github/workflows/call-build-images.yaml | 4 ++-- .github/workflows/call-integration-image-build.yaml | 4 ++-- .github/workflows/pr-image-tests.yaml | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/build-legacy-branch.yaml b/.github/workflows/build-legacy-branch.yaml index 435fb9af804..9522f9fc9dc 100644 --- a/.github/workflows/build-legacy-branch.yaml +++ b/.github/workflows/build-legacy-branch.yaml @@ -72,7 +72,7 @@ jobs: password: ${{ secrets.GITHUB_TOKEN }} - id: debug-meta - uses: docker/metadata-action@v4 + uses: docker/metadata-action@v5 with: images: ${{ env.IMAGE_NAME }} tags: | @@ -95,7 +95,7 @@ jobs: - name: Extract metadata from Github id: meta - uses: docker/metadata-action@v4 + uses: docker/metadata-action@v5 with: images: ${{ env.IMAGE_NAME }} tags: | diff --git a/.github/workflows/call-build-images.yaml b/.github/workflows/call-build-images.yaml index 1a696fd9401..5db65d3f184 100644 --- a/.github/workflows/call-build-images.yaml +++ b/.github/workflows/call-build-images.yaml @@ -104,7 +104,7 @@ jobs: - name: Extract metadata from Github id: meta - uses: docker/metadata-action@v4 + uses: docker/metadata-action@v5 with: images: ${{ inputs.registry }}/${{ inputs.image }} tags: | @@ -131,7 +131,7 @@ jobs: RELEASE_VERSION=${{ inputs.version }} - id: debug-meta - uses: docker/metadata-action@v4 + uses: docker/metadata-action@v5 with: images: ${{ inputs.registry }}/${{ inputs.image }} tags: | diff --git a/.github/workflows/call-integration-image-build.yaml b/.github/workflows/call-integration-image-build.yaml index 5e62c813d3a..6adf262ec85 100644 --- a/.github/workflows/call-integration-image-build.yaml +++ b/.github/workflows/call-integration-image-build.yaml @@ -55,7 +55,7 @@ jobs: - name: Extract metadata from Github id: meta - uses: docker/metadata-action@v4 + uses: docker/metadata-action@v5 with: images: ${{ inputs.registry }}/${{ inputs.image }} tags: | @@ -91,7 +91,7 @@ jobs: - name: Extract metadata from Github id: meta-debug - uses: docker/metadata-action@v4 + uses: docker/metadata-action@v5 with: images: ${{ inputs.registry }}/${{ inputs.image }} tags: | diff --git a/.github/workflows/pr-image-tests.yaml b/.github/workflows/pr-image-tests.yaml index 0c37ac951e6..7c26d00dbe3 100644 --- a/.github/workflows/pr-image-tests.yaml +++ b/.github/workflows/pr-image-tests.yaml @@ -28,7 +28,7 @@ jobs: - name: Extract metadata from Github id: meta - uses: docker/metadata-action@v4 + uses: docker/metadata-action@v5 with: images: ${{ github.repository }}/pr-${{ github.event.pull_request.number }} tags: | @@ -100,7 +100,7 @@ jobs: - name: Extract metadata from Github id: meta - uses: docker/metadata-action@v4 + uses: docker/metadata-action@v5 with: images: ${{ github.repository }}/pr-${{ github.event.pull_request.number }} tags: | From c8f0f60d9000528a2a604c0117d934da91f25a8c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 13 Sep 2023 10:04:24 +0100 Subject: [PATCH 239/315] workflows: bump docker/build-push-action from 4 to 5 (#7915) Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 4 to 5. - [Release notes](https://github.com/docker/build-push-action/releases) - [Commits](https://github.com/docker/build-push-action/compare/v4...v5) --- updated-dependencies: - dependency-name: docker/build-push-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build-legacy-branch.yaml | 4 ++-- .github/workflows/call-build-images.yaml | 6 +++--- .github/workflows/call-integration-image-build.yaml | 4 ++-- .github/workflows/pr-compile-check.yaml | 2 +- .github/workflows/pr-image-tests.yaml | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/build-legacy-branch.yaml b/.github/workflows/build-legacy-branch.yaml index 9522f9fc9dc..129b356f510 100644 --- a/.github/workflows/build-legacy-branch.yaml +++ b/.github/workflows/build-legacy-branch.yaml @@ -80,7 +80,7 @@ jobs: - name: Build the legacy x86_64 debug image if: matrix.arch == 'amd64' - uses: docker/build-push-action@v4 + uses: docker/build-push-action@v5 with: file: ./Dockerfile.x86_64.debug context: . @@ -102,7 +102,7 @@ jobs: raw,${{ matrix.suffix }}-${{ inputs.ref }} - name: Build the legacy ${{ matrix.arch }} image - uses: docker/build-push-action@v4 + uses: docker/build-push-action@v5 with: file: ./Dockerfile.${{ matrix.suffix }} context: . diff --git a/.github/workflows/call-build-images.yaml b/.github/workflows/call-build-images.yaml index 5db65d3f184..d3e83785fad 100644 --- a/.github/workflows/call-build-images.yaml +++ b/.github/workflows/call-build-images.yaml @@ -114,7 +114,7 @@ jobs: - name: Build the production images id: build_push - uses: docker/build-push-action@v4 + uses: docker/build-push-action@v5 with: file: ./dockerfiles/Dockerfile context: . @@ -141,7 +141,7 @@ jobs: - name: Build the debug multi-arch images id: debug_build_push - uses: docker/build-push-action@v4 + uses: docker/build-push-action@v5 with: file: ./dockerfiles/Dockerfile context: . @@ -314,7 +314,7 @@ jobs: docker push ${{ inputs.registry }}/${{ inputs.image }}:windows-${{ matrix.windows-base-version }}-${{ inputs.version }} # We cannot use this action as it requires privileged mode - # uses: docker/build-push-action@v4 + # uses: docker/build-push-action@v5 # with: # file: ./dockerfiles/Dockerfile.windows # context: . diff --git a/.github/workflows/call-integration-image-build.yaml b/.github/workflows/call-integration-image-build.yaml index 6adf262ec85..48233e960f3 100644 --- a/.github/workflows/call-integration-image-build.yaml +++ b/.github/workflows/call-integration-image-build.yaml @@ -62,7 +62,7 @@ jobs: raw,${{ inputs.image-tag }} - name: Build the AMD64 image - uses: docker/build-push-action@v4 + uses: docker/build-push-action@v5 with: file: ./dockerfiles/Dockerfile context: . @@ -98,7 +98,7 @@ jobs: raw,${{ inputs.image-tag }}-debug - name: Build the AMD64 debug image - uses: docker/build-push-action@v4 + uses: docker/build-push-action@v5 with: file: ./dockerfiles/Dockerfile context: . diff --git a/.github/workflows/pr-compile-check.yaml b/.github/workflows/pr-compile-check.yaml index 3aaee5ac4ab..cd60e1ac405 100644 --- a/.github/workflows/pr-compile-check.yaml +++ b/.github/workflows/pr-compile-check.yaml @@ -22,7 +22,7 @@ jobs: uses: docker/setup-buildx-action@v2 - name: Attempt to build current source for CentOS 7 - uses: docker/build-push-action@v4 + uses: docker/build-push-action@v5 with: context: . file: ./dockerfiles/Dockerfile.centos7 diff --git a/.github/workflows/pr-image-tests.yaml b/.github/workflows/pr-image-tests.yaml index 7c26d00dbe3..5e64481058d 100644 --- a/.github/workflows/pr-image-tests.yaml +++ b/.github/workflows/pr-image-tests.yaml @@ -36,7 +36,7 @@ jobs: - name: Build the multi-arch images id: build - uses: docker/build-push-action@v4 + uses: docker/build-push-action@v5 with: file: ./dockerfiles/Dockerfile context: . @@ -55,7 +55,7 @@ jobs: shell: bash - name: Build the debug multi-arch images - uses: docker/build-push-action@v4 + uses: docker/build-push-action@v5 with: file: ./dockerfiles/Dockerfile context: . From 44558d8de1110e626f0679dcf7f83f25de7165cf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 13 Sep 2023 10:04:46 +0100 Subject: [PATCH 240/315] workflows: bump docker/setup-qemu-action from 2 to 3 (#7913) Bumps [docker/setup-qemu-action](https://github.com/docker/setup-qemu-action) from 2 to 3. - [Release notes](https://github.com/docker/setup-qemu-action/releases) - [Commits](https://github.com/docker/setup-qemu-action/compare/v2...v3) --- updated-dependencies: - dependency-name: docker/setup-qemu-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build-legacy-branch.yaml | 2 +- .github/workflows/call-build-images.yaml | 2 +- .github/workflows/call-build-linux-packages.yaml | 2 +- .github/workflows/call-test-images.yaml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build-legacy-branch.yaml b/.github/workflows/build-legacy-branch.yaml index 129b356f510..060d383fe59 100644 --- a/.github/workflows/build-legacy-branch.yaml +++ b/.github/workflows/build-legacy-branch.yaml @@ -59,7 +59,7 @@ jobs: ref: "1.8" # Fixed to this branch - name: Set up QEMU - uses: docker/setup-qemu-action@v2 + uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v2 diff --git a/.github/workflows/call-build-images.yaml b/.github/workflows/call-build-images.yaml index d3e83785fad..ed7d8939d0a 100644 --- a/.github/workflows/call-build-images.yaml +++ b/.github/workflows/call-build-images.yaml @@ -90,7 +90,7 @@ jobs: ref: ${{ inputs.ref }} - name: Set up QEMU - uses: docker/setup-qemu-action@v2 + uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v2 diff --git a/.github/workflows/call-build-linux-packages.yaml b/.github/workflows/call-build-linux-packages.yaml index 8b5545d1560..7173fc80a46 100644 --- a/.github/workflows/call-build-linux-packages.yaml +++ b/.github/workflows/call-build-linux-packages.yaml @@ -125,7 +125,7 @@ jobs: uses: self-actuated/hub-mirror@master - name: Set up QEMU - uses: docker/setup-qemu-action@v2 + uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v2 diff --git a/.github/workflows/call-test-images.yaml b/.github/workflows/call-test-images.yaml index 22a90cbe6ad..7acf14b61d7 100644 --- a/.github/workflows/call-test-images.yaml +++ b/.github/workflows/call-test-images.yaml @@ -144,7 +144,7 @@ jobs: - name: Set up QEMU using standard action if: ${{ matrix.arch != 'linux/arm64' }} - uses: docker/setup-qemu-action@v2 + uses: docker/setup-qemu-action@v3 # Without this QEMU fails for ARM64 - name: Set up binary emulation for QEMU From 9c78785b4a95a99ec08198a244efbdc40f3fe55d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 13 Sep 2023 10:05:39 +0100 Subject: [PATCH 241/315] workflows: bump docker/login-action from 2 to 3 (#7912) Bumps [docker/login-action](https://github.com/docker/login-action) from 2 to 3. - [Release notes](https://github.com/docker/login-action/releases) - [Commits](https://github.com/docker/login-action/compare/v2...v3) --- updated-dependencies: - dependency-name: docker/login-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build-legacy-branch.yaml | 4 ++-- .github/workflows/call-build-images.yaml | 8 ++++---- .github/workflows/call-integration-image-build.yaml | 4 ++-- .github/workflows/call-test-images.yaml | 6 +++--- .github/workflows/cron-trivy.yaml | 2 +- .github/workflows/cron-unstable-build.yaml | 2 +- .github/workflows/staging-release.yaml | 12 ++++++------ 7 files changed, 19 insertions(+), 19 deletions(-) diff --git a/.github/workflows/build-legacy-branch.yaml b/.github/workflows/build-legacy-branch.yaml index 060d383fe59..2e991026f84 100644 --- a/.github/workflows/build-legacy-branch.yaml +++ b/.github/workflows/build-legacy-branch.yaml @@ -65,7 +65,7 @@ jobs: uses: docker/setup-buildx-action@v2 - name: Log in to the Container registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} @@ -130,7 +130,7 @@ jobs: uses: docker/setup-buildx-action@v2 - name: Log in to the Container registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} diff --git a/.github/workflows/call-build-images.yaml b/.github/workflows/call-build-images.yaml index ed7d8939d0a..7ca1e97502b 100644 --- a/.github/workflows/call-build-images.yaml +++ b/.github/workflows/call-build-images.yaml @@ -96,7 +96,7 @@ jobs: uses: docker/setup-buildx-action@v2 - name: Log in to the Container registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ${{ inputs.registry }} username: ${{ inputs.username }} @@ -168,7 +168,7 @@ jobs: packages: read steps: - name: Log in to the Container registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ${{ inputs.registry }} username: ${{ inputs.username }} @@ -199,7 +199,7 @@ jobs: packages: read steps: - name: Log in to the Container registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ${{ inputs.registry }} username: ${{ inputs.username }} @@ -302,7 +302,7 @@ jobs: ref: ${{ inputs.ref }} - name: Log in to the Container registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ${{ inputs.registry }} username: ${{ inputs.username }} diff --git a/.github/workflows/call-integration-image-build.yaml b/.github/workflows/call-integration-image-build.yaml index 48233e960f3..69049b0f6ee 100644 --- a/.github/workflows/call-integration-image-build.yaml +++ b/.github/workflows/call-integration-image-build.yaml @@ -47,7 +47,7 @@ jobs: uses: docker/setup-buildx-action@v2 - name: Log in to the Container registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ${{ inputs.registry }} username: ${{ inputs.username }} @@ -125,7 +125,7 @@ jobs: ref: ${{ inputs.ref }} - name: Log in to the Container registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ${{ inputs.registry }} username: ${{ inputs.username }} diff --git a/.github/workflows/call-test-images.yaml b/.github/workflows/call-test-images.yaml index 7acf14b61d7..29bc0cd3d5d 100644 --- a/.github/workflows/call-test-images.yaml +++ b/.github/workflows/call-test-images.yaml @@ -45,7 +45,7 @@ jobs: uses: sigstore/cosign-installer@v2 - name: Log in to the Container registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ${{ inputs.registry }} username: ${{ inputs.username }} @@ -87,7 +87,7 @@ jobs: expected: arm steps: - name: Log in to the Container registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ${{ inputs.registry }} username: ${{ inputs.username }} @@ -136,7 +136,7 @@ jobs: ref: ${{ inputs.ref }} - name: Log in to the Container registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ${{ inputs.registry }} username: ${{ inputs.username }} diff --git a/.github/workflows/cron-trivy.yaml b/.github/workflows/cron-trivy.yaml index ce204ae8445..a126681946f 100644 --- a/.github/workflows/cron-trivy.yaml +++ b/.github/workflows/cron-trivy.yaml @@ -37,7 +37,7 @@ jobs: local_tag: arm32 steps: - name: Log in to the Container registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} diff --git a/.github/workflows/cron-unstable-build.yaml b/.github/workflows/cron-unstable-build.yaml index 29c87b9811f..82235a41518 100644 --- a/.github/workflows/cron-unstable-build.yaml +++ b/.github/workflows/cron-unstable-build.yaml @@ -173,7 +173,7 @@ jobs: shell: bash - name: Log in to the Container registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} diff --git a/.github/workflows/staging-release.yaml b/.github/workflows/staging-release.yaml index b8a9eee1be7..8ae352bdacd 100644 --- a/.github/workflows/staging-release.yaml +++ b/.github/workflows/staging-release.yaml @@ -502,13 +502,13 @@ jobs: steps: - name: Login to Docker Hub - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Login to GitHub Container Registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} @@ -623,7 +623,7 @@ jobs: ] steps: - name: Login to GitHub Container Registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} @@ -647,7 +647,7 @@ jobs: shell: bash - name: Login to Docker Hub - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} @@ -677,13 +677,13 @@ jobs: uses: sigstore/cosign-installer@v2 - name: Login to Docker Hub - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Login to GitHub Container Registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} From 7d25ed2d0b83aa07d6e01000e0f84c5511b3f06f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 13 Sep 2023 10:44:46 +0100 Subject: [PATCH 242/315] workflows: bump docker/setup-buildx-action from 2 to 3 (#7914) Bumps [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) from 2 to 3. - [Release notes](https://github.com/docker/setup-buildx-action/releases) - [Commits](https://github.com/docker/setup-buildx-action/compare/v2...v3) --- updated-dependencies: - dependency-name: docker/setup-buildx-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build-legacy-branch.yaml | 4 ++-- .github/workflows/call-build-images.yaml | 2 +- .github/workflows/call-build-linux-packages.yaml | 2 +- .github/workflows/call-integration-image-build.yaml | 2 +- .github/workflows/pr-compile-check.yaml | 2 +- .github/workflows/pr-image-tests.yaml | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build-legacy-branch.yaml b/.github/workflows/build-legacy-branch.yaml index 2e991026f84..2bca2a719ca 100644 --- a/.github/workflows/build-legacy-branch.yaml +++ b/.github/workflows/build-legacy-branch.yaml @@ -62,7 +62,7 @@ jobs: uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v3 - name: Log in to the Container registry uses: docker/login-action@v3 @@ -127,7 +127,7 @@ jobs: - build-legacy-images-matrix steps: - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v3 - name: Log in to the Container registry uses: docker/login-action@v3 diff --git a/.github/workflows/call-build-images.yaml b/.github/workflows/call-build-images.yaml index 7ca1e97502b..fd2cf5b1dff 100644 --- a/.github/workflows/call-build-images.yaml +++ b/.github/workflows/call-build-images.yaml @@ -93,7 +93,7 @@ jobs: uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v3 - name: Log in to the Container registry uses: docker/login-action@v3 diff --git a/.github/workflows/call-build-linux-packages.yaml b/.github/workflows/call-build-linux-packages.yaml index 7173fc80a46..b8000225abe 100644 --- a/.github/workflows/call-build-linux-packages.yaml +++ b/.github/workflows/call-build-linux-packages.yaml @@ -128,7 +128,7 @@ jobs: uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v3 - name: Replace all special characters with dashes id: formatted_distro diff --git a/.github/workflows/call-integration-image-build.yaml b/.github/workflows/call-integration-image-build.yaml index 69049b0f6ee..1644883c0d4 100644 --- a/.github/workflows/call-integration-image-build.yaml +++ b/.github/workflows/call-integration-image-build.yaml @@ -44,7 +44,7 @@ jobs: ref: ${{ inputs.ref }} - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v3 - name: Log in to the Container registry uses: docker/login-action@v3 diff --git a/.github/workflows/pr-compile-check.yaml b/.github/workflows/pr-compile-check.yaml index cd60e1ac405..d9f3dc92ab5 100644 --- a/.github/workflows/pr-compile-check.yaml +++ b/.github/workflows/pr-compile-check.yaml @@ -19,7 +19,7 @@ jobs: uses: actions/checkout@v4 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v3 - name: Attempt to build current source for CentOS 7 uses: docker/build-push-action@v5 diff --git a/.github/workflows/pr-image-tests.yaml b/.github/workflows/pr-image-tests.yaml index 5e64481058d..2cdc362200e 100644 --- a/.github/workflows/pr-image-tests.yaml +++ b/.github/workflows/pr-image-tests.yaml @@ -24,7 +24,7 @@ jobs: uses: actions/checkout@v4 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v3 - name: Extract metadata from Github id: meta From 5e525659a7588a2d27ea2d16dee06fe5a9facb0e Mon Sep 17 00:00:00 2001 From: Phillip Whelan Date: Mon, 18 Sep 2023 11:03:12 -0700 Subject: [PATCH 243/315] in_calyptia_fleet: improve configuration reloading. (#7925) - use current configuration timestamp to evaluate if a reload is required. - increase minimum interval to 15 seconds, pause collector sooner. - use symlinks instead of hardlinks and check the filename to properly account for the timestamp. - in_calyptia_fleet: initialize ctx->collect_fd to -1. - in_calyptia_fleet: check return value from strtol() --------- Signed-off-by: Phillip Whelan --- plugins/in_calyptia_fleet/in_calyptia_fleet.c | 169 ++++++++++++++---- 1 file changed, 139 insertions(+), 30 deletions(-) diff --git a/plugins/in_calyptia_fleet/in_calyptia_fleet.c b/plugins/in_calyptia_fleet/in_calyptia_fleet.c index caca271e857..bb8dfb99992 100644 --- a/plugins/in_calyptia_fleet/in_calyptia_fleet.c +++ b/plugins/in_calyptia_fleet/in_calyptia_fleet.c @@ -42,7 +42,7 @@ #define CALYPTIA_H_CTYPE "Content-Type" #define CALYPTIA_H_CTYPE_JSON "application/json" -#define DEFAULT_INTERVAL_SEC "3" +#define DEFAULT_INTERVAL_SEC "15" #define DEFAULT_INTERVAL_NSEC "0" #define CALYPTIA_HOST "cloud-api.calyptia.com" @@ -61,6 +61,11 @@ struct flb_in_calyptia_fleet_config { int interval_sec; int interval_nsec; + /* Grabbed from the cfg_path, used to check if configuration has + * has been updated. + */ + long config_timestamp; + flb_sds_t api_key; flb_sds_t fleet_id; flb_sds_t fleet_name; @@ -103,12 +108,12 @@ static char *find_case_header(struct flb_http_client *cli, const char *header) ptr+=2; - // no space left for header + /* no space left for header */ if (ptr + strlen(header)+2 >= cli->resp.payload) { return NULL; } - // matched header and the delimiter + /* matched header and the delimiter */ if (strncasecmp(ptr, header, strlen(header)) == 0) { if (ptr[strlen(header)] == ':' && ptr[strlen(header)+1] == ' ') { @@ -159,6 +164,11 @@ static int case_header_lookup(struct flb_http_client *cli, return -1; } + /* sanity check that the header_len does not exceed the headers. */ + if (ptr + header_len + 2 > end) { + return -1; + } + ptr += header_len + 2; *out_val = ptr; @@ -257,13 +267,49 @@ static int is_cur_fleet_config(struct flb_in_calyptia_fleet_config *ctx, struct return ret; } +static int is_timestamped_fleet_config(struct flb_in_calyptia_fleet_config *ctx, struct flb_config *cfg) +{ + char *fname; + char *end; + long val; + + if (cfg->conf_path_file == NULL) { + return FLB_FALSE; + } + + fname = strrchr(cfg->conf_path_file, PATH_SEPARATOR[0]); + + if (fname == NULL) { + return FLB_FALSE; + } + + fname++; + + errno = 0; + val = strtol(fname, &end, 10); + + if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) || + (errno != 0 && val == 0)) { + flb_errno(); + return FLB_FALSE; + } + + if (strcmp(end, ".ini") == 0) { + return FLB_TRUE; + } + + return FLB_FALSE; +} + static int is_fleet_config(struct flb_in_calyptia_fleet_config *ctx, struct flb_config *cfg) { if (cfg->conf_path_file == NULL) { return FLB_FALSE; } - return is_new_fleet_config(ctx, cfg) || is_cur_fleet_config(ctx, cfg); + return is_new_fleet_config(ctx, cfg) || + is_cur_fleet_config(ctx, cfg) || + is_timestamped_fleet_config(ctx, cfg); } static int exists_new_fleet_config(struct flb_in_calyptia_fleet_config *ctx) @@ -296,7 +342,7 @@ static void *do_reload(void *data) { struct reload_ctx *reload = (struct reload_ctx *)data; - // avoid reloading the current configuration... just use our new one! + /* avoid reloading the current configuration... just use our new one! */ flb_context_set(reload->flb); reload->flb->config->enable_hot_reload = FLB_TRUE; reload->flb->config->conf_path_file = reload->cfg_path; @@ -359,19 +405,33 @@ static int execute_reload(struct flb_in_calyptia_fleet_config *ctx, flb_sds_t cf pthread_attr_t ptha; flb_ctx_t *flb = flb_context_get(); + if (ctx->collect_fd > 0) { + flb_input_collector_pause(ctx->collect_fd, ctx->ins); + } if (flb == NULL) { flb_plg_error(ctx->ins, "unable to get fluent-bit context."); + + if (ctx->collect_fd > 0) { + flb_input_collector_resume(ctx->collect_fd, ctx->ins); + } + return FLB_FALSE; } - // fix execution in valgrind... - // otherwise flb_reload errors out with: - // [error] [reload] given flb context is NULL + /* fix execution in valgrind... + * otherwise flb_reload errors out with: + * [error] [reload] given flb context is NULL + */ flb_plg_info(ctx->ins, "loading configuration from %s.", cfgpath); if (test_config_is_valid(cfgpath) == FLB_FALSE) { flb_plg_error(ctx->ins, "unable to load configuration."); + + if (ctx->collect_fd > 0) { + flb_input_collector_resume(ctx->collect_fd, ctx->ins); + } + return FLB_FALSE; } @@ -447,8 +507,7 @@ static flb_sds_t parse_api_key_json(struct flb_in_calyptia_fleet_config *ctx, } project_id = flb_sds_create_len(cur->val.via.str.ptr, - cur->val.via.str.size); - + cur->val.via.str.size); msgpack_unpacked_destroy(&result); flb_free(pack); @@ -724,7 +783,6 @@ static int in_calyptia_fleet_collect(struct flb_input_instance *ins, goto http_error; } - // Wed, 21 Oct 2015 07:28:00 GMT flb_strptime(fbit_last_modified, "%a, %d %B %Y %H:%M:%S GMT", &tm_last_modified); time_last_modified = mktime(&tm_last_modified.tm); @@ -807,14 +865,16 @@ static int in_calyptia_fleet_collect(struct flb_input_instance *ins, flb_sds_destroy(cfgoldname); } - link(cfgname, cfgnewname); + symlink(cfgname, cfgnewname); + } - // FORCE THE RELOAD!!! + if (ctx->config_timestamp < time_last_modified) { + flb_plg_debug(ctx->ins, "new configuration is newer than current: %ld < %ld", + ctx->config_timestamp, time_last_modified); flb_plg_info(ctx->ins, "force the reloading of the configuration file=%d.", ctx->event_fd); - flb_sds_destroy(cfgname); flb_sds_destroy(data); - if (execute_reload(ctx, cfgnewname) == FLB_FALSE) { + if (execute_reload(ctx, cfgname) == FLB_FALSE) { cfgoldname = old_fleet_config_filename(ctx); cfgcurname = cur_fleet_config_filename(ctx); rename(cfgoldname, cfgcurname); @@ -822,7 +882,7 @@ static int in_calyptia_fleet_collect(struct flb_input_instance *ins, flb_sds_destroy(cfgoldname); goto reload_error; } - else { + else { FLB_INPUT_RETURN(0); } } @@ -838,10 +898,11 @@ static int in_calyptia_fleet_collect(struct flb_input_instance *ins, FLB_INPUT_RETURN(ret); } -// recursively create directories, based on: -// https://stackoverflow.com/a/2336245 -// who found it at: -// http://nion.modprobe.de/blog/archives/357-Recursive-directory-creation.html +/* recursively create directories, based on: + * https://stackoverflow.com/a/2336245 + * who found it at: + * http://nion.modprobe.de/blog/archives/357-Recursive-directory-creation.html + */ static int _mkdir(const char *dir, int perms) { char tmp[255]; char *ptr = NULL; @@ -907,23 +968,62 @@ static int create_fleet_directory(struct flb_in_calyptia_fleet_config *ctx) static int load_fleet_config(struct flb_in_calyptia_fleet_config *ctx) { flb_ctx_t *flb_ctx = flb_context_get(); - + char *fname; + char *ext; + long timestamp; + char realname[4096]; + ssize_t len; if (create_fleet_directory(ctx) != 0) { return -1; } - // check if we are already using the fleet configuration file. + /* check if we are already using the fleet configuration file. */ if (is_fleet_config(ctx, flb_ctx->config) == FLB_FALSE) { - // check which one and load it + /* check which one and load it */ if (exists_cur_fleet_config(ctx) == FLB_TRUE) { - execute_reload(ctx, cur_fleet_config_filename(ctx)); + return execute_reload(ctx, cur_fleet_config_filename(ctx)); } - else if (exists_new_fleet_config(ctx) == FLB_TRUE) { - execute_reload(ctx, new_fleet_config_filename(ctx)); + else if (exists_new_fleet_config(ctx) == FLB_TRUE) { + return execute_reload(ctx, new_fleet_config_filename(ctx)); } } - return 0; + else { + if (is_new_fleet_config(ctx, flb_ctx->config) || is_cur_fleet_config(ctx, flb_ctx->config)) { + len = readlink(flb_ctx->config->conf_path_file, realname, sizeof(realname)); + + if (len > sizeof(realname)) { + return FLB_FALSE; + } + + fname = basename(realname); + } + else { + fname = basename(flb_ctx->config->conf_path_file); + } + + if (fname == NULL) { + return FLB_FALSE; + } + + errno = 0; + timestamp = strtol(fname, &ext, 10); + + if ((errno == ERANGE && (timestamp == LONG_MAX || timestamp == LONG_MIN)) || + (errno != 0 && timestamp == 0)) { + flb_errno(); + return FLB_FALSE; + } + + /* unable to parse the timstamp */ + if (errno == ERANGE) { + return FLB_FALSE; + } + + ctx->config_timestamp = timestamp; + } + + return FLB_FALSE; } static int in_calyptia_fleet_init(struct flb_input_instance *in, @@ -953,6 +1053,7 @@ static int in_calyptia_fleet_init(struct flb_input_instance *in, return -1; } ctx->ins = in; + ctx->collect_fd = -1; /* Load the config map */ @@ -1004,9 +1105,18 @@ static int in_calyptia_fleet_init(struct flb_input_instance *in, ctx->interval_nsec = atoi(DEFAULT_INTERVAL_NSEC); } + if (ctx->interval_sec < atoi(DEFAULT_INTERVAL_SEC)) { + ctx->interval_sec = atoi(DEFAULT_INTERVAL_SEC); + } + /* Set the context */ flb_input_set_context(in, ctx); - + + /* if we load a new configuration then we will be reloaded anyways */ + if (load_fleet_config(ctx) == FLB_TRUE) { + return 0; + } + /* Set our collector based on time */ ret = flb_input_set_collector_time(in, in_calyptia_fleet_collect, @@ -1015,14 +1125,13 @@ static int in_calyptia_fleet_init(struct flb_input_instance *in, config); if (ret == -1) { - flb_plg_error(ctx->ins, "could not set collector for Health input plugin"); + flb_plg_error(ctx->ins, "could not initialize collector for fleet input plugin"); flb_free(ctx); return -1; } ctx->collect_fd = ret; - load_fleet_config(ctx); return 0; } From bda170b62fe6ad82f6c1277ca7eb7d5e36e6cf76 Mon Sep 17 00:00:00 2001 From: Takahiro Yamashita Date: Mon, 18 Sep 2023 09:05:08 +0900 Subject: [PATCH 244/315] kernel: add release function Signed-off-by: Takahiro Yamashita --- include/fluent-bit/flb_kernel.h | 1 + src/flb_kernel.c | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/include/fluent-bit/flb_kernel.h b/include/fluent-bit/flb_kernel.h index 21a9d05c808..116b4a79d9a 100644 --- a/include/fluent-bit/flb_kernel.h +++ b/include/fluent-bit/flb_kernel.h @@ -35,5 +35,6 @@ struct flb_kernel { }; struct flb_kernel *flb_kernel_info(); +void flb_kernel_destroy(struct flb_kernel *kernel); #endif diff --git a/src/flb_kernel.c b/src/flb_kernel.c index 5e5fa886abb..d29ba922fe9 100644 --- a/src/flb_kernel.c +++ b/src/flb_kernel.c @@ -147,3 +147,15 @@ struct flb_kernel *flb_kernel_info() } #endif + +void flb_kernel_destroy(struct flb_kernel *kernel) +{ + if (kernel == NULL) { + return; + } + + if (kernel->s_version.data) { + flb_free(kernel->s_version.data); + } + flb_free(kernel); +} From 0ff2a69c53cda7801d345a50a55792587a53a209 Mon Sep 17 00:00:00 2001 From: Takahiro Yamashita Date: Mon, 18 Sep 2023 09:05:48 +0900 Subject: [PATCH 245/315] config: release kernel info using flb_kernel_destroy Signed-off-by: Takahiro Yamashita --- src/flb_config.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/flb_config.c b/src/flb_config.c index 459ff8197dd..a0feb73b3f2 100644 --- a/src/flb_config.c +++ b/src/flb_config.c @@ -393,8 +393,7 @@ void flb_config_exit(struct flb_config *config) } if (config->kernel) { - flb_free(config->kernel->s_version.data); - flb_free(config->kernel); + flb_kernel_destroy(config->kernel); } /* release resources */ From 142e1d197817a8bef1fb1ac12ffc17a583ea07e1 Mon Sep 17 00:00:00 2001 From: Kazuhiro Suzuki Date: Thu, 21 Sep 2023 13:10:30 +0900 Subject: [PATCH 246/315] out_loki: add compress option for gzip (#7949) --------- Signed-off-by: Kazuhiro Suzuki --- plugins/out_loki/loki.c | 59 ++++++++++++++++++++++++++++++++++++++--- plugins/out_loki/loki.h | 1 + 2 files changed, 56 insertions(+), 4 deletions(-) diff --git a/plugins/out_loki/loki.c b/plugins/out_loki/loki.c index 57eb4f681b5..d93a3f9aad6 100644 --- a/plugins/out_loki/loki.c +++ b/plugins/out_loki/loki.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -905,6 +906,7 @@ static struct flb_loki *loki_config_create(struct flb_output_instance *ins, int io_flags = 0; struct flb_loki *ctx; struct flb_upstream *upstream; + char *compress; /* Create context */ ctx = flb_calloc(1, sizeof(struct flb_loki)); @@ -951,6 +953,15 @@ static struct flb_loki *loki_config_create(struct flb_output_instance *ins, } } + /* Compress (gzip) */ + compress = (char *) flb_output_get_property("compress", ins); + ctx->compress_gzip = FLB_FALSE; + if (compress) { + if (strcasecmp(compress, "gzip") == 0) { + ctx->compress_gzip = FLB_TRUE; + } + } + /* Line Format */ if (strcasecmp(ctx->line_format, "json") == 0) { ctx->out_line_format = FLB_LOKI_FMT_JSON; @@ -1477,6 +1488,16 @@ static flb_sds_t loki_compose_payload(struct flb_loki *ctx, return json; } +static void payload_release(void *payload, int compressed) +{ + if (compressed) { + flb_free(payload); + } + else { + flb_sds_destroy(payload); + } +} + static void cb_loki_flush(struct flb_event_chunk *event_chunk, struct flb_output_flush *out_flush, struct flb_input_instance *i_ins, @@ -1487,6 +1508,9 @@ static void cb_loki_flush(struct flb_event_chunk *event_chunk, int out_ret = FLB_OK; size_t b_sent; flb_sds_t payload = NULL; + flb_sds_t out_buf = NULL; + size_t out_size; + int compressed = FLB_FALSE; struct flb_loki *ctx = out_context; struct flb_connection *u_conn; struct flb_http_client *c; @@ -1520,31 +1544,48 @@ static void cb_loki_flush(struct flb_event_chunk *event_chunk, flb_sds_len(event_chunk->tag), event_chunk->data, event_chunk->size, &dynamic_tenant_id->value); + if (!payload) { flb_plg_error(ctx->ins, "cannot compose request payload"); FLB_OUTPUT_RETURN(FLB_RETRY); } + /* Map buffer */ + out_buf = payload; + out_size = flb_sds_len(payload); + + if (ctx->compress_gzip == FLB_TRUE) { + ret = flb_gzip_compress((void *) payload, flb_sds_len(payload), (void **) &out_buf, &out_size); + if (ret == -1) { + flb_plg_error(ctx->ins, + "cannot gzip payload, disabling compression"); + } else { + compressed = FLB_TRUE; + /* payload is not longer needed */ + flb_sds_destroy(payload); + } + } + /* Lookup an available connection context */ u_conn = flb_upstream_conn_get(ctx->u); if (!u_conn) { flb_plg_error(ctx->ins, "no upstream connections available"); - flb_sds_destroy(payload); + payload_release(out_buf, compressed); FLB_OUTPUT_RETURN(FLB_RETRY); } /* Create HTTP client context */ c = flb_http_client(u_conn, FLB_HTTP_POST, FLB_LOKI_URI, - payload, flb_sds_len(payload), + out_buf, out_size, ctx->tcp_host, ctx->tcp_port, NULL, 0); if (!c) { flb_plg_error(ctx->ins, "cannot create HTTP client context"); - flb_sds_destroy(payload); + payload_release(out_buf, compressed); flb_upstream_conn_release(u_conn); FLB_OUTPUT_RETURN(FLB_RETRY); @@ -1568,6 +1609,10 @@ static void cb_loki_flush(struct flb_event_chunk *event_chunk, FLB_LOKI_CT, sizeof(FLB_LOKI_CT) - 1, FLB_LOKI_CT_JSON, sizeof(FLB_LOKI_CT_JSON) - 1); + if (compressed == FLB_TRUE) { + flb_http_set_content_encoding_gzip(c); + } + /* Add X-Scope-OrgID header */ if (dynamic_tenant_id->value != NULL) { flb_http_add_header(c, @@ -1583,7 +1628,7 @@ static void cb_loki_flush(struct flb_event_chunk *event_chunk, /* Send HTTP request */ ret = flb_http_do(c, &b_sent); - flb_sds_destroy(payload); + payload_release(out_buf, compressed); /* Validate HTTP client return status */ if (ret == 0) { @@ -1760,6 +1805,12 @@ static struct flb_config_map config_map[] = { "Set bearer token auth" }, + { + FLB_CONFIG_MAP_STR, "compress", NULL, + 0, FLB_FALSE, 0, + "Set payload compression in network transfer. Option available is 'gzip'" + }, + /* EOF */ {0} }; diff --git a/plugins/out_loki/loki.h b/plugins/out_loki/loki.h index 39ffed8d8a9..2011cee3ded 100644 --- a/plugins/out_loki/loki.h +++ b/plugins/out_loki/loki.h @@ -58,6 +58,7 @@ struct flb_loki { flb_sds_t line_format; flb_sds_t tenant_id; flb_sds_t tenant_id_key_config; + int compress_gzip; /* HTTP Auth */ flb_sds_t http_user; From 4a1bf9c114893415e760da5b51e414bebff3b2a3 Mon Sep 17 00:00:00 2001 From: Phillip Whelan Date: Wed, 20 Sep 2023 21:51:03 -0700 Subject: [PATCH 247/315] lib: monkey: upgrade to v1.7.2 (#7951) Signed-off-by: Phillip Whelan --- lib/monkey/CMakeLists.txt | 2 +- lib/monkey/mk_core/external/winpthreads.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/monkey/CMakeLists.txt b/lib/monkey/CMakeLists.txt index 6211abaaf5a..2d43835b70f 100644 --- a/lib/monkey/CMakeLists.txt +++ b/lib/monkey/CMakeLists.txt @@ -23,7 +23,7 @@ endif() # Monkey Version set(MK_VERSION_MAJOR 1) set(MK_VERSION_MINOR 7) -set(MK_VERSION_PATCH 1) +set(MK_VERSION_PATCH 2) set(MK_VERSION_STR "${MK_VERSION_MAJOR}.${MK_VERSION_MINOR}.${MK_VERSION_PATCH}") # Output paths diff --git a/lib/monkey/mk_core/external/winpthreads.c b/lib/monkey/mk_core/external/winpthreads.c index abf55006727..db495198977 100644 --- a/lib/monkey/mk_core/external/winpthreads.c +++ b/lib/monkey/mk_core/external/winpthreads.c @@ -1098,7 +1098,7 @@ int pthread_setspecific(pthread_key_t key, const void *value) { pthread_t t = pthread_self(); - if (key > t->keymax) + if (key >= t->keymax) { int keymax = (key + 1) * 2; void **kv = (void**)realloc(t->keyval, keymax * sizeof(void *)); From 37fddf74bf7b096056d7ba3ab3da7391d6abb5f8 Mon Sep 17 00:00:00 2001 From: Takahiro Yamashita Date: Thu, 21 Sep 2023 13:52:13 +0900 Subject: [PATCH 248/315] docs: replace tab with white space (#7932) Signed-off-by: Takahiro Yamashita --- src/flb_processor.c | 50 ++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/src/flb_processor.c b/src/flb_processor.c index 3a4f578e5e3..c46bc16a551 100644 --- a/src/flb_processor.c +++ b/src/flb_processor.c @@ -283,13 +283,13 @@ int flb_processor_unit_set_property(struct flb_processor_unit *pu, const char *k if (v->type == CFL_VARIANT_STRING) { return flb_filter_set_property(pu->ctx, k, v->data.as_string); } - else if (v->type == CFL_VARIANT_ARRAY) { + else if (v->type == CFL_VARIANT_ARRAY) { for (i = 0; i < v->data.as_array->entry_count; i++) { val = v->data.as_array->entries[i]; ret = flb_filter_set_property(pu->ctx, k, val->data.as_string); - if (ret == -1) { + if (ret == -1) { return ret; } } @@ -336,7 +336,7 @@ int flb_processor_unit_init(struct flb_processor_unit *pu) if (pu->unit_type == FLB_PROCESSOR_UNIT_FILTER) { ret = flb_filter_init(proc->config, pu->ctx); - if (ret == -1) { + if (ret == -1) { flb_error("[processor] error initializing unit filter %s", pu->name); return -1; } @@ -372,7 +372,7 @@ int flb_processor_init(struct flb_processor *proc) pu = mk_list_entry(head, struct flb_processor_unit, _head); ret = flb_processor_unit_init(pu); - if (ret == -1) { + if (ret == -1) { return -1; } count++; @@ -382,7 +382,7 @@ int flb_processor_init(struct flb_processor *proc) pu = mk_list_entry(head, struct flb_processor_unit, _head); ret = flb_processor_unit_init(pu); - if (ret == -1) { + if (ret == -1) { return -1; } count++; @@ -392,7 +392,7 @@ int flb_processor_init(struct flb_processor *proc) pu = mk_list_entry(head, struct flb_processor_unit, _head); ret = flb_processor_unit_init(pu); - if (ret == -1) { + if (ret == -1) { return -1; } count++; @@ -501,7 +501,7 @@ int flb_processor_run(struct flb_processor *proc, */ if (ret == FLB_FILTER_MODIFIED) { - /* release intermediate buffer */ + /* release intermediate buffer */ if (cur_buf != data) { flb_free(cur_buf); } @@ -615,7 +615,7 @@ int flb_processor_run(struct flb_processor *proc, } else if (type == FLB_PROCESSOR_METRICS) { - if (p_ins->p->cb_process_metrics != NULL) { + if (p_ins->p->cb_process_metrics != NULL) { ret = p_ins->p->cb_process_metrics(p_ins, (struct cmt *) cur_buf, tag, @@ -632,7 +632,7 @@ int flb_processor_run(struct flb_processor *proc, } else if (type == FLB_PROCESSOR_TRACES) { - if (p_ins->p->cb_process_traces != NULL) { + if (p_ins->p->cb_process_traces != NULL) { ret = p_ins->p->cb_process_traces(p_ins, (struct ctrace *) cur_buf, tag, @@ -715,7 +715,7 @@ static int load_from_config_format_group(struct flb_processor *proc, int type, s /* every entry in the array must be a map */ tmp = array->entries[i]; - if (tmp->type != CFL_VARIANT_KVLIST) { + if (tmp->type != CFL_VARIANT_KVLIST) { return -1; } @@ -724,7 +724,7 @@ static int load_from_config_format_group(struct flb_processor *proc, int type, s /* get the processor name, this is a mandatory config field */ tmp = cfl_kvlist_fetch(kvlist, "name"); - if (!tmp) { + if (!tmp) { flb_error("processor configuration don't have a 'name' defined"); return -1; } @@ -733,7 +733,7 @@ static int load_from_config_format_group(struct flb_processor *proc, int type, s name = tmp->data.as_string; pu = flb_processor_unit_create(proc, type, name); - if (!pu) { + if (!pu) { flb_error("cannot create '%s' processor unit", name); return -1; } @@ -742,7 +742,7 @@ static int load_from_config_format_group(struct flb_processor *proc, int type, s cfl_list_foreach(head, &kvlist->list) { pair = cfl_list_entry(head, struct cfl_kvpair, _head); - if (strcmp(pair->key, "name") == 0) { + if (strcmp(pair->key, "name") == 0) { continue; } @@ -751,10 +751,10 @@ static int load_from_config_format_group(struct flb_processor *proc, int type, s */ if (pu->unit_type == FLB_PROCESSOR_UNIT_FILTER) { - if (strcmp(pair->key, "match") == 0) { + if (strcmp(pair->key, "match") == 0) { f_ins = (struct flb_filter_instance *)pu->ctx; - if (f_ins->match != NULL) { + if (f_ins->match != NULL) { flb_sds_destroy(f_ins->match); f_ins->match = NULL; } @@ -763,7 +763,7 @@ static int load_from_config_format_group(struct flb_processor *proc, int type, s ret = flb_processor_unit_set_property(pu, pair->key, pair->val); - if (ret == -1) { + if (ret == -1) { flb_error("cannot set property '%s' for processor '%s'", pair->key, name); return -1; } @@ -786,7 +786,7 @@ int flb_processors_load_from_config_format_group(struct flb_processor *proc, str if (val) { ret = load_from_config_format_group(proc, FLB_PROCESSOR_LOGS, val); - if (ret == -1) { + if (ret == -1) { flb_error("failed to load 'logs' processors"); return -1; } @@ -798,7 +798,7 @@ int flb_processors_load_from_config_format_group(struct flb_processor *proc, str if (val) { ret = load_from_config_format_group(proc, FLB_PROCESSOR_METRICS, val); - if (ret == -1) { + if (ret == -1) { flb_error("failed to load 'metrics' processors"); return -1; } @@ -809,7 +809,7 @@ int flb_processors_load_from_config_format_group(struct flb_processor *proc, str if (val) { ret = load_from_config_format_group(proc, FLB_PROCESSOR_TRACES, val); - if (ret == -1) { + if (ret == -1) { flb_error("failed to load 'traces' processors"); return -1; } @@ -860,7 +860,7 @@ int flb_processor_instance_set_property(struct flb_processor_instance *ins, ret = flb_log_get_level_str(tmp); flb_sds_destroy(tmp); - if (ret == -1) { + if (ret == -1) { return -1; } ins->log_level = ret; @@ -872,9 +872,9 @@ int flb_processor_instance_set_property(struct flb_processor_instance *ins, */ kv = flb_kv_item_create(&ins->properties, (char *) k, NULL); - if (!kv) { + if (!kv) { - if (tmp) { + if (tmp) { flb_sds_destroy(tmp); } return -1; @@ -1004,7 +1004,7 @@ int flb_processor_instance_check_properties( */ config_map = flb_config_map_create(config, p->config_map); - if (!config_map) { + if (!config_map) { flb_error("[native processor] error loading config map for '%s' plugin", p->name); return -1; @@ -1016,9 +1016,9 @@ int flb_processor_instance_check_properties( &ins->properties, ins->config_map); - if (ret == -1) { + if (ret == -1) { - if (config->program_name) { + if (config->program_name) { flb_helper("try the command: %s -F %s -h\n", config->program_name, ins->p->name); } From 9664fb5c839cea843d386cefb815ecd04929e32b Mon Sep 17 00:00:00 2001 From: Takahiro Yamashita Date: Sun, 17 Sep 2023 09:35:26 +0900 Subject: [PATCH 249/315] tests: internal: uri: add test Signed-off-by: Takahiro Yamashita --- tests/internal/CMakeLists.txt | 1 + tests/internal/uri.c | 87 +++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+) create mode 100644 tests/internal/uri.c diff --git a/tests/internal/CMakeLists.txt b/tests/internal/CMakeLists.txt index 2838e0cd90e..5288004dbab 100644 --- a/tests/internal/CMakeLists.txt +++ b/tests/internal/CMakeLists.txt @@ -40,6 +40,7 @@ set(UNIT_TESTS_FILES log.c log_event_decoder.c processor.c + uri.c ) # Config format diff --git a/tests/internal/uri.c b/tests/internal/uri.c new file mode 100644 index 00000000000..2b533b37bbe --- /dev/null +++ b/tests/internal/uri.c @@ -0,0 +1,87 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Fluent Bit + * ========== + * Copyright (C) 2015-2023 The Fluent Bit Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include "flb_tests_internal.h" + +void uri_create_destroy() +{ + struct flb_uri *uri; + const char *uri_str = "https://fluentbit.io"; + + uri = flb_uri_create(uri_str); + if (!TEST_CHECK(uri != NULL)) { + TEST_MSG("flb_uri_create failed"); + return; + } + + flb_uri_destroy(uri); +} + +void uri_get() +{ + struct flb_uri *uri; + struct flb_uri_field *field; + const char *uri_str = "https://fluentbit.io"; + + uri = flb_uri_create(uri_str); + if (!TEST_CHECK(uri != NULL)) { + TEST_MSG("flb_uri_create failed"); + return; + } + + field = flb_uri_get(uri, 0); + if (!TEST_CHECK(field != NULL)) { + TEST_MSG("flb_uri_get failed"); + return; + } + + field = flb_uri_get(uri, -1); + if (!TEST_CHECK(field == NULL)) { + TEST_MSG("flb_uri_get should fail"); + return; + } + + flb_uri_destroy(uri); +} + +void uri_encode() +{ + flb_sds_t encoded_uri; + const char *input = "&# "; + const char *expect = "%26%23%20"; + + encoded_uri = flb_uri_encode(input, strlen(input)); + if (!TEST_CHECK(encoded_uri != NULL)) { + TEST_MSG("flb_uri_encode failed"); + return; + } + + flb_sds_destroy(encoded_uri); +} + +TEST_LIST = { + { "uri_create_destroy", uri_create_destroy }, + { "uri_get", uri_get }, + { "uri_encode", uri_encode }, + { 0 } +}; From f3c87e2e78e5b6702dcf2e90e99c0a5e5db095e0 Mon Sep 17 00:00:00 2001 From: Takahiro Yamashita Date: Sun, 17 Sep 2023 09:36:03 +0900 Subject: [PATCH 250/315] uri: not allow negative pos Signed-off-by: Takahiro Yamashita --- src/flb_uri.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/flb_uri.c b/src/flb_uri.c index af6d042a92b..48a8b0d8867 100644 --- a/src/flb_uri.c +++ b/src/flb_uri.c @@ -71,6 +71,11 @@ flb_sds_t flb_uri_encode(const char *uri, size_t len) /* Retrieve a given field based on it expected position in the URI */ struct flb_uri_field *flb_uri_get(struct flb_uri *uri, int pos) { + if (pos < 0) { + flb_trace("[uri] negative pos"); + return NULL; + } + if (pos >= FLB_URI_MAX || pos > uri->count) { flb_trace("[uri] requested position > FLB_URI_MAX"); return NULL; From e7c2d4f084b355a1cf1a229fcf52f6c3232ecbfc Mon Sep 17 00:00:00 2001 From: Hiroshi Hatake Date: Wed, 6 Sep 2023 13:55:30 +0900 Subject: [PATCH 251/315] config: reload: Save and increment the count of hot-reloaded times Signed-off-by: Hiroshi Hatake --- include/fluent-bit/flb_config.h | 1 + src/flb_config.c | 1 + src/flb_reload.c | 9 +++++++++ 3 files changed, 11 insertions(+) diff --git a/include/fluent-bit/flb_config.h b/include/fluent-bit/flb_config.h index 4e1912c6459..59bc3a57c8e 100644 --- a/include/fluent-bit/flb_config.h +++ b/include/fluent-bit/flb_config.h @@ -258,6 +258,7 @@ struct flb_config { int enable_hot_reload; int ensure_thread_safety_on_hot_reloading; + unsigned int hot_reloaded_count; /* Co-routines */ unsigned int coro_stack_size; diff --git a/src/flb_config.c b/src/flb_config.c index a0feb73b3f2..5f5289d0186 100644 --- a/src/flb_config.c +++ b/src/flb_config.c @@ -274,6 +274,7 @@ struct flb_config *flb_config_init() /* reload */ config->ensure_thread_safety_on_hot_reloading = FLB_TRUE; + config->hot_reloaded_count = 0; #ifdef FLB_HAVE_SQLDB mk_list_init(&config->sqldb_list); diff --git a/src/flb_reload.c b/src/flb_reload.c index 27c5b7f1520..641fa4a66d0 100644 --- a/src/flb_reload.c +++ b/src/flb_reload.c @@ -367,6 +367,7 @@ int flb_reload(flb_ctx_t *ctx, struct flb_cf *cf_opts) struct flb_cf *new_cf; struct flb_cf *original_cf; int verbose; + int reloaded_count = 0; if (ctx == NULL) { flb_error("[reload] given flb context is NULL"); @@ -425,6 +426,8 @@ int flb_reload(flb_ctx_t *ctx, struct flb_cf *cf_opts) /* Inherit verbose from the old ctx instance */ verbose = ctx->config->verbose; new_config->verbose = verbose; + /* Increment and store the number of hot reloaded times */ + reloaded_count = ctx->config->hot_reloaded_count + 1; #ifdef FLB_HAVE_STREAM_PROCESSOR /* Inherit stream processor definitions from command line */ @@ -504,5 +507,11 @@ int flb_reload(flb_ctx_t *ctx, struct flb_cf *cf_opts) ret = flb_start(new_ctx); + /* Store the new value of hot reloading times into the new context */ + if (ret == 0) { + new_config->hot_reloaded_count = reloaded_count; + flb_debug("[reload] hot reloaded %d time(s)", reloaded_count); + } + return 0; } From 2fea5a36cfc435801f904fdb4941483197c204b9 Mon Sep 17 00:00:00 2001 From: Hiroshi Hatake Date: Wed, 6 Sep 2023 14:22:21 +0900 Subject: [PATCH 252/315] http_server: v2: reload: Provide GET endpoint to retrieve the count of hot-reloaded Signed-off-by: Hiroshi Hatake --- src/http_server/api/v2/reload.c | 63 +++++++++++++++++++++++++++------ 1 file changed, 53 insertions(+), 10 deletions(-) diff --git a/src/http_server/api/v2/reload.c b/src/http_server/api/v2/reload.c index 83626f11ae2..6f3c2a32b09 100644 --- a/src/http_server/api/v2/reload.c +++ b/src/http_server/api/v2/reload.c @@ -33,22 +33,13 @@ #include -static void cb_reload(mk_request_t *request, void *data) +static void handle_reload_request(mk_request_t *request, struct flb_config *config) { int ret; flb_sds_t out_buf; size_t out_size; msgpack_packer mp_pck; msgpack_sbuffer mp_sbuf; - struct flb_hs *hs = data; - struct flb_config *config = hs->config; - - if (request->method != MK_METHOD_POST && - request->method != MK_METHOD_PUT) { - mk_http_status(request, 400); - mk_http_done(request); - return; - } /* initialize buffers */ msgpack_sbuffer_init(&mp_sbuf); @@ -109,6 +100,58 @@ static void cb_reload(mk_request_t *request, void *data) flb_sds_destroy(out_buf); } +static void handle_get_reload_status(mk_request_t *request, struct flb_config *config) +{ + flb_sds_t out_buf; + size_t out_size; + msgpack_packer mp_pck; + msgpack_sbuffer mp_sbuf; + + /* initialize buffers */ + msgpack_sbuffer_init(&mp_sbuf); + msgpack_packer_init(&mp_pck, &mp_sbuf, msgpack_sbuffer_write); + + msgpack_pack_map(&mp_pck, 1); + msgpack_pack_str(&mp_pck, 12); + msgpack_pack_str_body(&mp_pck, "hot_reloaded", 12); + msgpack_pack_int64(&mp_pck, config->hot_reloaded_count); + + /* Export to JSON */ + out_buf = flb_msgpack_raw_to_json_sds(mp_sbuf.data, mp_sbuf.size); + msgpack_sbuffer_destroy(&mp_sbuf); + if (!out_buf) { + mk_http_status(request, 400); + mk_http_done(request); + return; + } + out_size = flb_sds_len(out_buf); + + mk_http_status(request, 200); + flb_hs_add_content_type_to_req(request, FLB_HS_CONTENT_TYPE_JSON); + mk_http_send(request, out_buf, out_size, NULL); + mk_http_done(request); + + flb_sds_destroy(out_buf); +} + +static void cb_reload(mk_request_t *request, void *data) +{ + struct flb_hs *hs = data; + struct flb_config *config = hs->config; + + if (request->method == MK_METHOD_POST || + request->method == MK_METHOD_PUT) { + handle_reload_request(request, config); + } + else if (request->method == MK_METHOD_GET) { + handle_get_reload_status(request, config); + } + else { + mk_http_status(request, 400); + mk_http_done(request); + } +} + /* Perform registration */ int api_v2_reload(struct flb_hs *hs) { From 7e16bf9d74e45850d11285b386ab972949298138 Mon Sep 17 00:00:00 2001 From: Hiroshi Hatake Date: Wed, 6 Sep 2023 16:14:50 +0900 Subject: [PATCH 253/315] metrics: Add hot-reloaded metrics Signed-off-by: Hiroshi Hatake --- src/flb_metrics.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/flb_metrics.c b/src/flb_metrics.c index 6f664cfe602..9a9e9c7e7d8 100644 --- a/src/flb_metrics.c +++ b/src/flb_metrics.c @@ -320,6 +320,25 @@ static int attach_build_info(struct flb_config *ctx, struct cmt *cmt, uint64_t t return 0; } +static int attach_hot_reload_info(struct flb_config *ctx, struct cmt *cmt, uint64_t ts, + char *hostname) +{ + double val; + struct cmt_gauge *g; + + g = cmt_gauge_create(cmt, "fluentbit", "", "hot_reloaded_times", + "Collect the count of hot reloaded times.", + 1, (char *[]) {"hostname"}); + if (!g) { + return -1; + } + + val = (double) ctx->hot_reloaded_count; + + cmt_gauge_set(g, ts, val, 1, (char *[]) {hostname}); + return 0; +} + /* Append internal Fluent Bit metrics to context */ int flb_metrics_fluentbit_add(struct flb_config *ctx, struct cmt *cmt) { @@ -340,6 +359,7 @@ int flb_metrics_fluentbit_add(struct flb_config *ctx, struct cmt *cmt) attach_uptime(ctx, cmt, ts, hostname); attach_process_start_time_seconds(ctx, cmt, ts, hostname); attach_build_info(ctx, cmt, ts, hostname); + attach_hot_reload_info(ctx, cmt, ts, hostname); return 0; } From eba37f0e67f718509b8fc253c438a4900fea4b33 Mon Sep 17 00:00:00 2001 From: Hiroshi Hatake Date: Wed, 6 Sep 2023 17:23:45 +0900 Subject: [PATCH 254/315] http_server: v2: reload: Use more concrate key for storing reloaded times Signed-off-by: Hiroshi Hatake --- src/http_server/api/v2/reload.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/http_server/api/v2/reload.c b/src/http_server/api/v2/reload.c index 6f3c2a32b09..3bb5159fa57 100644 --- a/src/http_server/api/v2/reload.c +++ b/src/http_server/api/v2/reload.c @@ -112,8 +112,8 @@ static void handle_get_reload_status(mk_request_t *request, struct flb_config *c msgpack_packer_init(&mp_pck, &mp_sbuf, msgpack_sbuffer_write); msgpack_pack_map(&mp_pck, 1); - msgpack_pack_str(&mp_pck, 12); - msgpack_pack_str_body(&mp_pck, "hot_reloaded", 12); + msgpack_pack_str(&mp_pck, 16); + msgpack_pack_str_body(&mp_pck, "hot_reload_count", 16); msgpack_pack_int64(&mp_pck, config->hot_reloaded_count); /* Export to JSON */ From 109332d7aaf1df21195039fd41bbf23f5667d5f6 Mon Sep 17 00:00:00 2001 From: Phillip Whelan Date: Wed, 13 Sep 2023 07:43:14 -0700 Subject: [PATCH 255/315] fluent-bit: use console ctrl handlers in win32 to simulate SIGHUP. Signed-off-by: Phillip Whelan --- src/fluent-bit.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/src/fluent-bit.c b/src/fluent-bit.c index 774001f985a..d74f4e37e74 100644 --- a/src/fluent-bit.c +++ b/src/fluent-bit.c @@ -616,6 +616,40 @@ static void flb_signal_handler(int signal) } } +#ifdef FLB_SYSTEM_WINDOWS +#include + +static flb_ctx_t *handler_ctx = NULL; +static struct flb_cf *handler_opts = NULL; +static int handler_signal = 0; + +void flb_console_handler_set_ctx(flb_ctx_t *ctx, struct flb_cf *cf_opts) +{ + handler_ctx = ctx; + handler_opts = cf_opts; +} + +static bool flb_console_handler(DWORD evType) +{ + switch(evType) { + case 1 /* CTRL_BREAK_EVENT_1 */: + if (flb_bin_restarting == FLB_RELOAD_IDLE) { + flb_bin_restarting = FLB_RELOAD_IN_PROGRESS; + /* signal the main loop to execute reload. this is necessary since + * all signal handlers in win32 are executed on their own thread. + */ + handler_signal = 1; + flb_bin_restarting = FLB_RELOAD_IDLE; + } + else { + flb_utils_error(FLB_ERR_RELOADING_IN_PROGRESS); + } + break; + } + return 1; +} +#endif + static void flb_signal_init() { signal(SIGINT, &flb_signal_handler_break_loop); @@ -623,6 +657,9 @@ static void flb_signal_init() signal(SIGQUIT, &flb_signal_handler_break_loop); signal(SIGHUP, &flb_signal_handler); signal(SIGCONT, &flb_signal_handler); +#else + /* Use SetConsoleCtrlHandler on windows to simulate SIGHUP */ + SetConsoleCtrlHandler(flb_console_handler, 1); #endif signal(SIGTERM, &flb_signal_handler_break_loop); signal(SIGSEGV, &flb_signal_handler); @@ -995,6 +1032,10 @@ int flb_main(int argc, char **argv) cf = config->cf_main; service = cf_opts->service; +#ifdef FLB_SYSTEM_WINDOWS + flb_console_handler_set_ctx(ctx, cf_opts); +#endif + /* Add reference for cf_opts */ config->cf_opts = cf_opts; @@ -1315,8 +1356,19 @@ int flb_main(int argc, char **argv) while (ctx->status == FLB_LIB_OK && exit_signal == 0) { sleep(1); +#ifdef FLB_SYSTEM_WINDOWS + if (handler_signal == 1) { + handler_signal = 0; + flb_reload(ctx, cf_opts); + } +#endif + /* set the context again before checking the status again */ ctx = flb_context_get(); + +#ifdef FLB_SYSTEM_WINDOWS + flb_console_handler_set_ctx(ctx, cf_opts); +#endif } if (exit_signal) { From a83400769113f4fae6c1197eaf02f8bbfe00c926 Mon Sep 17 00:00:00 2001 From: Phillip Whelan Date: Wed, 13 Sep 2023 07:43:48 -0700 Subject: [PATCH 256/315] in_calyptia_fleet: reenable fleet on windows. Signed-off-by: Phillip Whelan --- cmake/windows-setup.cmake | 2 -- 1 file changed, 2 deletions(-) diff --git a/cmake/windows-setup.cmake b/cmake/windows-setup.cmake index dbd7f4a4a2d..fa67cb0d872 100644 --- a/cmake/windows-setup.cmake +++ b/cmake/windows-setup.cmake @@ -60,8 +60,6 @@ if(FLB_WINDOWS_DEFAULTS) set(FLB_IN_EMITTER Yes) set(FLB_IN_PODMAN_METRICS No) set(FLB_IN_ELASTICSEARCH Yes) - # disable calyptia fleet management for now - set(FLB_IN_CALYPTIA_FLEET No) set(FLB_IN_SPLUNK Yes) # OUTPUT plugins From 931d2bb41dd234091bc615cfb981a76cc241e929 Mon Sep 17 00:00:00 2001 From: Phillip Whelan Date: Wed, 13 Sep 2023 07:44:45 -0700 Subject: [PATCH 257/315] in_calyptia_fleet: use GenerateConsoleCtrlEvent on win32 to execute reload. Signed-off-by: Phillip Whelan --- plugins/in_calyptia_fleet/in_calyptia_fleet.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/plugins/in_calyptia_fleet/in_calyptia_fleet.c b/plugins/in_calyptia_fleet/in_calyptia_fleet.c index bb8dfb99992..7e0a81e4c03 100644 --- a/plugins/in_calyptia_fleet/in_calyptia_fleet.c +++ b/plugins/in_calyptia_fleet/in_calyptia_fleet.c @@ -348,8 +348,11 @@ static void *do_reload(void *data) reload->flb->config->conf_path_file = reload->cfg_path; sleep(5); +#ifndef FLB_SYSTEM_WINDOWS kill(getpid(), SIGHUP); - +#else + GenerateConsoleCtrlEvent(1 /* CTRL_BREAK_EVENT_1 */, 0); +#endif return NULL; } From 046ed56f2b2532f15056c0f6ce4a95157f6f47cd Mon Sep 17 00:00:00 2001 From: Phillip Whelan Date: Wed, 13 Sep 2023 07:47:34 -0700 Subject: [PATCH 258/315] in_calyptia_fleet: add support for creating configuration files for win32. Signed-off-by: Phillip Whelan --- plugins/in_calyptia_fleet/in_calyptia_fleet.c | 35 +++++++++++++++---- 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/plugins/in_calyptia_fleet/in_calyptia_fleet.c b/plugins/in_calyptia_fleet/in_calyptia_fleet.c index 7e0a81e4c03..3e2df36fff0 100644 --- a/plugins/in_calyptia_fleet/in_calyptia_fleet.c +++ b/plugins/in_calyptia_fleet/in_calyptia_fleet.c @@ -693,6 +693,10 @@ static int get_calyptia_fleet_id_by_name(struct flb_in_calyptia_fleet_config *ct return 0; } +#ifdef FLB_SYSTEM_WINDOWS +#define link(a, b) CreateHardLinkA(b, a, 0) +#endif + /* cb_collect callback */ static int in_calyptia_fleet_collect(struct flb_input_instance *ins, struct flb_config *config, @@ -715,6 +719,10 @@ static int in_calyptia_fleet_collect(struct flb_input_instance *ins, char *data; size_t b_sent; int ret = -1; +#ifdef FLB_SYSTEM_WINDOWS + DWORD err; + LPSTR lpMsg; +#endif u_conn = flb_upstream_conn_get(ctx->u); @@ -868,7 +876,16 @@ static int in_calyptia_fleet_collect(struct flb_input_instance *ins, flb_sds_destroy(cfgoldname); } - symlink(cfgname, cfgnewname); + if (!link(cfgname, cfgnewname)) { +#ifdef FLB_SYSTEM_WINDOWS + err = GetLastError(); + FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, + NULL, err, 0, &lpMsg, 0, NULL); + flb_plg_error(ctx->ins, "unable to create hard link: %s", lpMsg); +#else + flb_errno(); +#endif + } } if (ctx->config_timestamp < time_last_modified) { @@ -901,12 +918,18 @@ static int in_calyptia_fleet_collect(struct flb_input_instance *ins, FLB_INPUT_RETURN(ret); } +#ifdef FLB_SYSTEM_WINDOWS +#define _mkdir(a, b) mkdir(a) +#else +#define _mkdir(a, b) mkdir(a, b) +#endif + /* recursively create directories, based on: * https://stackoverflow.com/a/2336245 * who found it at: * http://nion.modprobe.de/blog/archives/357-Recursive-directory-creation.html */ -static int _mkdir(const char *dir, int perms) { +static int __mkdir(const char *dir, int perms) { char tmp[255]; char *ptr = NULL; size_t len; @@ -926,7 +949,7 @@ static int _mkdir(const char *dir, int perms) { if (*ptr == '/') { *ptr = 0; if (access(tmp, F_OK) != 0) { - ret = mkdir(tmp, perms); + ret = _mkdir(tmp, perms); if (ret != 0) { return ret; } @@ -934,7 +957,7 @@ static int _mkdir(const char *dir, int perms) { *ptr = '/'; } } - return mkdir(tmp, perms); + return _mkdir(tmp, perms); } static int create_fleet_directory(struct flb_in_calyptia_fleet_config *ctx) @@ -942,7 +965,7 @@ static int create_fleet_directory(struct flb_in_calyptia_fleet_config *ctx) flb_sds_t myfleetdir; if (access(ctx->config_dir, F_OK) != 0) { - if (_mkdir(ctx->config_dir, 0700) != 0) { + if (__mkdir(ctx->config_dir, 0700) != 0) { return -1; } } @@ -959,7 +982,7 @@ static int create_fleet_directory(struct flb_in_calyptia_fleet_config *ctx) } if (access(myfleetdir, F_OK) != 0) { - if (_mkdir(myfleetdir, 0700) !=0) { + if (__mkdir(myfleetdir, 0700) !=0) { return -1; } } From b84459be0245a688fd6713f53c998bec6b5d97f6 Mon Sep 17 00:00:00 2001 From: Phillip Whelan Date: Fri, 15 Sep 2023 12:50:02 -0300 Subject: [PATCH 259/315] fluent-bit: fix indentation. Signed-off-by: Phillip Whelan --- src/fluent-bit.c | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/src/fluent-bit.c b/src/fluent-bit.c index d74f4e37e74..c2d0a2a560d 100644 --- a/src/fluent-bit.c +++ b/src/fluent-bit.c @@ -632,9 +632,9 @@ void flb_console_handler_set_ctx(flb_ctx_t *ctx, struct flb_cf *cf_opts) static bool flb_console_handler(DWORD evType) { switch(evType) { - case 1 /* CTRL_BREAK_EVENT_1 */: - if (flb_bin_restarting == FLB_RELOAD_IDLE) { - flb_bin_restarting = FLB_RELOAD_IN_PROGRESS; + case 1 /* CTRL_BREAK_EVENT_1 */: + if (flb_bin_restarting == FLB_RELOAD_IDLE) { + flb_bin_restarting = FLB_RELOAD_IN_PROGRESS; /* signal the main loop to execute reload. this is necessary since * all signal handlers in win32 are executed on their own thread. */ @@ -645,7 +645,7 @@ static bool flb_console_handler(DWORD evType) flb_utils_error(FLB_ERR_RELOADING_IN_PROGRESS); } break; - } + } return 1; } #endif @@ -658,8 +658,8 @@ static void flb_signal_init() signal(SIGHUP, &flb_signal_handler); signal(SIGCONT, &flb_signal_handler); #else - /* Use SetConsoleCtrlHandler on windows to simulate SIGHUP */ - SetConsoleCtrlHandler(flb_console_handler, 1); + /* Use SetConsoleCtrlHandler on windows to simulate SIGHUP */ + SetConsoleCtrlHandler(flb_console_handler, 1); #endif signal(SIGTERM, &flb_signal_handler_break_loop); signal(SIGSEGV, &flb_signal_handler); @@ -873,12 +873,15 @@ static int parse_trace_pipeline(flb_ctx_t *ctx, const char *pipeline, char **tra } mk_list_foreach(cur, parts) { - key = NULL; - value = NULL; + key = NULL; + value = NULL; + part = mk_list_entry(cur, struct flb_split_entry, _head); + if (parse_trace_pipeline_prop(ctx, part->value, &key, &value) == FLB_ERROR) { return FLB_ERROR; } + if (strcmp(key, "input") == 0) { if (*trace_input != NULL) { flb_free(*trace_input); @@ -911,12 +914,14 @@ static int parse_trace_pipeline(flb_ctx_t *ctx, const char *pipeline, char **tra (char *)propname, strlen(propname), (char *)propval, strlen(propval)); } - if (key != NULL) { - mk_mem_free(key); - } - if (value != NULL) { - flb_free(value); - } + + if (key != NULL) { + mk_mem_free(key); + } + + if (value != NULL) { + flb_free(value); + } } flb_utils_split_free(parts); From 4b06006ee64790c6287092df9b5b6182b500d420 Mon Sep 17 00:00:00 2001 From: Phillip Whelan Date: Fri, 15 Sep 2023 14:06:14 -0300 Subject: [PATCH 260/315] fluent-bit: follow PHANDLER_ROUTINE definition more closely. Signed-off-by: Phillip Whelan --- src/fluent-bit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fluent-bit.c b/src/fluent-bit.c index c2d0a2a560d..51b814cfd02 100644 --- a/src/fluent-bit.c +++ b/src/fluent-bit.c @@ -629,7 +629,7 @@ void flb_console_handler_set_ctx(flb_ctx_t *ctx, struct flb_cf *cf_opts) handler_opts = cf_opts; } -static bool flb_console_handler(DWORD evType) +static BOOL WINAPI flb_console_handler(DWORD evType) { switch(evType) { case 1 /* CTRL_BREAK_EVENT_1 */: From de2f8f2a8d1686dc4aab9eeb389d76e32fb9934f Mon Sep 17 00:00:00 2001 From: Phillip Whelan Date: Wed, 20 Sep 2023 07:48:13 -0700 Subject: [PATCH 261/315] in_calyptia_fleet: add readlink equivalent for windows. Signed-off-by: Phillip Whelan --- plugins/in_calyptia_fleet/in_calyptia_fleet.c | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/plugins/in_calyptia_fleet/in_calyptia_fleet.c b/plugins/in_calyptia_fleet/in_calyptia_fleet.c index 3e2df36fff0..3175b5645c1 100644 --- a/plugins/in_calyptia_fleet/in_calyptia_fleet.c +++ b/plugins/in_calyptia_fleet/in_calyptia_fleet.c @@ -695,6 +695,29 @@ static int get_calyptia_fleet_id_by_name(struct flb_in_calyptia_fleet_config *ct #ifdef FLB_SYSTEM_WINDOWS #define link(a, b) CreateHardLinkA(b, a, 0) + +ssize_t readlink(const char *path, char *realpath, size_t srealpath) { + HANDLE hFile; + DWORD ret; + + hFile = CreateFile(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL); + + if (hFile == INVALID_HANDLE_VALUE) { + return -1; + } + + ret = GetFinalPathNameByHandleA(hFile, realpath, srealpath, VOLUME_NAME_NT); + + if (ret < srealpath) { + CloseHandle(hFile); + return -1; + } + + CloseHandle(hFile); + return ret; +} + #endif /* cb_collect callback */ From 2413610114e8cc1c5dc10523e5769f28450ceebb Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Thu, 21 Sep 2023 08:28:47 -0600 Subject: [PATCH 262/315] lib: chunkio: upgrade to v1.5.0 Signed-off-by: Eduardo Silva --- lib/chunkio/CMakeLists.txt | 23 ++- .../cmake/sanitizers-cmake/CMakeLists.txt | 2 +- lib/chunkio/cmake/sanitizers-cmake/README.md | 2 +- .../sanitizers-cmake/cmake/FindASan.cmake | 3 + .../sanitizers-cmake/cmake/FindMSan.cmake | 3 + .../cmake/FindSanitizers.cmake | 21 +-- .../sanitizers-cmake/cmake/FindTSan.cmake | 3 + .../sanitizers-cmake/cmake/FindUBSan.cmake | 3 + .../cmake/sanitize-helpers.cmake | 22 ++- lib/chunkio/include/chunkio/chunkio.h | 25 ++- lib/chunkio/include/chunkio/cio_file.h | 1 + lib/chunkio/include/chunkio/cio_file_st.h | 83 +++++++-- lib/chunkio/src/chunkio.c | 82 +++++++-- lib/chunkio/src/cio_file.c | 163 +++++++++++++----- lib/chunkio/src/cio_file_unix.c | 70 +++++--- lib/chunkio/src/cio_memfs.c | 6 +- lib/chunkio/tests/CMakeLists.txt | 21 +++ lib/chunkio/tests/context.c | 30 +++- lib/chunkio/tests/fs.c | 141 +++++++++++++-- lib/chunkio/tests/memfs.c | 5 +- lib/chunkio/tests/stream.c | 2 +- lib/chunkio/tools/cio.c | 2 +- 22 files changed, 569 insertions(+), 144 deletions(-) mode change 100644 => 100755 lib/chunkio/cmake/sanitizers-cmake/cmake/FindSanitizers.cmake mode change 100644 => 100755 lib/chunkio/cmake/sanitizers-cmake/cmake/sanitize-helpers.cmake diff --git a/lib/chunkio/CMakeLists.txt b/lib/chunkio/CMakeLists.txt index 8bfe5199d19..f49d01d9095 100644 --- a/lib/chunkio/CMakeLists.txt +++ b/lib/chunkio/CMakeLists.txt @@ -2,8 +2,8 @@ cmake_minimum_required(VERSION 3.0) project(chunk-io C) set(CIO_VERSION_MAJOR 1) -set(CIO_VERSION_MINOR 4) -set(CIO_VERSION_PATCH 0) +set(CIO_VERSION_MINOR 5) +set(CIO_VERSION_PATCH 1) set(CIO_VERSION_STR "${CIO_VERSION_MAJOR}.${CIO_VERSION_MINOR}.${CIO_VERSION_PATCH}") # CFLAGS @@ -15,11 +15,7 @@ else() endif() # Set __FILENAME__ -if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Windows") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D__FILENAME__='\"$(subst ${CMAKE_SOURCE_DIR}/,,$(abspath $<))\"'") -else() - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D__FILENAME__=__FILE__") -endif() +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D__FILENAME__=__FILE__") include(cmake/macros.cmake) @@ -91,6 +87,18 @@ if(CIO_HAVE_FALLOCATE) CIO_DEFINITION(CIO_HAVE_FALLOCATE) endif() +# posix_fallocate(2) support +check_c_source_compiles(" + #include + int main() { + posix_fallocate(0,0,0); + return 0; + }" CIO_HAVE_POSIX_FALLOCATE) + +if(CIO_HAVE_POSIX_FALLOCATE) + CIO_DEFINITION(CIO_HAVE_POSIX_FALLOCATE) +endif() + configure_file( "${PROJECT_SOURCE_DIR}/include/chunkio/cio_info.h.in" "${PROJECT_BINARY_DIR}/include/chunkio/cio_info.h" @@ -105,6 +113,7 @@ include_directories( include deps/ deps/monkey/include + ${PROJECT_BINARY_DIR}/include/ ) add_subdirectory(deps/crc32) diff --git a/lib/chunkio/cmake/sanitizers-cmake/CMakeLists.txt b/lib/chunkio/cmake/sanitizers-cmake/CMakeLists.txt index d249a4db5cc..a1928525587 100644 --- a/lib/chunkio/cmake/sanitizers-cmake/CMakeLists.txt +++ b/lib/chunkio/cmake/sanitizers-cmake/CMakeLists.txt @@ -30,7 +30,7 @@ # # minimum required cmake version -cmake_minimum_required(VERSION 2.8) +cmake_minimum_required(VERSION 2.8.12) # project name project("CMake-sanitizers") diff --git a/lib/chunkio/cmake/sanitizers-cmake/README.md b/lib/chunkio/cmake/sanitizers-cmake/README.md index 8df8d175c21..b4ca621c31e 100644 --- a/lib/chunkio/cmake/sanitizers-cmake/README.md +++ b/lib/chunkio/cmake/sanitizers-cmake/README.md @@ -11,7 +11,7 @@ CMake module to enable sanitizers for binary targets. To use [FindSanitizers.cmake](cmake/FindSanitizers.cmake), simply add this repository as git submodule into your own repository ```Shell mkdir externals -git submodule add git://github.com/arsenm/sanitizers-cmake.git externals/sanitizers-cmake +git submodule add git@github.com:arsenm/sanitizers-cmake.git externals/sanitizers-cmake ``` and adding ```externals/sanitizers-cmake/cmake``` to your ```CMAKE_MODULE_PATH``` ```CMake diff --git a/lib/chunkio/cmake/sanitizers-cmake/cmake/FindASan.cmake b/lib/chunkio/cmake/sanitizers-cmake/cmake/FindASan.cmake index 98ea7cb311c..4548e46a887 100644 --- a/lib/chunkio/cmake/sanitizers-cmake/cmake/FindASan.cmake +++ b/lib/chunkio/cmake/sanitizers-cmake/cmake/FindASan.cmake @@ -25,6 +25,9 @@ option(SANITIZE_ADDRESS "Enable AddressSanitizer for sanitized targets." Off) set(FLAG_CANDIDATES + # MSVC uses + "/fsanitize=address" + # Clang 3.2+ use this version. The no-omit-frame-pointer option is optional. "-g -fsanitize=address -fno-omit-frame-pointer" "-g -fsanitize=address" diff --git a/lib/chunkio/cmake/sanitizers-cmake/cmake/FindMSan.cmake b/lib/chunkio/cmake/sanitizers-cmake/cmake/FindMSan.cmake index 22d0050e97c..d744c34be81 100644 --- a/lib/chunkio/cmake/sanitizers-cmake/cmake/FindMSan.cmake +++ b/lib/chunkio/cmake/sanitizers-cmake/cmake/FindMSan.cmake @@ -25,6 +25,9 @@ option(SANITIZE_MEMORY "Enable MemorySanitizer for sanitized targets." Off) set(FLAG_CANDIDATES + # MSVC uses + "/fsanitize=memory" + # GNU/Clang "-g -fsanitize=memory" ) diff --git a/lib/chunkio/cmake/sanitizers-cmake/cmake/FindSanitizers.cmake b/lib/chunkio/cmake/sanitizers-cmake/cmake/FindSanitizers.cmake old mode 100644 new mode 100755 index a11809b0bb4..d9b438c0f6c --- a/lib/chunkio/cmake/sanitizers-cmake/cmake/FindSanitizers.cmake +++ b/lib/chunkio/cmake/sanitizers-cmake/cmake/FindSanitizers.cmake @@ -26,8 +26,8 @@ # link against the sanitizers. option(SANITIZE_LINK_STATIC "Try to link static against sanitizers." Off) - - +# Highlight this module has been loaded. +set(Sanitizers_FOUND TRUE) set(FIND_QUIETLY_FLAG "") if (DEFINED Sanitizers_FIND_QUIETLY) @@ -39,9 +39,6 @@ find_package(TSan ${FIND_QUIETLY_FLAG}) find_package(MSan ${FIND_QUIETLY_FLAG}) find_package(UBSan ${FIND_QUIETLY_FLAG}) - - - function(sanitizer_add_blacklist_file FILE) if(NOT IS_ABSOLUTE ${FILE}) set(FILE "${CMAKE_CURRENT_SOURCE_DIR}/${FILE}") @@ -52,7 +49,7 @@ function(sanitizer_add_blacklist_file FILE) "SanitizerBlacklist" "SanBlist") endfunction() -function(add_sanitizers ...) +function(add_sanitizers) # If no sanitizer is enabled, return immediately. if (NOT (SANITIZE_ADDRESS OR SANITIZE_MEMORY OR SANITIZE_THREAD OR SANITIZE_UNDEFINED)) @@ -77,12 +74,12 @@ function(add_sanitizers ...) "Target will be compiled without sanitizers.") return() - # If the target is compiled by no known compiler, ignore it. elseif (NUM_COMPILERS EQUAL 0) - message(WARNING "Can't use any sanitizers for target ${TARGET}, " - "because it uses an unknown compiler. Target will be " - "compiled without sanitizers.") - return() + # If the target is compiled by no known compiler, give a warning. + message(WARNING "Sanitizers for target ${TARGET} may not be" + " usable, because it uses no or an unknown compiler. " + "This is a false warning for targets using only " + "object lib(s) as input.") endif () # Add sanitizers for target. @@ -90,5 +87,5 @@ function(add_sanitizers ...) add_sanitize_thread(${TARGET}) add_sanitize_memory(${TARGET}) add_sanitize_undefined(${TARGET}) - endforeach () + endforeach () endfunction(add_sanitizers) diff --git a/lib/chunkio/cmake/sanitizers-cmake/cmake/FindTSan.cmake b/lib/chunkio/cmake/sanitizers-cmake/cmake/FindTSan.cmake index 3cba3c03b6b..efb2e9525b8 100644 --- a/lib/chunkio/cmake/sanitizers-cmake/cmake/FindTSan.cmake +++ b/lib/chunkio/cmake/sanitizers-cmake/cmake/FindTSan.cmake @@ -25,6 +25,9 @@ option(SANITIZE_THREAD "Enable ThreadSanitizer for sanitized targets." Off) set(FLAG_CANDIDATES + # MSVC uses + "/fsanitize=thread" + # GNU/Clang "-g -fsanitize=thread" ) diff --git a/lib/chunkio/cmake/sanitizers-cmake/cmake/FindUBSan.cmake b/lib/chunkio/cmake/sanitizers-cmake/cmake/FindUBSan.cmake index ae103f71725..4354c2e4d63 100644 --- a/lib/chunkio/cmake/sanitizers-cmake/cmake/FindUBSan.cmake +++ b/lib/chunkio/cmake/sanitizers-cmake/cmake/FindUBSan.cmake @@ -26,6 +26,9 @@ option(SANITIZE_UNDEFINED "Enable UndefinedBehaviorSanitizer for sanitized targets." Off) set(FLAG_CANDIDATES + # MSVC uses + "/fsanitize=undefined" + # GNU/Clang "-g -fsanitize=undefined" ) diff --git a/lib/chunkio/cmake/sanitizers-cmake/cmake/sanitize-helpers.cmake b/lib/chunkio/cmake/sanitizers-cmake/cmake/sanitize-helpers.cmake old mode 100644 new mode 100755 index 610f8957420..efc325ce309 --- a/lib/chunkio/cmake/sanitizers-cmake/cmake/sanitize-helpers.cmake +++ b/lib/chunkio/cmake/sanitizers-cmake/cmake/sanitize-helpers.cmake @@ -25,6 +25,11 @@ # Helper function to get the language of a source file. function (sanitizer_lang_of_source FILE RETURN_VAR) get_filename_component(LONGEST_EXT "${FILE}" EXT) + # If extension is empty return. This can happen for extensionless headers + if("${LONGEST_EXT}" STREQUAL "") + set(${RETURN_VAR} "" PARENT_SCOPE) + return() + endif() # Get shortest extension as some files can have dot in their names string(REGEX REPLACE "^.*(\\.[^.]+)$" "\\1" FILE_EXT ${LONGEST_EXT}) string(TOLOWER "${FILE_EXT}" FILE_EXT) @@ -70,6 +75,7 @@ endfunction () # Helper function to check compiler flags for language compiler. function (sanitizer_check_compiler_flag FLAG LANG VARIABLE) + if (${LANG} STREQUAL "C") include(CheckCCompilerFlag) check_c_compiler_flag("${FLAG}" ${VARIABLE}) @@ -92,6 +98,7 @@ function (sanitizer_check_compiler_flag FLAG LANG VARIABLE) " - Failed (Check not supported)") endif () endif() + endfunction () @@ -105,7 +112,7 @@ function (sanitizer_check_compiler_flags FLAG_CANDIDATES NAME PREFIX) # So instead of searching flags foreach language, search flags foreach # compiler used. set(COMPILER ${CMAKE_${LANG}_COMPILER_ID}) - if (NOT DEFINED ${PREFIX}_${COMPILER}_FLAGS) + if (COMPILER AND NOT DEFINED ${PREFIX}_${COMPILER}_FLAGS) foreach (FLAG ${FLAG_CANDIDATES}) if(NOT CMAKE_REQUIRED_QUIET) message(STATUS "Try ${COMPILER} ${NAME} flag = [${FLAG}]") @@ -162,11 +169,10 @@ function (sanitizer_add_flags TARGET NAME PREFIX) return() endif() - # Set compile- and link-flags for target. - set_property(TARGET ${TARGET} APPEND_STRING - PROPERTY COMPILE_FLAGS " ${${PREFIX}_${TARGET_COMPILER}_FLAGS}") - set_property(TARGET ${TARGET} APPEND_STRING - PROPERTY COMPILE_FLAGS " ${SanBlist_${TARGET_COMPILER}_FLAGS}") - set_property(TARGET ${TARGET} APPEND_STRING - PROPERTY LINK_FLAGS " ${${PREFIX}_${TARGET_COMPILER}_FLAGS}") + separate_arguments(flags_list UNIX_COMMAND "${${PREFIX}_${TARGET_COMPILER}_FLAGS} ${SanBlist_${TARGET_COMPILER}_FLAGS}") + target_compile_options(${TARGET} PUBLIC ${flags_list}) + + separate_arguments(flags_list UNIX_COMMAND "${${PREFIX}_${TARGET_COMPILER}_FLAGS}") + target_link_options(${TARGET} PUBLIC ${flags_list}) + endfunction () diff --git a/lib/chunkio/include/chunkio/chunkio.h b/lib/chunkio/include/chunkio/chunkio.h index 6dff9edb08d..c60ddacce1d 100644 --- a/lib/chunkio/include/chunkio/chunkio.h +++ b/lib/chunkio/include/chunkio/chunkio.h @@ -44,6 +44,7 @@ #define CIO_CHECKSUM 4 /* enable checksum verification (crc32) */ #define CIO_FULL_SYNC 8 /* force sync to fs through MAP_SYNC */ #define CIO_DELETE_IRRECOVERABLE 16 /* delete irrecoverable chunks from disk */ +#define CIO_TRIM_FILES 32 /* trim files to their required size */ /* Return status */ #define CIO_CORRUPTED -3 /* Indicate that a chunk is corrupted */ @@ -51,13 +52,25 @@ #define CIO_ERROR -1 /* Generic error */ #define CIO_OK 0 /* OK */ +/* Configuration limits */ +/* The file minimum growth factor is 8 memory pages and + * the file maximum growth factor is 8 megabytes + */ +#define CIO_REALLOC_HINT_MIN (cio_getpagesize() * 8) +#define CIO_REALLOC_HINT_MAX (8 * 1000 * 1000) /* defaults */ -#define CIO_MAX_CHUNKS_UP 64 /* default limit for cio_ctx->max_chunks_up */ +#define CIO_MAX_CHUNKS_UP 64 /* default limit for cio_ctx->max_chunks_up */ +#define CIO_DISABLE_REALLOC_HINT -1 /* default value of size of realloc hint */ +#define CIO_DEFAULT_REALLOC_HINT CIO_REALLOC_HINT_MIN +#define CIO_INITIALIZED 1337 struct cio_ctx; struct cio_options { + /* this bool flag sets if the options has been initialized, that's a mandatory step */ + int initialized; + int flags; char *root_path; @@ -68,10 +81,14 @@ struct cio_options { char *user; char *group; char *chmod; + + /* chunk handlings */ + int realloc_size_hint; }; struct cio_ctx { int page_size; + int realloc_size_hint; struct cio_options options; void *processed_user; @@ -104,7 +121,7 @@ struct cio_ctx { #include #include - +void cio_options_init(struct cio_options *options); struct cio_ctx *cio_create(struct cio_options *options); void cio_destroy(struct cio_ctx *ctx); int cio_load(struct cio_ctx *ctx, char *chunk_extension); @@ -113,6 +130,10 @@ int cio_qsort(struct cio_ctx *ctx, int (*compar)(const void *, const void *)); void cio_set_log_callback(struct cio_ctx *ctx, void (*log_cb)); int cio_set_log_level(struct cio_ctx *ctx, int level); int cio_set_max_chunks_up(struct cio_ctx *ctx, int n); +int cio_set_realloc_size_hint(struct cio_ctx *ctx, size_t realloc_size_hint); + +void cio_enable_file_trimming(struct cio_ctx *ctx); +void cio_disable_file_trimming(struct cio_ctx *ctx); int cio_meta_write(struct cio_chunk *ch, char *buf, size_t size); int cio_meta_cmp(struct cio_chunk *ch, char *meta_buf, int meta_len); diff --git a/lib/chunkio/include/chunkio/cio_file.h b/lib/chunkio/include/chunkio/cio_file.h index d75b14c3a30..7d447492902 100644 --- a/lib/chunkio/include/chunkio/cio_file.h +++ b/lib/chunkio/include/chunkio/cio_file.h @@ -35,6 +35,7 @@ struct cio_file { int allocate_strategy; /* linux-only: fallocate strategy */ size_t fs_size; /* original size in the file system */ size_t data_size; /* number of bytes used */ + size_t page_size; /* curent page size */ size_t alloc_size; /* allocated size */ size_t realloc_size; /* chunk size to increase alloc */ char *path; /* root path + stream */ diff --git a/lib/chunkio/include/chunkio/cio_file_st.h b/lib/chunkio/include/chunkio/cio_file_st.h index a6b4f46cd60..4b1552b612a 100644 --- a/lib/chunkio/include/chunkio/cio_file_st.h +++ b/lib/chunkio/include/chunkio/cio_file_st.h @@ -36,7 +36,10 @@ * +--------------+----------------+ * | 0xC1 | 0x00 +--> Header 2 bytes * +--------------+----------------+ - * | 4 BYTES CRC32 + 16 BYTES +--> CRC32(Content) + Padding + * | 4 BYTES +--> CRC32(Content) + * | 4 BYTES +--> CRC32(Padding) + * | 4 BYTES +--> Content length + * | 8 BYTES +--> Padding * +-------------------------------+ * | Content | * | +-------------------------+ | @@ -55,11 +58,14 @@ * +-------------------------------+ */ -#define CIO_FILE_ID_00 0xc1 /* header: first byte */ -#define CIO_FILE_ID_01 0x00 /* header: second byte */ -#define CIO_FILE_HEADER_MIN 24 /* 24 bytes for the header */ -#define CIO_FILE_CONTENT_OFFSET 22 - +#define CIO_FILE_ID_00 0xc1 /* header: first byte */ +#define CIO_FILE_ID_01 0x00 /* header: second byte */ +#define CIO_FILE_HEADER_MIN 24 /* 24 bytes for the header */ +#define CIO_FILE_CONTENT_OFFSET 22 +#define CIO_FILE_CONTENT_LENGTH_OFFSET 10 /* We store the content length + * right after the checksum in + * what used to be padding + */ /* Return pointer to hash position */ static inline char *cio_file_st_get_hash(char *map) { @@ -94,22 +100,71 @@ static inline char *cio_file_st_get_content(char *map) return map + CIO_FILE_HEADER_MIN + len; } -static inline ssize_t cio_file_st_get_content_size(char *map, size_t size) +/* Infer content length when not available */ +static inline ssize_t cio_file_st_infer_content_len(char *map, size_t size) +{ + size_t content_length; + + content_length = size; + content_length -= CIO_FILE_HEADER_MIN; + content_length -= cio_file_st_get_meta_len(map); + + return content_length; +} + +/* Get content length */ +static inline ssize_t cio_file_st_get_content_len(char *map, size_t size, + size_t page_size) { - int meta_len; - size_t s; + uint8_t *content_length_buffer; + ssize_t content_length; if (size < CIO_FILE_HEADER_MIN) { return -1; } - meta_len = cio_file_st_get_meta_len(map); - s = (size - CIO_FILE_HEADER_MIN) - meta_len; - if (s < size) { - return s; + content_length_buffer = (uint8_t *) &map[CIO_FILE_CONTENT_LENGTH_OFFSET]; + + content_length = (ssize_t) (((uint32_t) content_length_buffer[0]) << 24) | + (((uint32_t) content_length_buffer[1]) << 16) | + (((uint32_t) content_length_buffer[2]) << 8) | + (((uint32_t) content_length_buffer[3]) << 0); + + /* This is required in order to be able to load chunk files generated by + * previous versions of chunkio that didn't include the content length + * as part of the headers. + * + * The reason why we need to ensure that the file size is larger than 4096 + * is that this is the minimal expected page size which is the unit used + * to initialize chunk files when they are created. + * + * In doing so, we effectively avoid returning bogus results when loading + * newly created, non trimmed files while at the same time retaining the + * capability of loading legacy files (that don't have a content size) + * that are larger than 4096 bytes. + * + * The only caveat is that trimmed files + */ + if (content_length == 0 && + size > 0 && + size != page_size) { + content_length = cio_file_st_infer_content_len(map, size); } - return -1; + return content_length; +} + +/* Set content length */ +static inline void cio_file_st_set_content_len(char *map, uint32_t len) +{ + uint8_t *content_length_buffer; + + content_length_buffer = (uint8_t *) &map[CIO_FILE_CONTENT_LENGTH_OFFSET]; + + content_length_buffer[0] = (uint8_t) ((len & 0xFF000000) >> 24); + content_length_buffer[1] = (uint8_t) ((len & 0x00FF0000) >> 16); + content_length_buffer[2] = (uint8_t) ((len & 0x0000FF00) >> 8); + content_length_buffer[3] = (uint8_t) ((len & 0x000000FF) >> 0); } #endif diff --git a/lib/chunkio/src/chunkio.c b/lib/chunkio/src/chunkio.c index 89e76b39da3..a69325cfe9e 100644 --- a/lib/chunkio/src/chunkio.c +++ b/lib/chunkio/src/chunkio.c @@ -65,25 +65,44 @@ static int check_root_path(struct cio_ctx *ctx, const char *root_path) return access(root_path, W_OK); } +void cio_options_init(struct cio_options *options) +{ + memset(options, 0, sizeof(struct cio_options)); + + options->initialized = CIO_INITIALIZED; + + options->root_path = NULL; + options->user = NULL; + options->group = NULL; + options->chmod = NULL; + options->log_cb = NULL; + options->log_level = CIO_LOG_INFO; + options->flags = CIO_OPEN_RW; + options->realloc_size_hint = CIO_DISABLE_REALLOC_HINT; +} + struct cio_ctx *cio_create(struct cio_options *options) { int ret; struct cio_ctx *ctx; struct cio_options default_options; - memset(&default_options, 0, sizeof(default_options)); - - default_options.root_path = NULL; - default_options.user = NULL; - default_options.group = NULL; - default_options.chmod = NULL; - default_options.log_cb = NULL; - default_options.log_level = CIO_LOG_INFO; - default_options.flags = 0; - if (options == NULL) { + cio_options_init(&default_options); options = &default_options; } + else { + if (options->initialized != CIO_INITIALIZED) { + /* the caller 'must' call cio_options_init() or pass NULL before creating a context */ + fprintf(stderr, "[cio] 'options' has not been initialized properly\n"); + return NULL; + } + } + + /* sanitize chunk open flags */ + if (!(options->flags & CIO_OPEN_RW) && !(options->flags & CIO_OPEN_RD)) { + options->flags |= CIO_OPEN_RW; + } if (options->log_level < CIO_LOG_ERROR || options->log_level > CIO_LOG_TRACE) { @@ -107,6 +126,7 @@ struct cio_ctx *cio_create(struct cio_options *options) ctx->page_size = cio_getpagesize(); ctx->max_chunks_up = CIO_MAX_CHUNKS_UP; ctx->options.flags = options->flags; + ctx->realloc_size_hint = CIO_DISABLE_REALLOC_HINT; if (options->user != NULL) { ctx->options.user = strdup(options->user); @@ -171,6 +191,18 @@ struct cio_ctx *cio_create(struct cio_options *options) ctx->processed_group = NULL; } + if (options->realloc_size_hint > 0) { + ret = cio_set_realloc_size_hint(ctx, options->realloc_size_hint); + if (ret == -1) { + cio_log_error(ctx, + "[chunkio] cannot initialize with realloc size hint %d\n", + options->realloc_size_hint); + cio_destroy(ctx); + + return NULL; + } + } + return ctx; } @@ -305,3 +337,33 @@ int cio_set_max_chunks_up(struct cio_ctx *ctx, int n) ctx->max_chunks_up = n; return 0; } + +int cio_set_realloc_size_hint(struct cio_ctx *ctx, size_t realloc_size_hint) +{ + if (realloc_size_hint < CIO_REALLOC_HINT_MIN) { + cio_log_error(ctx, + "[chunkio] cannot specify less than %zu bytes\n", + CIO_REALLOC_HINT_MIN); + return -1; + } + else if (realloc_size_hint > CIO_REALLOC_HINT_MAX) { + cio_log_error(ctx, + "[chunkio] cannot specify more than %zu bytes\n", + CIO_REALLOC_HINT_MAX); + return -1; + } + + ctx->realloc_size_hint = realloc_size_hint; + + return 0; +} + +void cio_enable_file_trimming(struct cio_ctx *ctx) +{ + ctx->options.flags |= CIO_TRIM_FILES; +} + +void cio_disable_file_trimming(struct cio_ctx *ctx) +{ + ctx->options.flags &= ~CIO_TRIM_FILES; +} \ No newline at end of file diff --git a/lib/chunkio/src/cio_file.c b/lib/chunkio/src/cio_file.c index 786a022e927..019baa89048 100644 --- a/lib/chunkio/src/cio_file.c +++ b/lib/chunkio/src/cio_file.c @@ -40,6 +40,8 @@ #include #include +size_t scio_file_page_size = 0; + char cio_file_init_bytes[] = { /* file type (2 bytes) */ CIO_FILE_ID_00, CIO_FILE_ID_01, @@ -59,25 +61,31 @@ char cio_file_init_bytes[] = { #define ROUND_UP(N, S) ((((N) + (S) - 1) / (S)) * (S)) -/* Get the number of bytes in the Content section */ -static size_t content_len(struct cio_file *cf) -{ - int meta; - size_t len; - - meta = cio_file_st_get_meta_len(cf->map); - len = 2 + meta + cf->data_size; - return len; -} /* Calculate content checksum in a variable */ void cio_file_calculate_checksum(struct cio_file *cf, crc_t *out) { crc_t val; size_t len; + ssize_t content_length; unsigned char *in_data; - len = content_len(cf); + if (cf->fs_size == 0) { + cio_file_update_size(cf); + } + + /* Metadata length header + metadata length + content length */ + len = 2; + len += cio_file_st_get_meta_len(cf->map); + + content_length = cio_file_st_get_content_len(cf->map, + cf->fs_size, + cf->page_size); + + if (content_length > 0) { + len += content_length; + } + in_data = (unsigned char *) cf->map + CIO_FILE_CONTENT_OFFSET; val = cio_crc32_update(cf->crc_cur, in_data, len); *out = val; @@ -109,6 +117,7 @@ static void finalize_checksum(struct cio_file *cf) crc = cio_crc32_finalize(cf->crc_cur); crc = htonl(crc); + memcpy(cf->map + 2, &crc, sizeof(crc)); } @@ -146,21 +155,26 @@ static void write_init_header(struct cio_chunk *ch, struct cio_file *cf) cf->map[4] = 0; cf->map[5] = 0; } + + cio_file_st_set_content_len(cf->map, 0); } /* Return the available size in the file map to write data */ static size_t get_available_size(struct cio_file *cf, int *meta_len) { size_t av; - int len; + int metadata_len; /* Get metadata length */ - len = cio_file_st_get_meta_len(cf->map); + metadata_len = cio_file_st_get_meta_len(cf->map); + + av = cf->alloc_size; + av -= CIO_FILE_HEADER_MIN; + av -= metadata_len; + av -= cf->data_size; - av = cf->alloc_size - cf->data_size; - av -= (CIO_FILE_HEADER_MIN + len); + *meta_len = metadata_len; - *meta_len = len; return av; } @@ -171,6 +185,9 @@ static size_t get_available_size(struct cio_file *cf, int *meta_len) static int cio_file_format_check(struct cio_chunk *ch, struct cio_file *cf, int flags) { + size_t metadata_length; + ssize_t content_length; + ssize_t logical_length; unsigned char *p; crc_t crc_check; crc_t crc; @@ -186,6 +203,7 @@ static int cio_file_format_check(struct cio_chunk *ch, cio_log_warn(ch->ctx, "[cio file] cannot initialize chunk (read-only)"); cio_error_set(ch, CIO_ERR_PERMISSION); + return -1; } @@ -193,6 +211,7 @@ static int cio_file_format_check(struct cio_chunk *ch, if (cf->alloc_size < CIO_FILE_HEADER_MIN) { cio_log_warn(ch->ctx, "[cio file] cannot initialize chunk"); cio_error_set(ch, CIO_ERR_BAD_LAYOUT); + return -1; } @@ -210,6 +229,34 @@ static int cio_file_format_check(struct cio_chunk *ch, cio_log_debug(ch->ctx, "[cio file] invalid header at %s", ch->name); cio_error_set(ch, CIO_ERR_BAD_LAYOUT); + + return -1; + } + + /* Expected / logical file size verification */ + content_length = cio_file_st_get_content_len(cf->map, + cf->fs_size, + cf->page_size); + + if (content_length == -1) { + cio_log_debug(ch->ctx, "[cio file] truncated header (%zu / %zu) %s", + cf->fs_size, CIO_FILE_HEADER_MIN, ch->name); + cio_error_set(ch, CIO_ERR_BAD_FILE_SIZE); + + return -1; + } + + metadata_length = cio_file_st_get_meta_len(cf->map); + + logical_length = CIO_FILE_HEADER_MIN + + metadata_length + + content_length; + + if (logical_length > cf->fs_size) { + cio_log_debug(ch->ctx, "[cio file] truncated file (%zd / %zd) %s", + cf->fs_size, logical_length, ch->name); + cio_error_set(ch, CIO_ERR_BAD_FILE_SIZE); + return -1; } @@ -227,12 +274,15 @@ static int cio_file_format_check(struct cio_chunk *ch, /* Compare */ crc_check = cio_crc32_finalize(crc); crc_check = htonl(crc_check); + if (memcmp(p, &crc_check, sizeof(crc_check)) != 0) { - cio_log_debug(ch->ctx, "[cio file] invalid crc32 at %s/%s", + cio_log_info(ch->ctx, "[cio file] invalid crc32 at %s/%s", ch->name, cf->path); cio_error_set(ch, CIO_ERR_BAD_CHECKSUM); + return -1; } + cf->crc_cur = crc; } } @@ -368,7 +418,9 @@ static int mmap_file(struct cio_ctx *ctx, struct cio_chunk *ch, size_t size) /* check content data size */ if (fs_size > 0) { - content_size = cio_file_st_get_content_size(cf->map, fs_size); + content_size = cio_file_st_get_content_len(cf->map, + fs_size, + cf->page_size); if (content_size == -1) { cio_error_set(ch, CIO_ERR_BAD_FILE_SIZE); @@ -383,6 +435,7 @@ static int mmap_file(struct cio_ctx *ctx, struct cio_chunk *ch, size_t size) return CIO_CORRUPTED; } + cf->data_size = content_size; cf->fs_size = fs_size; } @@ -591,7 +644,15 @@ struct cio_file *cio_file_open(struct cio_ctx *ctx, cf->fd = -1; cf->flags = flags; - cf->realloc_size = cio_getpagesize() * 8; + cf->page_size = cio_getpagesize(); + + if (ctx->realloc_size_hint > 0) { + cf->realloc_size = ctx->realloc_size_hint; + } + else { + cf->realloc_size = CIO_REALLOC_HINT_MIN; + } + cf->st_content = NULL; cf->crc_cur = cio_crc32_init(); cf->path = path; @@ -699,14 +760,14 @@ int cio_file_delete(struct cio_ctx *ctx, struct cio_stream *st, const char *name char *path; int ret; - ret = cio_file_native_filename_check(name); + ret = cio_file_native_filename_check((char *) name); if (ret != CIO_OK) { cio_log_error(ctx, "[cio file] invalid file name"); return CIO_ERROR; } - path = cio_file_native_compose_path(ctx->options.root_path, st->name, name); + path = cio_file_native_compose_path(ctx->options.root_path, st->name, (char *) name); if (path == NULL) { return CIO_ERROR; } @@ -890,6 +951,7 @@ void cio_file_close(struct cio_chunk *ch, int delete) free(cf); } + int cio_file_write(struct cio_chunk *ch, const void *buf, size_t count) { int ret; @@ -946,6 +1008,14 @@ int cio_file_write(struct cio_chunk *ch, const void *buf, size_t count) old_size, new_size); } + /* If crc_reset was toggled we know that data_size was + * modified by cio_chunk_write_at which means we need + * to update the header before we recalculate the checksum + */ + if (cf->crc_reset) { + cio_file_st_set_content_len(cf->map, cf->data_size); + } + if (ch->ctx->options.flags & CIO_CHECKSUM) { update_checksum(cf, (unsigned char *) buf, count); } @@ -956,6 +1026,8 @@ int cio_file_write(struct cio_chunk *ch, const void *buf, size_t count) cf->data_size += count; cf->synced = CIO_FALSE; + cio_file_st_set_content_len(cf->map, cf->data_size); + return 0; } @@ -1069,28 +1141,41 @@ int cio_file_sync(struct cio_chunk *ch) return -1; } - /* If there are extra space, truncate the file size */ - av_size = get_available_size(cf, &meta_len); + /* File trimming has been made opt-in because it causes + * performance degradation and excessive fragmentation + * in XFS. + */ + if ((ch->ctx->options.flags & CIO_TRIM_FILES) != 0) { + /* If there are extra space, truncate the file size */ + av_size = get_available_size(cf, &meta_len); - if (av_size > 0) { - desired_size = cf->alloc_size - av_size; - } - else if (cf->alloc_size > file_size) { - desired_size = cf->alloc_size; - } - else { - desired_size = file_size; - } + if (av_size > 0) { + desired_size = cf->alloc_size - av_size; + } + else if (cf->alloc_size > file_size) { + desired_size = cf->alloc_size; + } + else { + desired_size = file_size; + } - if (desired_size != file_size) { - ret = cio_file_resize(cf, desired_size); + if (desired_size != file_size) { + /* When file trimming is enabled we still round the file size up + * to the memory page size because even though not explicitly + * stated there seems to be a performance degradation issue that + * correlates with sub-page mapping. + */ + desired_size = ROUND_UP(desired_size, ch->ctx->page_size); - if (ret != CIO_OK) { - cio_log_error(ch->ctx, - "[cio file sync] error adjusting size at: " - " %s/%s", ch->st->name, ch->name); + ret = cio_file_resize(cf, desired_size); + + if (ret != CIO_OK) { + cio_log_error(ch->ctx, + "[cio file sync] error adjusting size at: " + " %s/%s", ch->st->name, ch->name); - return ret; + return ret; + } } } diff --git a/lib/chunkio/src/cio_file_unix.c b/lib/chunkio/src/cio_file_unix.c index a9ef6056fbe..72d49312dc1 100644 --- a/lib/chunkio/src/cio_file_unix.c +++ b/lib/chunkio/src/cio_file_unix.c @@ -497,45 +497,65 @@ int cio_file_native_sync(struct cio_file *cf, int sync_mode) int cio_file_native_resize(struct cio_file *cf, size_t new_size) { + int fallocate_available; int result; result = -1; +#if defined(CIO_HAVE_FALLOCATE) || defined(CIO_HAVE_POSIX_FALLOCATE) + fallocate_available = CIO_TRUE; +#else + fallocate_available = CIO_FALSE; +#endif + /* * fallocate() is not portable an Linux only. Since macOS does not have * fallocate() we use ftruncate(). */ -#if defined(CIO_HAVE_FALLOCATE) - if (new_size > cf->alloc_size) { + if (fallocate_available && new_size > cf->fs_size) { retry: - if (cf->allocate_strategy == CIO_FILE_LINUX_FALLOCATE) { - /* - * To increase the file size we use fallocate() since this option - * will send a proper ENOSPC error if the file system ran out of - * space. ftruncate() will not fail and upon memcpy() over the - * mmap area it will trigger a 'Bus Error' crashing the program. - * - * fallocate() is not portable, Linux only. - */ - result = fallocate(cf->fd, 0, 0, new_size); - if (result == -1 && errno == EOPNOTSUPP) { - /* - * If fallocate fails with an EOPNOTSUPP try operation using - * posix_fallocate. Required since some filesystems do not support - * the fallocate operation e.g. ext3 and reiserfs. - */ - cf->allocate_strategy = CIO_FILE_LINUX_POSIX_FALLOCATE; - goto retry; - } - } - else if (cf->allocate_strategy == CIO_FILE_LINUX_POSIX_FALLOCATE) { + if (cf->allocate_strategy == CIO_FILE_LINUX_FALLOCATE) { + /* + * To increase the file size we use fallocate() since this option + * will send a proper ENOSPC error if the file system ran out of + * space. ftruncate() will not fail and upon memcpy() over the + * mmap area it will trigger a 'Bus Error' crashing the program. + * + * fallocate() is not portable, Linux only. + */ +#if defined(CIO_HAVE_FALLOCATE) + result = fallocate(cf->fd, 0, 0, new_size); + +#elif defined(CIO_HAVE_POSIX_FALLOCATE) + result = -1; + errno = EOPNOTSUPP; +#endif + + if (result == -1 && errno == EOPNOTSUPP) { + /* + * If fallocate fails with an EOPNOTSUPP try operation using + * posix_fallocate. Required since some filesystems do not support + * the fallocate operation e.g. ext3 and reiserfs. + */ + cf->allocate_strategy = CIO_FILE_LINUX_POSIX_FALLOCATE; + goto retry; + } + } + else if (cf->allocate_strategy == CIO_FILE_LINUX_POSIX_FALLOCATE) { +#if defined(CIO_HAVE_POSIX_FALLOCATE) result = posix_fallocate(cf->fd, 0, new_size); - } +#else + goto fallback; +#endif + } } else -#endif { +#if !defined(CIO_HAVE_POSIX_FALLOCATE) + fallback: +#endif + result = ftruncate(cf->fd, new_size); } diff --git a/lib/chunkio/src/cio_memfs.c b/lib/chunkio/src/cio_memfs.c index d114355c97a..8cd0f6c10eb 100644 --- a/lib/chunkio/src/cio_memfs.c +++ b/lib/chunkio/src/cio_memfs.c @@ -54,7 +54,11 @@ struct cio_memfs *cio_memfs_open(struct cio_ctx *ctx, struct cio_stream *st, } mf->buf_size = size; mf->buf_len = 0; - mf->realloc_size = cio_getpagesize() * 8; + if (ctx->realloc_size_hint > 0) { + mf->realloc_size = ctx->realloc_size_hint; + } else { + mf->realloc_size = cio_getpagesize() * 8; + } return mf; } diff --git a/lib/chunkio/tests/CMakeLists.txt b/lib/chunkio/tests/CMakeLists.txt index 063d2fa8e8c..7cee7e6c936 100644 --- a/lib/chunkio/tests/CMakeLists.txt +++ b/lib/chunkio/tests/CMakeLists.txt @@ -34,3 +34,24 @@ foreach(source_file ${UNIT_TESTS_FILES}) add_test(${source_file_we} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${source_file_we}) endforeach() + +# Perf tests for dev purposes: note these tests are not registered, they need to +# be executed manually +set(UNIT_PERF_TESTS + fs_perf.c + fs_fragmentation.c + ) +foreach(source_file ${UNIT_PERF_TESTS}) + get_filename_component(source_file_we ${source_file} NAME_WE) + set(source_file_we cio-${source_file_we}) + add_executable( + ${source_file_we} + ${source_file} + ) + target_link_libraries(${source_file_we} chunkio-static) + + if (CIO_SANITIZE_ADDRESS) + add_sanitizers(${source_file_we}) + endif() + #add_test(${source_file_we} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${source_file_we}) +endforeach() diff --git a/lib/chunkio/tests/context.c b/lib/chunkio/tests/context.c index c64b94ced93..7b7d9ea4865 100644 --- a/lib/chunkio/tests/context.c +++ b/lib/chunkio/tests/context.c @@ -46,10 +46,8 @@ static void test_context() flags = CIO_CHECKSUM; - memset(&cio_opts, 0, sizeof(cio_opts)); - + cio_options_init(&cio_opts); cio_opts.flags = flags; - cio_opts.log_cb = NULL; /* Invalid path */ cio_opts.root_path = ""; @@ -97,10 +95,7 @@ static void test_log_level() struct cio_ctx *ctx; struct cio_options cio_opts; - memset(&cio_opts, 0, sizeof(cio_opts)); - - cio_opts.flags = 0; - cio_opts.log_cb = NULL; + cio_options_init(&cio_opts); /* Logging with unset callback at creation, but set later */ log_check = 0; @@ -159,8 +154,29 @@ static void test_log_level() cio_destroy(ctx); } +static void test_open_flags() +{ + struct cio_ctx *ctx; + struct cio_options cio_opts; + + cio_options_init(&cio_opts); + TEST_CHECK(cio_opts.flags & CIO_OPEN_RW); + + /* reset flags */ + cio_opts.flags = 0; + + /* check that after context creation a default has been set */ + ctx = cio_create(&cio_opts); + TEST_CHECK(ctx != NULL); + TEST_CHECK(cio_opts.flags & CIO_OPEN_RW); + + /* destroy context */ + cio_destroy(ctx); +} + TEST_LIST = { {"context", test_context}, {"log_level", test_log_level}, + {"open_flags", test_open_flags}, { 0 } }; diff --git a/lib/chunkio/tests/fs.c b/lib/chunkio/tests/fs.c index 2de052617e8..a976f46d103 100644 --- a/lib/chunkio/tests/fs.c +++ b/lib/chunkio/tests/fs.c @@ -33,6 +33,7 @@ #include #include #include +#include #include "cio_tests_internal.h" @@ -73,11 +74,10 @@ static void test_fs_write() flags = CIO_CHECKSUM; - memset(&cio_opts, 0, sizeof(cio_opts)); + cio_options_init(&cio_opts); cio_opts.root_path = CIO_ENV; cio_opts.log_cb = log_cb; - cio_opts.log_level = CIO_LOG_INFO; cio_opts.flags = flags; /* cleanup environment */ @@ -160,7 +160,7 @@ static void test_fs_write() free(in_data); cio_destroy(ctx); - memset(&cio_opts, 0, sizeof(cio_opts)); + cio_options_init(&cio_opts); cio_opts.root_path = CIO_ENV; cio_opts.log_cb = log_cb; @@ -221,11 +221,10 @@ static void test_fs_checksum() /* cleanup environment */ cio_utils_recursive_delete(CIO_ENV); - memset(&cio_opts, 0, sizeof(cio_opts)); + cio_options_init(&cio_opts); cio_opts.root_path = CIO_ENV; cio_opts.log_cb = log_cb; - cio_opts.log_level = CIO_LOG_INFO; cio_opts.flags = flags; ctx = cio_create(&cio_opts); @@ -336,7 +335,7 @@ static void test_fs_up_down() /* cleanup environment */ cio_utils_recursive_delete(CIO_ENV); - memset(&cio_opts, 0, sizeof(cio_opts)); + cio_options_init(&cio_opts); cio_opts.root_path = CIO_ENV; cio_opts.log_cb = log_cb; @@ -442,7 +441,7 @@ static void test_issue_51() struct cio_options cio_opts; /* Create a temporal storage */ - memset(&cio_opts, 0, sizeof(cio_opts)); + cio_options_init(&cio_opts); cio_opts.root_path = "tmp"; cio_opts.log_cb = log_cb; @@ -495,7 +494,7 @@ static void test_issue_flb_2025() cio_utils_recursive_delete("tmp"); /* Create a temporal storage */ - memset(&cio_opts, 0, sizeof(cio_opts)); + cio_options_init(&cio_opts); cio_opts.root_path = "tmp"; cio_opts.log_cb = log_cb; @@ -547,7 +546,7 @@ void test_fs_size_chunks_up() flags = CIO_CHECKSUM; - memset(&cio_opts, 0, sizeof(cio_opts)); + cio_options_init(&cio_opts); cio_opts.root_path = CIO_ENV; cio_opts.log_cb = log_cb; @@ -646,7 +645,7 @@ void test_issue_write_at() cio_utils_recursive_delete(CIO_ENV); /* create Chunk I/O context */ - memset(&cio_opts, 0, sizeof(cio_opts)); + cio_options_init(&cio_opts); cio_opts.root_path = CIO_ENV; cio_opts.log_cb = log_cb; @@ -740,7 +739,7 @@ void test_fs_up_down_up_append() cio_utils_recursive_delete(CIO_ENV); /* create Chunk I/O context */ - memset(&cio_opts, 0, sizeof(cio_opts)); + cio_options_init(&cio_opts); cio_opts.root_path = CIO_ENV; cio_opts.log_cb = log_cb; @@ -818,7 +817,7 @@ static void test_deep_hierarchy() cio_utils_recursive_delete("tmp"); /* Create a temporal storage */ - memset(&cio_opts, 0, sizeof(cio_opts)); + cio_options_init(&cio_opts); cio_opts.root_path = "tmp/deep/log/dir"; cio_opts.log_cb = log_cb; @@ -849,6 +848,122 @@ static void test_deep_hierarchy() cio_destroy(ctx); } +static void truncate_file(struct cio_file *chunk_file, + size_t new_file_size, + int remove_content_length) +{ + int result; + + result = cio_file_native_open(chunk_file); + TEST_CHECK(result == CIO_OK); + + result = cio_file_native_map(chunk_file, + chunk_file->page_size); + TEST_CHECK(result == CIO_OK); + + if (remove_content_length) { + chunk_file->map[CIO_FILE_CONTENT_LENGTH_OFFSET + 0] = 0; + chunk_file->map[CIO_FILE_CONTENT_LENGTH_OFFSET + 1] = 0; + chunk_file->map[CIO_FILE_CONTENT_LENGTH_OFFSET + 2] = 0; + chunk_file->map[CIO_FILE_CONTENT_LENGTH_OFFSET + 3] = 0; + } + + result = cio_file_native_unmap(chunk_file); + TEST_CHECK(result == CIO_OK); + + result = cio_file_native_resize(chunk_file, new_file_size); + TEST_CHECK(result == 0); + + result = cio_file_native_close(chunk_file); + TEST_CHECK(result == CIO_OK); +} + +static void test_legacy_core(int trigger_checksum_error) +{ + struct cio_options cio_opts; + char *in_data; + size_t in_size; + struct cio_stream *stream; + struct cio_chunk *chunk; + size_t delta; + struct cio_ctx *ctx; + int ret; + + /* delete any previous temporary content directory */ + cio_utils_recursive_delete(CIO_ENV); + /* + * Load sample data file and with the same content through multiple write + * operations generating other files. + */ + ret = cio_utils_read_file(CIO_FILE_400KB, &in_data, &in_size); + TEST_CHECK(ret == 0); + if (ret == -1) { + exit(EXIT_FAILURE); + } + + /* create Chunk I/O context */ + cio_options_init(&cio_opts); + + cio_opts.root_path = CIO_ENV; + cio_opts.log_cb = log_cb; + cio_opts.log_level = CIO_LOG_DEBUG; + cio_opts.flags = CIO_CHECKSUM; + + /* Create a temporal storage */ + ctx = cio_create(&cio_opts); + + stream = cio_stream_create(ctx, "test-legacy", CIO_STORE_FS); + + /* do not force a maximum of chunks up, we want to test writing overhead */ + cio_set_max_chunks_up(ctx, 1); + + chunk = cio_chunk_open(ctx, + stream, + "test_chunk", + CIO_OPEN, + 1000, + &ret); + + ret = cio_chunk_write(chunk, in_data, 128); + TEST_CHECK(ret == 0); + + ret = cio_chunk_down(chunk); + TEST_CHECK(ret == CIO_OK); + + delta = CIO_FILE_HEADER_MIN; + + if (trigger_checksum_error) { + delta++; + } + + truncate_file((struct cio_file *) chunk->backend, + 128 + delta, + CIO_TRUE); + + ret = cio_chunk_up(chunk); + + if (trigger_checksum_error) { + TEST_CHECK(ret != CIO_OK); + } + else { + TEST_CHECK(ret == CIO_OK); + } + + cio_destroy(ctx); + + free(in_data); +} + +void test_legacy_success() +{ + test_legacy_core(CIO_FALSE); +} + +void test_legacy_failure() +{ + test_legacy_core(CIO_TRUE); +} + TEST_LIST = { {"fs_write", test_fs_write}, {"fs_checksum", test_fs_checksum}, @@ -859,5 +974,7 @@ TEST_LIST = { {"issue_write_at", test_issue_write_at}, {"fs_up_down_up_append", test_fs_up_down_up_append}, {"fs_deep_hierachy", test_deep_hierarchy}, + {"legacy_success", test_legacy_success}, + {"legacy_failure", test_legacy_failure}, { 0 } }; diff --git a/lib/chunkio/tests/memfs.c b/lib/chunkio/tests/memfs.c index e10d0205710..0c79f0097e4 100644 --- a/lib/chunkio/tests/memfs.c +++ b/lib/chunkio/tests/memfs.c @@ -93,11 +93,10 @@ static void test_memfs_write() flags = CIO_CHECKSUM; - memset(&cio_opts, 0, sizeof(cio_opts)); + cio_options_init(&cio_opts); + cio_opts.flags = flags; - cio_opts.root_path = NULL; cio_opts.log_cb = log_cb; - cio_opts.log_level = CIO_LOG_INFO; cio_opts.flags = flags; /* Create main context */ diff --git a/lib/chunkio/tests/stream.c b/lib/chunkio/tests/stream.c index 1b47a8a2d9a..0a86c1437b2 100644 --- a/lib/chunkio/tests/stream.c +++ b/lib/chunkio/tests/stream.c @@ -54,7 +54,7 @@ static void test_stream_delete() cio_utils_recursive_delete("tmp"); - memset(&cio_opts, 0, sizeof(cio_opts)); + cio_options_init(&cio_opts); cio_opts.root_path = "tmp"; cio_opts.log_cb = log_cb; diff --git a/lib/chunkio/tools/cio.c b/lib/chunkio/tools/cio.c index 9ac27129766..a278276534e 100644 --- a/lib/chunkio/tools/cio.c +++ b/lib/chunkio/tools/cio.c @@ -591,7 +591,7 @@ int main(int argc, char **argv) verbose = 0; } - memset(&cio_opts, 0, sizeof(cio_opts)); + cio_options_init(&cio_opts); cio_opts.root_path = root_path; cio_opts.flags = flags; From b78b05a7ee3be1ba8df2d1ff108698af24afd457 Mon Sep 17 00:00:00 2001 From: Leonardo Alminana Date: Thu, 21 Sep 2023 17:54:20 +0200 Subject: [PATCH 263/315] storage: added chunkio options structure initialization and trim support Signed-off-by: Leonardo Alminana --- src/flb_storage.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/flb_storage.c b/src/flb_storage.c index 3535fae3a4c..a89a4c4b558 100644 --- a/src/flb_storage.c +++ b/src/flb_storage.c @@ -622,7 +622,14 @@ int flb_storage_create(struct flb_config *ctx) flags |= CIO_CHECKSUM; } + /* file trimming */ + if (ctx->storage_trim_files == FLB_TRUE) { + flags |= CIO_TRIM_FILES; + } + /* chunkio options */ + cio_options_init(&opts); + opts.root_path = ctx->storage_path; opts.flags = flags; opts.log_cb = log_cb; From 3de9cb97a2a7a2f17d4fddbbb37ad2c4ab0d1303 Mon Sep 17 00:00:00 2001 From: Leonardo Alminana Date: Thu, 21 Sep 2023 17:54:29 +0200 Subject: [PATCH 264/315] storage: added chunkio options structure initialization Signed-off-by: Leonardo Alminana --- src/flb_fstore.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/flb_fstore.c b/src/flb_fstore.c index 40980986d75..03bcc99dba6 100644 --- a/src/flb_fstore.c +++ b/src/flb_fstore.c @@ -461,6 +461,8 @@ struct flb_fstore *flb_fstore_create(char *path, int store_type) flags = CIO_OPEN; /* Create Chunk I/O context */ + cio_options_init(&opts); + opts.root_path = path; opts.log_cb = log_cb; opts.flags = flags; From 3547fb158348c8f61b0b527b4354a1e52b979d53 Mon Sep 17 00:00:00 2001 From: Leonardo Alminana Date: Thu, 21 Sep 2023 17:54:42 +0200 Subject: [PATCH 265/315] tests: added chunkio options structure initialization Signed-off-by: Leonardo Alminana --- tests/internal/input_chunk.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/internal/input_chunk.c b/tests/internal/input_chunk.c index f9ded1ed189..757e3b4cc0c 100644 --- a/tests/internal/input_chunk.c +++ b/tests/internal/input_chunk.c @@ -424,6 +424,8 @@ void flb_test_input_chunk_fs_chunks_size_real() i_ins = flb_input_new(cfg, "dummy", NULL, FLB_TRUE); i_ins->storage_type = CIO_STORE_FS; + cio_options_init(&opts); + opts.root_path = "/tmp/input-chunk-fs_chunks-size_real"; opts.log_cb = log_cb; opts.log_level = CIO_LOG_DEBUG; From 1a1bf0517422a7ae39ddf90cdf5a3a6949c9caaa Mon Sep 17 00:00:00 2001 From: Leonardo Alminana Date: Thu, 21 Sep 2023 17:55:03 +0200 Subject: [PATCH 266/315] config: added chunkio trimming support Signed-off-by: Leonardo Alminana --- include/fluent-bit/flb_config.h | 2 ++ src/flb_config.c | 3 +++ 2 files changed, 5 insertions(+) diff --git a/include/fluent-bit/flb_config.h b/include/fluent-bit/flb_config.h index 59bc3a57c8e..a00ac48bf55 100644 --- a/include/fluent-bit/flb_config.h +++ b/include/fluent-bit/flb_config.h @@ -225,6 +225,7 @@ struct flb_config { int storage_del_bad_chunks; /* delete irrecoverable chunks */ char *storage_bl_mem_limit; /* storage backlog memory limit */ struct flb_storage_metrics *storage_metrics_ctx; /* storage metrics context */ + int storage_trim_files; /* enable/disable file trimming */ /* Embedded SQL Database support (SQLite3) */ #ifdef FLB_HAVE_SQLDB @@ -355,6 +356,7 @@ enum conf_type { #define FLB_CONF_STORAGE_MAX_CHUNKS_UP "storage.max_chunks_up" #define FLB_CONF_STORAGE_DELETE_IRRECOVERABLE_CHUNKS \ "storage.delete_irrecoverable_chunks" +#define FLB_CONF_STORAGE_TRIM_FILES "storage.trim_files" /* Coroutines */ #define FLB_CONF_STR_CORO_STACK_SIZE "Coro_Stack_Size" diff --git a/src/flb_config.c b/src/flb_config.c index 5f5289d0186..34a4e727b0e 100644 --- a/src/flb_config.c +++ b/src/flb_config.c @@ -147,6 +147,9 @@ struct flb_service_config service_configs[] = { {FLB_CONF_STORAGE_DELETE_IRRECOVERABLE_CHUNKS, FLB_CONF_TYPE_BOOL, offsetof(struct flb_config, storage_del_bad_chunks)}, + {FLB_CONF_STORAGE_TRIM_FILES, + FLB_CONF_TYPE_BOOL, + offsetof(struct flb_config, storage_trim_files)}, /* Coroutines */ {FLB_CONF_STR_CORO_STACK_SIZE, From b699614407cfc4573e63afa46d8f961783bc502b Mon Sep 17 00:00:00 2001 From: Baek Choong deok Date: Thu, 21 Sep 2023 15:40:50 +0900 Subject: [PATCH 267/315] out_http: Fix bug where post_all_requests() always returns a value less than 0 --- plugins/out_http/http.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/out_http/http.c b/plugins/out_http/http.c index 17c3ef92b9d..f88b6346dca 100644 --- a/plugins/out_http/http.c +++ b/plugins/out_http/http.c @@ -503,7 +503,7 @@ static int post_all_requests(struct flb_out_http *ctx, return -1; } - while ((ret = flb_log_event_decoder_next( + while ((flb_log_event_decoder_next( &log_decoder, &log_event)) == FLB_EVENT_DECODER_SUCCESS) { headers = NULL; From fdb3adf3afd1c20b895c217b244d4d9d0d8e2c1a Mon Sep 17 00:00:00 2001 From: Aditya Bharadwaj <49105292+adiforluls@users.noreply.github.com> Date: Fri, 22 Sep 2023 06:04:52 +0530 Subject: [PATCH 268/315] out_oracle_log_analytics: add new Oracle log analytics connector (#7830) --------- Signed-off-by: adiforluls --- CMakeLists.txt | 1 + plugins/CMakeLists.txt | 1 + .../out_oracle_log_analytics/CMakeLists.txt | 6 + plugins/out_oracle_log_analytics/oci_logan.c | 1313 +++++++++++++++++ plugins/out_oracle_log_analytics/oci_logan.h | 215 +++ .../out_oracle_log_analytics/oci_logan_conf.c | 493 +++++++ .../out_oracle_log_analytics/oci_logan_conf.h | 34 + 7 files changed, 2063 insertions(+) create mode 100644 plugins/out_oracle_log_analytics/CMakeLists.txt create mode 100644 plugins/out_oracle_log_analytics/oci_logan.c create mode 100644 plugins/out_oracle_log_analytics/oci_logan.h create mode 100644 plugins/out_oracle_log_analytics/oci_logan_conf.c create mode 100644 plugins/out_oracle_log_analytics/oci_logan_conf.h diff --git a/CMakeLists.txt b/CMakeLists.txt index ca0a4683a6b..b67b93659a7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -261,6 +261,7 @@ option(FLB_OUT_PROMETHEUS_REMOTE_WRITE "Enable Prometheus remote write plugin" option(FLB_OUT_S3 "Enable AWS S3 output plugin" Yes) option(FLB_OUT_VIVO_EXPORTER "Enabel Vivo exporter output plugin" Yes) option(FLB_OUT_WEBSOCKET "Enable Websocket output plugin" Yes) +option(FLB_OUT_ORACLE_LOG_ANALYTICS "Enable Oracle Cloud Infrastructure Logging analytics plugin" Yes) option(FLB_OUT_CHRONICLE "Enable Google Chronicle output plugin" Yes) option(FLB_FILTER_ALTER_SIZE "Enable alter_size filter" Yes) option(FLB_FILTER_AWS "Enable aws filter" Yes) diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 2715876119d..36299074ab2 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -304,6 +304,7 @@ REGISTER_OUT_PLUGIN("out_nats") REGISTER_OUT_PLUGIN("out_nrlogs") REGISTER_OUT_PLUGIN("out_null") REGISTER_OUT_PLUGIN("out_opensearch") +REGISTER_OUT_PLUGIN("out_oracle_log_analytics") if (NOT CMAKE_SYSTEM_NAME MATCHES "Windows") REGISTER_OUT_PLUGIN("out_plot") diff --git a/plugins/out_oracle_log_analytics/CMakeLists.txt b/plugins/out_oracle_log_analytics/CMakeLists.txt new file mode 100644 index 00000000000..81f971a9501 --- /dev/null +++ b/plugins/out_oracle_log_analytics/CMakeLists.txt @@ -0,0 +1,6 @@ +set(src + oci_logan.c + oci_logan_conf.c + ) + +FLB_PLUGIN(out_oracle_log_analytics "${src}" "") diff --git a/plugins/out_oracle_log_analytics/oci_logan.c b/plugins/out_oracle_log_analytics/oci_logan.c new file mode 100644 index 00000000000..630812e2d28 --- /dev/null +++ b/plugins/out_oracle_log_analytics/oci_logan.c @@ -0,0 +1,1313 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Fluent Bit + * ========== + * Copyright (C) 2015-2023 The Fluent Bit Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "oci_logan_conf.h" +#include "oci_logan.h" + + +static int check_config_from_record(msgpack_object key, + char *name, int len) +{ + if (key.type != MSGPACK_OBJECT_STR) { + return FLB_FALSE; + } + + if (key.via.str.size != len) { + return FLB_FALSE; + } + + + return memcmp(key.via.str.ptr, name, len) == 0; +} + +/* + * Authorization: Signature version="1",keyId="//", + * algorithm="rsa-sha256",headers="(request-target) date x-content-sha256 content-type content-length", + * signature="signature" + */ +static flb_sds_t create_authorization_header_content(struct flb_oci_logan *ctx, + flb_sds_t signature) +{ + flb_sds_t content; + + content = flb_sds_create_size(512); + flb_sds_cat_safe(&content, FLB_OCI_SIGN_SIGNATURE_VERSION, + sizeof(FLB_OCI_SIGN_SIGNATURE_VERSION) - 1); + flb_sds_cat_safe(&content, ",", 1); + flb_sds_cat_safe(&content, FLB_OCI_SIGN_KEYID, + sizeof(FLB_OCI_SIGN_KEYID) - 1); + flb_sds_cat_safe(&content, "=\"", 2); + flb_sds_cat_safe(&content, ctx->key_id, flb_sds_len(ctx->key_id)); + flb_sds_cat_safe(&content, "\",", 2); + flb_sds_cat_safe(&content, FLB_OCI_SIGN_ALGORITHM, + sizeof(FLB_OCI_SIGN_ALGORITHM) - 1); + flb_sds_cat_safe(&content, ",", 1); + flb_sds_cat_safe(&content, FLB_OCI_SIGN_HEADERS, + sizeof(FLB_OCI_SIGN_HEADERS) - 1); + flb_sds_cat_safe(&content, ",", 1); + flb_sds_cat_safe(&content, FLB_OCI_SIGN_SIGNATURE, + sizeof(FLB_OCI_SIGN_SIGNATURE) - 1); + flb_sds_cat_safe(&content, "=\"", 2); + flb_sds_cat_safe(&content, signature, flb_sds_len(signature)); + flb_sds_cat_safe(&content, "\"", 1); + + return content; +} + +static flb_sds_t create_base64_sha256_signature(struct flb_oci_logan *ctx, + flb_sds_t signing_string) +{ + int len = 0, ret; + size_t outlen; + flb_sds_t signature; + unsigned char sha256_buf[32] = { 0 }; + unsigned char sig[256] = { 0 }; + size_t sig_len = sizeof(sig); + + ret = flb_hash_simple(FLB_HASH_SHA256, + (unsigned char*) signing_string, + flb_sds_len(signing_string), + sha256_buf, sizeof(sha256_buf)); + + if(ret != FLB_CRYPTO_SUCCESS) { + flb_plg_error(ctx->ins, "error generating hash buffer"); + return NULL; + } + + ret = flb_crypto_sign_simple(FLB_CRYPTO_PRIVATE_KEY, + FLB_CRYPTO_PADDING_PKCS1, + FLB_HASH_SHA256, + (unsigned char *) ctx->private_key, + flb_sds_len(ctx->private_key), + sha256_buf, sizeof(sha256_buf), + sig, &sig_len); + + + if (ret != FLB_CRYPTO_SUCCESS) { + flb_plg_error(ctx->ins, "error signing SHA256"); + return NULL; + } + + signature = flb_sds_create_size(512); + if (!signature) { + flb_errno(); + return NULL; + } + + /* base 64 encode */ + len = flb_sds_alloc(signature) - 1; + flb_base64_encode((unsigned char*) signature, len, &outlen, sig, + sizeof(sig)); + signature[outlen] = '\0'; + flb_sds_len_set(signature, outlen); + + return signature; +} + +static flb_sds_t get_date(void) +{ + + flb_sds_t rfc1123date; + time_t t; + size_t size; + struct tm tm = { 0 }; + + /* Format Date */ + rfc1123date = flb_sds_create_size(32); + if (!rfc1123date) { + flb_errno(); + return NULL; + } + + t = time(NULL); + if (!gmtime_r(&t, &tm)) { + flb_errno(); + flb_sds_destroy(rfc1123date); + return NULL; + } + size = strftime(rfc1123date, flb_sds_alloc(rfc1123date) - 1, + "%a, %d %b %Y %H:%M:%S GMT", &tm); + if (size <= 0) { + flb_errno(); + flb_sds_destroy(rfc1123date); + return NULL; + } + flb_sds_len_set(rfc1123date, size); + return rfc1123date; +} + +static flb_sds_t add_header_and_signing(struct flb_http_client *c, + flb_sds_t signing_str, const char *header, int headersize, + const char *val, int val_size) +{ + if (!signing_str) { + return NULL; + } + + flb_http_add_header(c, header, headersize, val, val_size); + + flb_sds_cat_safe(&signing_str, "\n", 1); + flb_sds_cat_safe(&signing_str, header, headersize); + flb_sds_cat_safe(&signing_str, ": ", 2); + flb_sds_cat_safe(&signing_str, val, val_size); + + return signing_str; +} + +static int build_headers(struct flb_http_client *c, struct flb_oci_logan *ctx, + flb_sds_t json, flb_sds_t hostname, int port, flb_sds_t uri) +{ + int ret = -1; + flb_sds_t tmp_sds = NULL; + flb_sds_t signing_str = NULL; + flb_sds_t rfc1123date = NULL; + flb_sds_t encoded_uri = NULL; + flb_sds_t signature = NULL; + flb_sds_t auth_header_str = NULL; + + flb_sds_t tmp_ref = NULL; + + size_t tmp_len = 0; + + unsigned char sha256_buf[32] = { 0 }; + + tmp_sds = flb_sds_create_size(512); + if (!tmp_sds) { + flb_errno(); + goto error_label; + } + + signing_str = flb_sds_create_size(1024); + if (!signing_str) { + flb_errno(); + goto error_label; + } + + /* Add (requeset-target) to signing string */ + encoded_uri = flb_uri_encode(uri, flb_sds_len(uri)); + if (!encoded_uri) { + flb_errno(); + goto error_label; + } + flb_sds_cat_safe(&signing_str, FLB_OCI_HEADER_REQUEST_TARGET, + sizeof(FLB_OCI_HEADER_REQUEST_TARGET) - 1); + flb_sds_cat_safe(&signing_str, ": post ", sizeof(": post ") - 1); + flb_sds_cat_safe(&signing_str, encoded_uri, + flb_sds_len(encoded_uri)); + + /* Add Host to Header */ + if (((c->flags & FLB_IO_TLS) && c->port == 443) + || (!(c->flags & FLB_IO_TLS) && c->port == 80)) { + /* default port */ + tmp_ref = flb_sds_copy(tmp_sds, c->host, strlen(c->host)); + } + else { + tmp_ref = flb_sds_printf(&tmp_sds, "%s:%i", c->host, c->port); + } + if (!tmp_ref) { + flb_plg_error(ctx->ins, "cannot compose temporary host header"); + goto error_label; + } + tmp_sds = tmp_ref; + tmp_ref = NULL; + + signing_str = add_header_and_signing(c, signing_str, FLB_OCI_HEADER_HOST, + sizeof(FLB_OCI_HEADER_HOST) - 1, + tmp_sds, flb_sds_len(tmp_sds)); + if (!signing_str) { + flb_plg_error(ctx->ins, "cannot compose signing string"); + goto error_label; + } + + /* Add Date header */ + rfc1123date = get_date(); + if (!rfc1123date) { + flb_plg_error(ctx->ins, "cannot compose temporary date header"); + goto error_label; + } + signing_str = add_header_and_signing(c, signing_str, FLB_OCI_HEADER_DATE, + sizeof(FLB_OCI_HEADER_DATE) - 1, rfc1123date, + flb_sds_len(rfc1123date)); + if (!signing_str) { + flb_plg_error(ctx->ins, "cannot compose signing string"); + goto error_label; + } + + /* Add x-content-sha256 Header */ + ret = flb_hash_simple(FLB_HASH_SHA256, + (unsigned char*) json, + flb_sds_len(json), + sha256_buf, sizeof(sha256_buf)); + + if (ret != FLB_CRYPTO_SUCCESS) { + flb_plg_error(ctx->ins, "error forming hash buffer for x-content-sha256 Header"); + goto error_label; + } + + flb_base64_encode((unsigned char*) tmp_sds, flb_sds_len(tmp_sds) - 1, + &tmp_len, sha256_buf, sizeof(sha256_buf)); + + tmp_sds[tmp_len] = '\0'; + flb_sds_len_set(tmp_sds, tmp_len); + + signing_str = add_header_and_signing(c, signing_str, + FLB_OCI_HEADER_X_CONTENT_SHA256, + sizeof(FLB_OCI_HEADER_X_CONTENT_SHA256) - 1, tmp_sds, + flb_sds_len(tmp_sds)); + if (!signing_str) { + flb_plg_error(ctx->ins, "cannot compose signing string"); + goto error_label; + } + + /* Add content-Type */ + signing_str = add_header_and_signing(c, signing_str, + FLB_OCI_HEADER_CONTENT_TYPE, sizeof(FLB_OCI_HEADER_CONTENT_TYPE) - 1, + FLB_OCI_HEADER_CONTENT_TYPE_VAL, + sizeof(FLB_OCI_HEADER_CONTENT_TYPE_VAL) - 1); + if (!signing_str) { + flb_plg_error(ctx->ins, "cannot compose signing string"); + goto error_label; + } + + /* Add content-Length */ + tmp_len = snprintf(tmp_sds, flb_sds_alloc(tmp_sds) - 1, "%i", + (int) flb_sds_len(json)); + flb_sds_len_set(tmp_sds, tmp_len); + signing_str = add_header_and_signing(c, signing_str, + FLB_OCI_HEADER_CONTENT_LENGTH, sizeof(FLB_OCI_HEADER_CONTENT_LENGTH) - 1, + tmp_sds, flb_sds_len(tmp_sds)); + if (!signing_str) { + flb_plg_error(ctx->ins, "cannot compose signing string"); + goto error_label; + } + + /* Add Authorization header */ + signature = create_base64_sha256_signature(ctx, signing_str); + if (!signature) { + flb_plg_error(ctx->ins, "cannot compose signing signature"); + goto error_label; + } + + auth_header_str = create_authorization_header_content(ctx, signature); + if (!auth_header_str) { + flb_plg_error(ctx->ins, "cannot compose authorization header"); + goto error_label; + } + + flb_http_add_header(c, FLB_OCI_HEADER_AUTH, sizeof(FLB_OCI_HEADER_AUTH) - 1, + auth_header_str, flb_sds_len(auth_header_str)); + + /* User-Agent */ + flb_http_add_header(c, FLB_OCI_HEADER_USER_AGENT, + sizeof(FLB_OCI_HEADER_USER_AGENT) - 1, + FLB_OCI_HEADER_USER_AGENT_VAL, + sizeof(FLB_OCI_HEADER_USER_AGENT_VAL) - 1); + + /* Accept */ + flb_http_add_header(c, "Accept", 6, "*/*", 3); + + ret = 0; + + error_label: + if (tmp_sds) { + flb_sds_destroy(tmp_sds); + } + if (signing_str) { + flb_sds_destroy(signing_str); + } + if (rfc1123date) { + flb_sds_destroy(rfc1123date); + } + if (encoded_uri) { + flb_sds_destroy(encoded_uri); + } + if (signature) { + flb_sds_destroy(signature); + } + if (auth_header_str) { + flb_sds_destroy(auth_header_str); + } + return ret; +} + +static struct flb_oci_error_response* parse_response_error(struct flb_oci_logan *ctx, + char *response, size_t response_len) +{ + int tok_size = 32, ret, i; + jsmn_parser parser; + jsmntok_t *t; + jsmntok_t *tokens; + char *key; + char *val; + int key_len; + int val_len; + struct flb_oci_error_response *error_response; + + jsmn_init(&parser); + + tokens = flb_calloc(1, sizeof(jsmntok_t) * tok_size); + if (!tokens) { + flb_errno(); + return NULL; + } + + ret = jsmn_parse(&parser, response, response_len, tokens, tok_size); + + if (ret == JSMN_ERROR_INVAL || ret == JSMN_ERROR_PART) { + flb_free(tokens); + flb_plg_info(ctx->ins, + "Unable to parser error response. reponse is not valid json"); + return NULL; + } + tok_size = ret; + + error_response = flb_calloc(1, sizeof(struct flb_oci_error_response)); + if (!error_response) { + flb_errno(); + flb_free(tokens); + return NULL; + } + + /* Parse JSON tokens */ + for (i = 0; i < tok_size; i++) { + t = &tokens[i]; + + if (t->start == -1 || t->end == -1 || (t->start == 0 && t->end == 0)) { + break; + } + + if (t->type != JSMN_STRING) { + continue; + } + + key = response + t->start; + key_len = (t->end - t->start); + + i++; + t = &tokens[i]; + val = response + t->start; + val_len = (t->end - t->start); + + if (val_len < 1) { + continue; + } + + if ((key_len == sizeof(FLB_OCI_ERROR_RESPONSE_CODE) - 1) + && strncasecmp(key, FLB_OCI_ERROR_RESPONSE_CODE, + sizeof(FLB_OCI_ERROR_RESPONSE_CODE) - 1) == 0) { + /* code */ + error_response->code = flb_sds_create_len(val, val_len); + if (!error_response->code) { + flb_free(error_response); + flb_free(tokens); + return NULL; + } + } + else if ((key_len == sizeof(FLB_OCI_ERROR_RESPONSE_MESSAGE) - 1) + && strncasecmp(key, FLB_OCI_ERROR_RESPONSE_MESSAGE, + sizeof(FLB_OCI_ERROR_RESPONSE_MESSAGE) - 1) == 0) { + + /* message */ + error_response->message = flb_sds_create_len(val, val_len); + if (!error_response->message) { + flb_free(error_response); + flb_free(tokens); + return NULL; + } + } + } + + flb_free(tokens); + return error_response; +} + +static int retry_error(struct flb_http_client *c, struct flb_oci_logan *ctx) +{ + struct flb_oci_error_response *error_response = NULL; + int tmp_len; + int ret = FLB_FALSE; + + /* possible retry error message */ + if ( !(c->resp.status == 400 || c->resp.status == 401 + || c->resp.status == 404 || c->resp.status == 409 + || c->resp.status == 429 || c->resp.status == 500)) { + return FLB_FALSE; + } + + /* parse error message */ + error_response = parse_response_error(ctx, c->resp.payload, + c->resp.payload_size); + if (!error_response) { + return FLB_FALSE; + } + + if (error_response->code) { + tmp_len = flb_sds_len(error_response->code); + if (c->resp.status == 400 + && (tmp_len == sizeof(FLB_OCI_ERROR_CODE_RELATED_RESOURCE_NOT_FOUND) - 1) + && strncasecmp(error_response->code, FLB_OCI_ERROR_CODE_RELATED_RESOURCE_NOT_FOUND, tmp_len) == 0) { + ret = FLB_TRUE; + } + else if( c->resp.status == 401 + &&( tmp_len == sizeof(FLB_OCI_ERROR_CODE_NOT_AUTHENTICATED)-1 ) + && strncasecmp(error_response->code, FLB_OCI_ERROR_CODE_NOT_AUTHENTICATED, tmp_len) == 0) { + ret = FLB_TRUE; + } + else if (c->resp.status == 404 + && (tmp_len == sizeof(FLB_OCI_ERROR_CODE_NOT_AUTHENTICATEDORNOTFOUND) - 1) + && strncasecmp(error_response->code, FLB_OCI_ERROR_CODE_NOT_AUTHENTICATEDORNOTFOUND, tmp_len) == 0) { + ret = FLB_TRUE; + } + else if (c->resp.status == 409 + && (tmp_len == sizeof(FLB_OCI_ERROR_CODE_INCORRECTSTATE) - 1) + && strncasecmp(error_response->code, FLB_OCI_ERROR_CODE_INCORRECTSTATE, tmp_len) == 0) { + ret = FLB_TRUE; + } + else if (c->resp.status == 409 + && (tmp_len == sizeof(FLB_OCI_ERROR_CODE_NOT_AUTH_OR_RESOURCE_EXIST) - 1) + && strncasecmp(error_response->code, FLB_OCI_ERROR_CODE_NOT_AUTH_OR_RESOURCE_EXIST, tmp_len) == 0) { + ret = FLB_TRUE; + } + else if (c->resp.status == 429 + && (tmp_len == sizeof(FLB_OCI_ERROR_CODE_TOO_MANY_REQUESTS) - 1) + && strncasecmp(error_response->code, FLB_OCI_ERROR_CODE_TOO_MANY_REQUESTS, tmp_len) == 0) { + ret = FLB_TRUE; + } + else if (c->resp.status == 500 + && (tmp_len == sizeof(FLB_OCI_ERROR_CODE_INTERNAL_SERVER_ERROR) - 1) + && strncasecmp(error_response->code, FLB_OCI_ERROR_CODE_INTERNAL_SERVER_ERROR, tmp_len) == 0) { + ret = FLB_TRUE; + } + } + + if (error_response->code) { + flb_sds_destroy(error_response->code); + } + if (error_response->message) { + flb_sds_destroy(error_response->message); + } + flb_free(error_response); + + return ret; +} + +static int cb_oci_logan_init(struct flb_output_instance *ins, + struct flb_config *config, + void *data) +{ + struct flb_oci_logan *ctx; + ctx = flb_oci_logan_conf_create(ins, config); + if (!ctx) { + flb_plg_error(ins, "cannot initialize plugin"); + return -1; + } + flb_plg_info(ins, "initialized logan plugin"); + flb_output_set_context(ins, ctx); + flb_output_set_http_debug_callbacks(ins); + + return 0; +} + +static flb_sds_t compose_uri(struct flb_oci_logan *ctx, + flb_sds_t log_set, flb_sds_t log_group_id) +{ + flb_sds_t uri_param; + flb_sds_t full_uri; + + uri_param = flb_sds_create_size(512); + if (!uri_param) { + flb_errno(); + return NULL; + } + + /* LogGroupId */ + if (log_group_id) { + if (flb_sds_len(uri_param) > 0) { + flb_sds_cat_safe(&uri_param, "&", 1); + } + flb_sds_cat_safe(&uri_param, FLB_OCI_LOG_GROUP_ID, + FLB_OCI_LOG_GROUP_ID_SIZE); + flb_sds_cat_safe(&uri_param, "=", 1); + flb_sds_cat_safe(&uri_param, log_group_id, + flb_sds_len(log_group_id)); + } + + if (!uri_param) { + return NULL; + } + + /* logSet */ + if (log_set) { + if (flb_sds_len(uri_param) > 0) { + flb_sds_cat_safe(&uri_param, "&", 1); + } + flb_sds_cat_safe(&uri_param, FLB_OCI_LOG_SET, + FLB_OCI_LOG_SET_SIZE); + flb_sds_cat_safe(&uri_param, "=", 1); + flb_sds_cat_safe(&uri_param, log_set, + flb_sds_len(log_set)); + } + + if (!uri_param) { + return NULL; + } + + flb_sds_cat_safe(&uri_param, "&", 1); + flb_sds_cat_safe(&uri_param, FLB_OCI_PAYLOAD_TYPE, + sizeof(FLB_OCI_PAYLOAD_TYPE) - 1); + flb_sds_cat_safe(&uri_param, "=", 1); + flb_sds_cat_safe(&uri_param, "JSON", 4); + + + if (!uri_param) { + return NULL; + } + + + if (flb_sds_len(uri_param) == 0) { + flb_sds_destroy(uri_param); + return flb_sds_create(ctx->uri); + } + + full_uri = flb_sds_create_size( + flb_sds_len(ctx->uri) + 1 + flb_sds_len(uri_param)); + if (!full_uri) { + flb_errno(); + flb_sds_destroy(uri_param); + return NULL; + } + + flb_sds_cat_safe(&full_uri, ctx->uri, flb_sds_len(ctx->uri)); + flb_sds_cat_safe(&full_uri, "?", 1); + flb_sds_cat_safe(&full_uri, uri_param, flb_sds_len(uri_param)); + + flb_sds_destroy(uri_param); + + return full_uri; +} + +static int flush_to_endpoint(struct flb_oci_logan *ctx, + flb_sds_t payload, + flb_sds_t log_group_id, + flb_sds_t log_set_id) +{ + int out_ret = FLB_RETRY; + int http_ret; + size_t b_sent; + flb_sds_t full_uri; + struct flb_http_client *c = NULL; + struct flb_connection *u_conn; + + full_uri = compose_uri(ctx, log_set_id, log_group_id); + if(!full_uri) { + flb_plg_error(ctx->ins, "unable to compose uri for logGroup: %s logSet: %s", + ctx->oci_la_log_group_id, ctx->oci_la_log_set_id); + } + + flb_plg_debug(ctx->ins, "full_uri=%s", full_uri); + + u_conn = flb_upstream_conn_get(ctx->u); + if(!u_conn) { + goto error_label; + } + /* Create HTTP client context */ + c = flb_http_client(u_conn, FLB_HTTP_POST, full_uri, (void*) payload, + flb_sds_len(payload), ctx->ins->host.name, ctx->ins->host.port, ctx->proxy, 0); + if (!c) { + goto error_label; + } + flb_http_allow_duplicated_headers(c, FLB_FALSE); + + flb_plg_debug(ctx->ins, "built client"); + flb_http_buffer_size(c, FLB_HTTP_DATA_SIZE_MAX); + if (build_headers(c, ctx, payload, ctx->ins->host.name, ctx->ins->host.port, full_uri) < 0) { + flb_plg_error(ctx->ins, "failed to build headers"); + goto error_label; + } + flb_plg_debug(ctx->ins, "built request"); + + out_ret = FLB_OK; + + http_ret = flb_http_do(c, &b_sent); + flb_plg_debug(ctx->ins, "placed request"); + + if (http_ret == 0) { + + if (c->resp.status != 200) { + flb_plg_debug(ctx->ins, "request header %s", c->header_buf); + + out_ret = FLB_ERROR; + + if (c->resp.payload && c->resp.payload_size > 0) { + if (retry_error(c, ctx) == FLB_TRUE) { + out_ret = FLB_RETRY; + } + + flb_plg_error(ctx->ins, "%s:%i, retry=%s, HTTP status=%i\n%s", + ctx->ins->host.name, ctx->ins->host.port, + (out_ret == FLB_RETRY ? "true" : "false"), + c->resp.status, c->resp.payload); + } + else { + flb_plg_error(ctx->ins, "%s:%i, retry=%s, HTTP status=%i", + ctx->ins->host.name, ctx->ins->host.port, + (out_ret == FLB_RETRY ? "true" : "false"), + c->resp.status); + } + } + } + else { + out_ret = FLB_RETRY; + flb_plg_error(ctx->ins, "could not flush records to %s:%i (http_do=%i), retry=%s", + ctx->ins->host.name, ctx->ins->host.port, + http_ret, (out_ret == FLB_RETRY ? "true" : "false")); + goto error_label; + } + + + + error_label: + if (full_uri) { + flb_sds_destroy(full_uri); + } + + /* Destroy HTTP client context */ + if (c) { + flb_http_client_destroy(c); + } + + /* Release the TCP connection */ + if (u_conn) { + flb_upstream_conn_release(u_conn); + } + + return out_ret; + +} + +static void pack_oci_fields(msgpack_packer *packer, + struct flb_oci_logan *ctx) +{ + int num_global_meta = 0; + int num_event_meta = 0; + int pck_sz = 2; + struct mk_list *head = NULL; + struct metadata_obj *f; + + + /* number of meta properties */ + if(ctx->oci_la_global_metadata != NULL) { + num_global_meta = mk_list_size(&ctx->global_metadata_fields); + } + if(ctx->oci_la_metadata != NULL) { + num_event_meta = mk_list_size(&ctx->log_event_metadata_fields); + } + + + if (num_global_meta > 0) { + msgpack_pack_map(packer, 2); + msgpack_pack_str(packer, FLB_OCI_LOG_METADATA_SIZE); + msgpack_pack_str_body(packer, FLB_OCI_LOG_METADATA, + FLB_OCI_LOG_METADATA_SIZE); + + msgpack_pack_map(packer, num_global_meta); + /* pack kv list */ + mk_list_foreach(head, &ctx->global_metadata_fields) { + f = mk_list_entry(head, struct metadata_obj, _head); + + msgpack_pack_str(packer, flb_sds_len(f->key)); + msgpack_pack_str_body(packer, f->key, flb_sds_len(f->key)); + + msgpack_pack_str(packer, flb_sds_len(f->val)); + msgpack_pack_str_body(packer, f->val, flb_sds_len(f->val)); + + } + + } + else { + msgpack_pack_map(packer, 1); + } + + /* + *logEvents":[ + { + "entityId":"", + "logSourceName":"LinuxSyslogSource", + "logPath":"/var/log/messages", + "metadata":{ + "Error ID":"1", + "Environment":"prod", + "Client Host Region":"PST" + }, + "logRecords":[ + "May 8 2017 04:02:36 blr00akm syslogd 1.4.1: shutdown.", + "May 8 2017 04:02:37 blr00akm syslogd 1.4.1: restart." + ] + }, + { + + } + ] + */ + msgpack_pack_str(packer, FLB_OCI_LOG_EVENTS_SIZE); + msgpack_pack_str_body(packer, FLB_OCI_LOG_EVENTS, FLB_OCI_LOG_EVENTS_SIZE); + + msgpack_pack_array(packer, 1); + + if (ctx->oci_la_entity_id) { + pck_sz++; + } + if (ctx->oci_la_log_path) { + pck_sz++; + } + if (ctx->oci_la_entity_type) { + pck_sz++; + } + + if (num_event_meta > 0) { + pck_sz++; + } + + msgpack_pack_map(packer, pck_sz); /* entityId, logSourceName, logPath, logRecords */ + + + /* "entityType:"" */ + if (ctx->oci_la_entity_type) { + msgpack_pack_str(packer, FLB_OCI_ENTITY_TYPE_SIZE); + msgpack_pack_str_body(packer, FLB_OCI_ENTITY_TYPE, FLB_OCI_ENTITY_TYPE_SIZE); + msgpack_pack_str(packer, flb_sds_len(ctx->oci_la_entity_type)); + msgpack_pack_str_body(packer, ctx->oci_la_entity_type, + flb_sds_len(ctx->oci_la_entity_type)); + } + + /* "entityId":"", */ + if (ctx->oci_la_entity_id) { + msgpack_pack_str(packer, FLB_OCI_ENTITY_ID_SIZE); + msgpack_pack_str_body(packer, FLB_OCI_ENTITY_ID, FLB_OCI_ENTITY_ID_SIZE); + msgpack_pack_str(packer, flb_sds_len(ctx->oci_la_entity_id)); + msgpack_pack_str_body(packer, ctx->oci_la_entity_id, + flb_sds_len(ctx->oci_la_entity_id)); + } + + + /* "logSourceName":"", */ + msgpack_pack_str(packer, FLB_OCI_LOG_SOURCE_NAME_SIZE); + msgpack_pack_str_body(packer, FLB_OCI_LOG_SOURCE_NAME, + FLB_OCI_LOG_SOURCE_NAME_SIZE); + msgpack_pack_str(packer, flb_sds_len(ctx->oci_la_log_source_name)); + msgpack_pack_str_body(packer, ctx->oci_la_log_source_name, + flb_sds_len(ctx->oci_la_log_source_name)); + + + /* "logPath":"" */ + if (ctx->oci_la_log_path) { + msgpack_pack_str(packer, FLB_OCI_LOG_PATH_SIZE); + msgpack_pack_str_body(packer, FLB_OCI_LOG_PATH, FLB_OCI_LOG_PATH_SIZE); + msgpack_pack_str(packer, flb_sds_len(ctx->oci_la_log_path)); + msgpack_pack_str_body(packer, ctx->oci_la_log_path, + flb_sds_len(ctx->oci_la_log_path)); + } + + + /* Add metadata */ + if (num_event_meta > 0) { + /* + "metadata":{ + "Error ID":"0", + "Environment":"dev", + "Client Host Region":"IST" + }, + */ + msgpack_pack_str(packer, FLB_OCI_LOG_METADATA_SIZE); + msgpack_pack_str_body(packer, FLB_OCI_LOG_METADATA, + FLB_OCI_LOG_METADATA_SIZE); + + msgpack_pack_map(packer, num_event_meta); + /* pack kv list */ + mk_list_foreach(head, &ctx->log_event_metadata_fields) { + f = mk_list_entry(head, struct metadata_obj, _head); + + msgpack_pack_str(packer, flb_sds_len(f->key)); + msgpack_pack_str_body(packer, f->key, flb_sds_len(f->key)); + + msgpack_pack_str(packer, flb_sds_len(f->val)); + msgpack_pack_str_body(packer, f->val, flb_sds_len(f->val)); + + } + + } +} + +static int get_and_pack_oci_fields_from_record(msgpack_packer *packer, + msgpack_object map, + flb_sds_t *lg_id, + flb_sds_t *ls_id, + struct flb_oci_logan *ctx) +{ + int map_size = map.via.map.size; + int pck_size = 1, i; + msgpack_object *log_group_id= NULL; + msgpack_object *log_set_id = NULL; + msgpack_object *entity_id = NULL; + msgpack_object *entity_type = NULL; + msgpack_object *log_path = NULL; + msgpack_object *log_source = NULL; + msgpack_object *global_metadata = NULL; + msgpack_object *metadata = NULL; + + for(i = 0; i < map_size; i++) { + if (check_config_from_record(map.via.map.ptr[i].key, + FLB_OCI_LOG_GROUP_ID_KEY, + FLB_OCI_LOG_GROUP_ID_KEY_SIZE) == FLB_TRUE) { + if (map.via.map.ptr[i].val.type == MSGPACK_OBJECT_STR) { + log_group_id = &map.via.map.ptr[i].val; + } + continue; + } + else if (check_config_from_record(map.via.map.ptr[i].key, + FLB_OCI_LOG_SET_ID_KEY, + FLB_OCI_LOG_SET_ID_KEY_SIZE) == FLB_TRUE) { + if (map.via.map.ptr[i].val.type == MSGPACK_OBJECT_STR) { + log_set_id = &map.via.map.ptr[i].val; + } + continue; + } + else if (check_config_from_record(map.via.map.ptr[i].key, + FLB_OCI_LOG_ENTITY_ID_KEY, + FLB_OCI_LOG_ENTITY_ID_KEY_SIZE) == FLB_TRUE) { + if (map.via.map.ptr[i].val.type == MSGPACK_OBJECT_STR) { + entity_id = &map.via.map.ptr[i].val; + pck_size++; + } + continue; + } + else if (check_config_from_record(map.via.map.ptr[i].key, + FLB_OCI_LOG_ENTITY_TYPE_KEY, + FLB_OCI_LOG_ENTITY_TYPE_KEY_SIZE) == FLB_TRUE) { + if (map.via.map.ptr[i].val.type == MSGPACK_OBJECT_STR) { + entity_type = &map.via.map.ptr[i].val; + pck_size++; + } + continue; + } + else if (check_config_from_record(map.via.map.ptr[i].key, + FLB_OCI_LOG_SOURCE_NAME_KEY, + FLB_OCI_LOG_SOURCE_NAME_KEY_SIZE) == FLB_TRUE) { + if (map.via.map.ptr[i].val.type == MSGPACK_OBJECT_STR) { + log_source = &map.via.map.ptr[i].val; + pck_size++; + } + continue; + } + else if (check_config_from_record(map.via.map.ptr[i].key, + FLB_OCI_LOG_PATH_KEY, + FLB_OCI_LOG_PATH_KEY_SIZE) == FLB_TRUE) { + if (map.via.map.ptr[i].val.type == MSGPACK_OBJECT_STR) { + log_path = &map.via.map.ptr[i].val; + pck_size++; + } + continue; + } + else if (check_config_from_record(map.via.map.ptr[i].key, + FLB_OCI_METADATA_KEY, + FLB_OCI_METADATA_KEY_SIZE) == FLB_TRUE) { + if (map.via.map.ptr[i].val.type == MSGPACK_OBJECT_STR) { + metadata = &map.via.map.ptr[i].val; + pck_size++; + } + continue; + } + else if (check_config_from_record(map.via.map.ptr[i].key, + FLB_OCI_GLOBAL_METADATA_KEY, + FLB_OCI_GLOBAL_METADATA_KEY_SIZE) == FLB_TRUE) { + if (map.via.map.ptr[i].val.type == MSGPACK_OBJECT_STR) { + global_metadata = &map.via.map.ptr[i].val; + } + continue; + } + } + + if (log_group_id == NULL || log_source == NULL) { + flb_plg_error(ctx->ins, + "log source name and log group id are required"); + return -1; + } + if (global_metadata != NULL) { + msgpack_pack_map(packer, 2); + msgpack_pack_str(packer, FLB_OCI_LOG_METADATA_SIZE); + msgpack_pack_str_body(packer, FLB_OCI_LOG_METADATA, + FLB_OCI_LOG_METADATA_SIZE); + + msgpack_pack_object(packer, *global_metadata); + } + else { + msgpack_pack_map(packer, 1); + } + + /* + *logEvents":[ + { + "entityId":"", + "logSourceName":"LinuxSyslogSource", + "logPath":"/var/log/messages", + "metadata":{ + "Error ID":"1", + "Environment":"prod", + "Client Host Region":"PST" + }, + "logRecords":[ + "May 8 2017 04:02:36 blr00akm syslogd 1.4.1: shutdown.", + "May 8 2017 04:02:37 blr00akm syslogd 1.4.1: restart." + ] + }, + { + + } + ] + */ + msgpack_pack_str(packer, FLB_OCI_LOG_EVENTS_SIZE); + msgpack_pack_str_body(packer, FLB_OCI_LOG_EVENTS, FLB_OCI_LOG_EVENTS_SIZE); + + msgpack_pack_array(packer, 1); + + if (metadata != NULL) { + pck_size++; + msgpack_pack_map(packer, pck_size); /* entityType, entityId, logSourceName, logPath, metadata, logRecords */ + msgpack_pack_str(packer, FLB_OCI_LOG_METADATA_SIZE); + msgpack_pack_str_body(packer, FLB_OCI_LOG_METADATA, + FLB_OCI_LOG_METADATA_SIZE); + msgpack_pack_object(packer, *global_metadata); + + } + else { + msgpack_pack_map(packer, pck_size); /* entityType, entityId, logSourceName, logPath, logRecords */ + } + + /* "entityType:"" */ + if (entity_type) { + msgpack_pack_str(packer, FLB_OCI_ENTITY_TYPE_SIZE); + msgpack_pack_str_body(packer, FLB_OCI_ENTITY_TYPE, FLB_OCI_ENTITY_TYPE_SIZE); + msgpack_pack_object(packer, *entity_type); + } + + /* "entityId":"", */ + if (entity_type) { + msgpack_pack_str(packer, FLB_OCI_ENTITY_ID_SIZE); + msgpack_pack_str_body(packer, FLB_OCI_ENTITY_ID, FLB_OCI_ENTITY_ID_SIZE); + msgpack_pack_object(packer, *entity_id); + } + + + + /* "logSourceName":"", */ + msgpack_pack_str(packer, FLB_OCI_LOG_SOURCE_NAME_SIZE); + msgpack_pack_str_body(packer, FLB_OCI_LOG_SOURCE_NAME, + FLB_OCI_LOG_SOURCE_NAME_SIZE); + msgpack_pack_object(packer, *log_source); + + + /* "logPath":"" */ + if (log_path) { + msgpack_pack_str(packer, FLB_OCI_LOG_PATH_SIZE); + msgpack_pack_str_body(packer, FLB_OCI_LOG_PATH, FLB_OCI_LOG_PATH_SIZE); + msgpack_pack_object(packer, *log_path); + } + + *lg_id = flb_sds_create_len(log_group_id->via.str.ptr, log_group_id->via.str.size); + if(!*lg_id) { + return -1; + } + if (log_set_id != NULL) { + *ls_id = flb_sds_create_len(log_set_id->via.str.ptr, log_set_id->via.str.size); + if(!*ls_id) { + return -1; + } + } + return 0; + +} + +static int total_flush(struct flb_event_chunk *event_chunk, + struct flb_output_flush *out_flush, + struct flb_input_instance *ins, void *out_context, + struct flb_config *config) +{ + struct flb_oci_logan *ctx = out_context; + flb_sds_t out_buf = NULL; + int ret = 0, res = FLB_OK, ret1 = 0, i; + msgpack_object map; + int map_size; + msgpack_sbuffer mp_sbuf; + msgpack_packer mp_pck; + int msg = -1, log = -1; + struct flb_log_event_decoder log_decoder; + struct flb_log_event log_event; + int num_records; + flb_sds_t log_group_id = NULL; + flb_sds_t log_set_id = NULL; + int count = 0; + + ret = flb_log_event_decoder_init(&log_decoder, (char *) event_chunk->data, event_chunk->size); + + if (ret != FLB_EVENT_DECODER_SUCCESS) { + flb_plg_error(ctx->ins, + "Log event decoder initialization error : %d", ret); + res = FLB_ERROR; + goto clean_up; + } + + /* Create temporary msgpack buffer */ + msgpack_sbuffer_init(&mp_sbuf); + msgpack_packer_init(&mp_pck, &mp_sbuf, msgpack_sbuffer_write); + + /* pack oci fields */ + /* pack_oci_fields(&mp_pck, ctx); */ + + num_records = flb_mp_count(event_chunk->data, event_chunk->size); + + while ((ret = flb_log_event_decoder_next( + &log_decoder, + &log_event)) == FLB_EVENT_DECODER_SUCCESS) { + map = *log_event.body; + map_size = map.via.map.size; + if (count < 1) { + if (ctx->oci_config_in_record == FLB_FALSE) { + pack_oci_fields(&mp_pck, ctx); + log_group_id = ctx->oci_la_log_group_id; + log_set_id = ctx->oci_la_log_set_id; + } else { + ret1 = get_and_pack_oci_fields_from_record(&mp_pck, map, &log_group_id, &log_set_id, ctx); + if (ret1 != 0) { + break; + } + } + msgpack_pack_str(&mp_pck, FLB_OCI_LOG_RECORDS_SIZE); + msgpack_pack_str_body(&mp_pck, FLB_OCI_LOG_RECORDS, + FLB_OCI_LOG_RECORDS_SIZE); + msgpack_pack_array(&mp_pck, num_records); + count++; + } + + for(i = 0; i < map_size; i++) { + if (check_config_from_record(map.via.map.ptr[i].key, + "message", + 7) == FLB_TRUE) { + msg = i; + } + if (check_config_from_record(map.via.map.ptr[i].key, + "log", + 3) == FLB_TRUE) { + log = i; + } + } + if (log >= 0) { + msgpack_pack_str(&mp_pck, map.via.map.ptr[log].val.via.str.size); + msgpack_pack_str_body(&mp_pck, map.via.map.ptr[log].val.via.str.ptr, + map.via.map.ptr[log].val.via.str.size); + } + else if (msg >= 0) { + msgpack_pack_str(&mp_pck, map.via.map.ptr[msg].val.via.str.size); + msgpack_pack_str_body(&mp_pck, map.via.map.ptr[msg].val.via.str.ptr, + map.via.map.ptr[msg].val.via.str.size); + } + log = -1; + msg = -1; + } + + if (ret1 != 0) { + res = FLB_ERROR; + msgpack_sbuffer_destroy(&mp_sbuf); + flb_log_event_decoder_destroy(&log_decoder); + goto clean_up; + } + + out_buf = flb_msgpack_raw_to_json_sds(mp_sbuf.data, mp_sbuf.size); + msgpack_sbuffer_destroy(&mp_sbuf); + flb_log_event_decoder_destroy(&log_decoder); + + flb_plg_debug(ctx->ins, "payload=%s", out_buf); + flb_plg_debug(ctx->ins, "lg_id=%s", log_group_id); + + ret = flush_to_endpoint(ctx, out_buf, log_group_id, log_set_id); + if(ret != FLB_OK) { + res = FLB_RETRY; + goto clean_up; + } + + clean_up: + if (out_buf != NULL) { + flb_sds_destroy(out_buf); + } + if (log_group_id != NULL && ctx->oci_config_in_record) { + flb_sds_destroy(log_group_id); + } + if (log_set_id != NULL && ctx->oci_config_in_record) { + flb_sds_destroy(log_set_id); + } + return res; +} + +static void cb_oci_logan_flush(struct flb_event_chunk *event_chunk, + struct flb_output_flush *out_flush, + struct flb_input_instance *ins, void *out_context, + struct flb_config *config) +{ + struct flb_oci_logan *ctx = out_context; + int ret = -1; + + ret = total_flush(event_chunk, out_flush, + ins, out_context, + config); + if (ret != FLB_OK) { + flb_oci_logan_conf_destroy(ctx); + FLB_OUTPUT_RETURN(ret); + } + flb_plg_debug(ctx->ins, "success"); + + FLB_OUTPUT_RETURN(FLB_OK); + +} + +static int cb_oci_logan_exit(void *data, struct flb_config *config) +{ + struct flb_oci_logan *ctx = data; + + flb_oci_logan_conf_destroy(ctx); + return 0; +} + +/* Configuration properties map */ +static struct flb_config_map config_map[] = { + { + FLB_CONFIG_MAP_STR, "config_file_location", "", + 0, FLB_TRUE, offsetof(struct flb_oci_logan, config_file_location), + "Location of the oci config file for user api key signing" + }, + { + FLB_CONFIG_MAP_STR, "profile_name", "DEFAULT", + 0, FLB_TRUE, offsetof(struct flb_oci_logan, profile_name), + "name of the profile in the config file from which the user configs should be loaded" + }, + { + FLB_CONFIG_MAP_BOOL, "oci_config_in_record", "false", + 0, FLB_TRUE, offsetof(struct flb_oci_logan, oci_config_in_record), + "If true, oci_la_* configs will be read from the record" + }, + { + FLB_CONFIG_MAP_STR, "uri", NULL, + 0, FLB_TRUE, offsetof(struct flb_oci_logan, uri), + "Set the uri for rest api request" + }, + { + FLB_CONFIG_MAP_STR, "oci_la_log_group_id", NULL, + 0, FLB_TRUE, offsetof(struct flb_oci_logan, oci_la_log_group_id), + "log group id" + }, + { + FLB_CONFIG_MAP_STR, "oci_la_log_set_id", NULL, + 0, FLB_TRUE, offsetof(struct flb_oci_logan, oci_la_log_set_id), + "" + }, + { + FLB_CONFIG_MAP_STR, "oci_la_entity_id", NULL, + 0, FLB_TRUE, offsetof(struct flb_oci_logan, oci_la_entity_id), + "" + }, + { + FLB_CONFIG_MAP_STR, "oci_la_entity_type", NULL, + 0, FLB_TRUE, offsetof(struct flb_oci_logan, oci_la_entity_type), + "" + }, + { + FLB_CONFIG_MAP_STR, "oci_la_log_source_name", NULL, + 0, FLB_TRUE, offsetof(struct flb_oci_logan, oci_la_log_source_name), + "" + }, + { + FLB_CONFIG_MAP_STR, "oci_la_log_set_id", NULL, + 0, FLB_TRUE, offsetof(struct flb_oci_logan, oci_la_log_set_id), + "" + }, + { + FLB_CONFIG_MAP_STR, "oci_la_log_path", NULL, + 0, FLB_TRUE, offsetof(struct flb_oci_logan, oci_la_log_path), + "" + }, + { + FLB_CONFIG_MAP_SLIST_2, "oci_la_global_metadata", NULL, + FLB_CONFIG_MAP_MULT, FLB_TRUE, offsetof(struct flb_oci_logan, oci_la_global_metadata), + "" + }, + { + FLB_CONFIG_MAP_SLIST_2, "oci_la_metadata", NULL, + FLB_CONFIG_MAP_MULT, FLB_TRUE, offsetof(struct flb_oci_logan, oci_la_metadata), + "" + }, + { + FLB_CONFIG_MAP_STR, "namespace", NULL, + 0, FLB_TRUE, offsetof(struct flb_oci_logan, namespace), + "namespace in your tenancy where the log objects reside" + }, + { + FLB_CONFIG_MAP_STR, "proxy", NULL, + 0, FLB_TRUE, offsetof(struct flb_oci_logan, proxy), + "define proxy if required, in http://host:port format, supports only http protocol" + }, + + {0} +}; + +/* Plugin reference */ +struct flb_output_plugin out_oracle_log_analytics_plugin = { + .name = "oracle_log_analytics", + .description = "Oracle log analytics", + .cb_init = cb_oci_logan_init, + .cb_pre_run = NULL, + .cb_flush = cb_oci_logan_flush, + .cb_exit = cb_oci_logan_exit, + + /* Configuration */ + .config_map = config_map, + + /* Events supported */ + .event_type = FLB_OUTPUT_LOGS, + + + /* Plugin flags */ + .flags = FLB_OUTPUT_NET | FLB_IO_OPT_TLS, + .workers = 1, +}; diff --git a/plugins/out_oracle_log_analytics/oci_logan.h b/plugins/out_oracle_log_analytics/oci_logan.h new file mode 100644 index 00000000000..7cc9e75f4a1 --- /dev/null +++ b/plugins/out_oracle_log_analytics/oci_logan.h @@ -0,0 +1,215 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Fluent Bit + * ========== + * Copyright (C) 2015-2023 The Fluent Bit Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef FLB_OUT_OCI_LOGAN_H +#define FLB_OUT_OCI_LOGAN_H + +#define FLB_OCI_LOG_ENTITY_ID_KEY "oci_la_entity_id" +#define FLB_OCI_LOG_ENTITY_ID_KEY_SIZE sizeof(FLB_OCI_LOG_ENTITY_ID_KEY) - 1 + +#define FLB_OCI_LOG_ENTITY_TYPE_KEY "oci_la_entity_type" +#define FLB_OCI_LOG_ENTITY_TYPE_KEY_SIZE sizeof(FLB_OCI_LOG_ENTITY_TYPE_KEY) - 1 + +#define FLB_OCI_LOG_GROUP_ID_KEY "oci_la_log_group_id" +#define FLB_OCI_LOG_GROUP_ID_KEY_SIZE sizeof(FLB_OCI_LOG_GROUP_ID_KEY) - 1 + +#define FLB_OCI_LOG_SET_ID_KEY "oci_la_log_set_id" +#define FLB_OCI_LOG_SET_ID_KEY_SIZE sizeof(FLB_OCI_LOG_SET_ID_KEY) - 1 + +#define FLB_OCI_LOG_SOURCE_NAME_KEY "oci_la_log_source_name" +#define FLB_OCI_LOG_SOURCE_NAME_KEY_SIZE sizeof(FLB_OCI_LOG_SOURCE_NAME_KEY) - 1 + +#define FLB_OCI_LOG_PATH_KEY "oci_la_log_path" +#define FLB_OCI_LOG_PATH_KEY_SIZE sizeof(FLB_OCI_LOG_PATH_KEY) - 1 + +#define FLB_OCI_METADATA_KEY "oci_la_metadata" +#define FLB_OCI_METADATA_KEY_SIZE sizeof(FLB_OCI_METADATA_KEY) - 1 + +#define FLB_OCI_GLOBAL_METADATA_KEY "oci_la_global_metadata" +#define FLB_OCI_GLOBAL_METADATA_KEY_SIZE sizeof(FLB_OCI_GLOBAL_METADATA_KEY) - 1 + +#define FLB_OCI_LOG_EVENTS "logEvents" +#define FLB_OCI_LOG_EVENTS_SIZE sizeof(FLB_OCI_LOG_EVENTS)-1 + +#define FLB_OCI_LOG_RECORDS "logRecords" +#define FLB_OCI_LOG_RECORDS_SIZE sizeof(FLB_OCI_LOG_RECORDS)-1 + +#define FLB_OCI_LOG_GROUP_ID "logGroupId" +#define FLB_OCI_LOG_GROUP_ID_SIZE sizeof(FLB_OCI_LOG_GROUP_ID)-1 + +#define FLB_OCI_ENTITY_TYPE "entityType" +#define FLB_OCI_ENTITY_TYPE_SIZE sizeof(FLB_OCI_ENTITY_TYPE) - 1 + +#define FLB_OCI_LOG_SET "logSet" +#define FLB_OCI_LOG_SET_SIZE sizeof(FLB_OCI_LOG_SET)-1 + +#define FLB_OCI_LOG_METADATA "metadata" +#define FLB_OCI_LOG_METADATA_SIZE sizeof(FLB_OCI_LOG_METADATA)-1 + +#define FLB_OCI_ENTITY_ID "entityId" +#define FLB_OCI_ENTITY_ID_SIZE sizeof(FLB_OCI_ENTITY_ID)-1 + +#define FLB_OCI_LOG_SOURCE_NAME "logSourceName" +#define FLB_OCI_LOG_SOURCE_NAME_SIZE sizeof(FLB_OCI_LOG_SOURCE_NAME)-1 + +#define FLB_OCI_LOG_PATH "logPath" +#define FLB_OCI_LOG_PATH_SIZE sizeof(FLB_OCI_LOG_PATH)-1 + +#define FLB_OCI_META_PREFIX "metadata_" +#define FLB_OCI_META_PREFIX_SIZE sizeof(FLB_OCI_META_PREFIX)-1 + +#define FLB_OCI_MATCH_PREFIX "oci_match_" +#define FLB_OCI_MATCH_PREFIX_SIZE sizeof(FLB_OCI_MATCH_PREFIX)-1 + +#ifdef FLB_HAVE_REGEX +#define FLB_OCI_MATCH_REGEX_PREFIX "oci_match_regex_" +#define FLB_OCI_MATCH_REGEX_PREFIX_SIZE sizeof(FLB_OCI_MATCH_REGEX_PREFIX)-1 +#endif + +/* Params */ +#define FLB_OCI_PARAM_SKIP_HTTP_POST "skip_http_post" +#define FLB_OCI_PARAM_URI "uri" +#define FLB_OCI_PARAM_ENABLE_TRACE_OUTPUT "enable_trace" +#define FLB_OCI_PARAM_TRACE_OUTPUT_PATH "trace_file_path" +#define FLB_OCI_PARAM_TRACE_OUTPUT_FILE "trace_file_name" +#define FLB_OCI_PARAM_COLLECT_TIME_FIELD "collect_time_field_name" + +#define FLB_OCI_PARAM_USE_RAW_RECORD "use_raw_record" +#define FLB_OCI_PARAM_USE_RAW_RECORD_SIZE sizeof(FLB_OCI_PARAM_USE_RAW_RECORD)-1 + +#define FLB_OCI_PARAM_INCLUDE_COLLECT_TIME "include_collect_time" +#define FLB_OCI_PARAM_INCLUDE_COLLECT_TIME_SIZE sizeof(FLB_OCI_PARAM_INCLUDE_COLLECT_TIME)-1 + +#define FLB_OCI_MATCH_ID_MAX 1000 // TO avoid too large memory allocation + +#define FLB_OCI_DEFAULT_COLLECT_TIME "oci_collect_time" +#define FLB_OCI_DEFAULT_COLLECT_TIME_SIZE sizeof(FLB_OCI_DEFAULT_COLLECT_TIME)-1 + +/* Http Header */ +#define FLB_OCI_HEADER_REQUEST_TARGET "(request-target)" +#define FLB_OCI_HEADER_USER_AGENT "User-Agent" +#define FLB_OCI_HEADER_USER_AGENT_VAL "Fluent-Bit" +#define FLB_OCI_HEADER_CONTENT_TYPE "content-type" +#define FLB_OCI_HEADER_CONTENT_TYPE_VAL "application/octet-stream" +#define FLB_OCI_HEADER_X_CONTENT_SHA256 "x-content-sha256" +#define FLB_OCI_HEADER_CONTENT_LENGTH "content-length" +#define FLB_OCI_HEADER_HOST "host" +#define FLB_OCI_HEADER_DATE "date" +#define FLB_OCI_HEADER_AUTH "Authorization" +#define FLB_OCI_PAYLOAD_TYPE "payloadType" + + +/* For OCI signing */ +#define FLB_OCI_PARAM_TENANCY "tenancy" +#define FLB_OCI_PARAM_USER "user" +#define FLB_OCI_PARAM_KEY_FINGERPRINT "fingerprint" +#define FLB_OCI_PARAM_KEY_FILE "key_file" +#define FLB_OCI_PARAM_REGION "region" +#define FLB_OCI_PARAM_KEY_FILE_PASSPHRASE "key_file_passphrase" + +#define FLB_OCI_SIGN_SIGNATURE_VERSION "Signature version=\"1\"" +#define FLB_OCI_SIGN_KEYID "keyId" +#define FLB_OCI_SIGN_ALGORITHM "algorithm=\"rsa-sha256\"" + +#define FLB_OCI_SIGN_HEADERS "headers=\"" \ + FLB_OCI_HEADER_REQUEST_TARGET " " \ + FLB_OCI_HEADER_HOST " " \ + FLB_OCI_HEADER_DATE " " \ + FLB_OCI_HEADER_X_CONTENT_SHA256 " " \ + FLB_OCI_HEADER_CONTENT_TYPE " " \ + FLB_OCI_HEADER_CONTENT_LENGTH "\"" + +#define FLB_OCI_SIGN_SIGNATURE "signature" + +/* For error response */ +#define FLB_OCI_ERROR_RESPONSE_CODE "code" +#define FLB_OCI_ERROR_RESPONSE_MESSAGE "message" + +#define FLB_OCI_ERROR_CODE_RELATED_RESOURCE_NOT_FOUND "RelatedResourceNotAuthorizedOrNotFound" +#define FLB_OCI_ERROR_CODE_NOT_AUTHENTICATED "NotAuthenticated" +#define FLB_OCI_ERROR_CODE_NOT_AUTHENTICATEDORNOTFOUND "NotAuthorizedOrNotFound" +#define FLB_OCI_ERROR_CODE_INCORRECTSTATE "IncorrectState" +#define FLB_OCI_ERROR_CODE_NOT_AUTH_OR_RESOURCE_EXIST "NotAuthorizedOrResourceAlreadyExists" +#define FLB_OCI_ERROR_CODE_TOO_MANY_REQUESTS "TooManyRequests" +#define FLB_OCI_ERROR_CODE_INTERNAL_SERVER_ERROR "InternalServerError" + +#include +#include +#include +#include +#include + +struct metadata_obj { + flb_sds_t key; + flb_sds_t val; + struct mk_list _head; + +}; + +struct flb_oci_error_response +{ + flb_sds_t code; + flb_sds_t message; +}; + +struct flb_oci_logan { + flb_sds_t namespace; + flb_sds_t config_file_location; + flb_sds_t profile_name; + int oci_config_in_record; + flb_sds_t uri; + + struct flb_upstream *u; + flb_sds_t proxy; + char *proxy_host; + int proxy_port; + + // oci_la_* configs + flb_sds_t oci_la_entity_id; + + flb_sds_t oci_la_entity_type; + + flb_sds_t oci_la_log_source_name; + + flb_sds_t oci_la_log_path; + + flb_sds_t oci_la_log_group_id; + + flb_sds_t oci_la_log_set_id; + + struct mk_list *oci_la_global_metadata; + struct mk_list global_metadata_fields; + struct mk_list *oci_la_metadata; + struct mk_list log_event_metadata_fields; + + // config_file + flb_sds_t user; + flb_sds_t region; + flb_sds_t tenancy; + flb_sds_t key_fingerprint; + flb_sds_t key_file; + /* For OCI signing */ + flb_sds_t key_id; // tenancy/user/key_fingerprint + flb_sds_t private_key; + + struct flb_output_instance *ins; + +}; +#endif diff --git a/plugins/out_oracle_log_analytics/oci_logan_conf.c b/plugins/out_oracle_log_analytics/oci_logan_conf.c new file mode 100644 index 00000000000..a3980318465 --- /dev/null +++ b/plugins/out_oracle_log_analytics/oci_logan_conf.c @@ -0,0 +1,493 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Fluent Bit + * ========== + * Copyright (C) 2015-2023 The Fluent Bit Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "oci_logan.h" +#include "oci_logan_conf.h" + +static int create_pk_context(flb_sds_t filepath, const char *key_passphrase, + struct flb_oci_logan *ctx) +{ + int ret; + struct stat st; + struct file_info finfo; + FILE *fp; + flb_sds_t kbuffer; + + + ret = stat(filepath, &st); + if (ret == -1) { + flb_errno(); + flb_plg_error(ctx->ins, "cannot open key file %s", filepath); + return -1; + } + + if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) { + flb_plg_error(ctx->ins, "key file is not a valid file: %s", filepath); + return -1; + } + + /* Read file content */ + if (mk_file_get_info(filepath, &finfo, MK_FILE_READ) != 0) { + flb_plg_error(ctx->ins, "error to read key file: %s", filepath); + return -1; + } + + if (!(fp = fopen(filepath, "rb"))) { + flb_plg_error(ctx->ins, "error to open key file: %s", filepath); + return -1; + } + + kbuffer = flb_sds_create_size(finfo.size + 1); + if (!kbuffer) { + flb_errno(); + fclose(fp); + return -1; + } + + ret = fread(kbuffer, finfo.size, 1, fp); + if (ret < 1) { + flb_sds_destroy(kbuffer); + fclose(fp); + flb_plg_error(ctx->ins, "fail to read key file: %s", filepath); + return -1; + } + fclose(fp); + + /* In mbedtls, for PEM, the buffer must contains a null-terminated string */ + kbuffer[finfo.size] = '\0'; + flb_sds_len_set(kbuffer, finfo.size + 1); + + ctx->private_key = kbuffer; + + return 0; +} + +static int load_oci_credentials(struct flb_oci_logan *ctx) +{ + flb_sds_t content; + int found_profile = 0, res = 0; + char *line, *profile = NULL; + int eq_pos = 0; + char* key = NULL; + char* val; + + content = flb_file_read(ctx->config_file_location); + if (content == NULL || flb_sds_len(content) == 0) + { + return -1; + } + flb_plg_debug(ctx->ins, "content = %s", content); + line = strtok(content, "\n"); + while(line != NULL) { + /* process line */ + flb_plg_debug(ctx->ins, "line = %s", line); + if(!found_profile && line[0] == '[') { + profile = mk_string_copy_substr(line, 1, strlen(line) - 1); + if(!strcmp(profile, ctx->profile_name)) { + flb_plg_info(ctx->ins, "found profile"); + found_profile = 1; + goto iterate; + } + mk_mem_free(profile); + } + if(found_profile) { + if(line[0] == '[') { + break; + } + eq_pos = mk_string_char_search(line, '=', strlen(line)); + flb_plg_debug(ctx->ins, "eq_pos %d", eq_pos); + key = mk_string_copy_substr(line, 0, eq_pos); + flb_plg_debug(ctx->ins, "key = %s", key); + val = line + eq_pos + 1; + if (!key || !val) { + res = -1; + break; + } + if (strcmp(key, FLB_OCI_PARAM_USER) == 0) { + ctx->user = flb_sds_create(val); + } + else if (strcmp(key, FLB_OCI_PARAM_TENANCY) == 0) { + ctx->tenancy = flb_sds_create(val); + } + else if (strcmp(key, FLB_OCI_PARAM_KEY_FILE) == 0) { + ctx->key_file = flb_sds_create(val); + } + else if (strcmp(key, FLB_OCI_PARAM_KEY_FINGERPRINT) == 0) { + ctx->key_fingerprint = flb_sds_create(val); + } + else if (strcmp(key, FLB_OCI_PARAM_REGION) == 0) { + ctx->region = flb_sds_create(val); + } + else { + goto iterate; + } + } + iterate: + if (profile) { + mk_mem_free(profile); + profile = NULL; + } + if (key) { + mk_mem_free(key); + key = NULL; + } + line = strtok(NULL, "\n"); + } + if (!found_profile) { + flb_errno(); + res = -1; + } + + flb_sds_destroy(content); + if (profile) { + mk_mem_free(profile); + } + if (key) { + mk_mem_free(key); + } + return res; +} + +static int global_metadata_fields_create(struct flb_oci_logan *ctx) +{ + struct mk_list *head; + struct flb_slist_entry *kname; + struct flb_slist_entry *val; + struct flb_config_map_val *mv; + struct metadata_obj *f; + + if (!ctx->oci_la_global_metadata) { + return 0; + } + + flb_config_map_foreach(head, mv, ctx->oci_la_global_metadata) { + kname = mk_list_entry_first(mv->val.list, struct flb_slist_entry, _head); + val = mk_list_entry_last(mv->val.list, struct flb_slist_entry, _head); + + f = flb_malloc(sizeof(struct metadata_obj)); + if (!f) { + flb_errno(); + return -1; + } + + f->key = flb_sds_create(kname->str); + if (!f->key) { + flb_free(f); + return -1; + } + f->val = flb_sds_create(val->str); + if (!f->val) { + flb_free(f); + return -1; + } + + + mk_list_add(&f->_head, &ctx->global_metadata_fields); + } + + return 0; +} + +static int log_event_metadata_create(struct flb_oci_logan *ctx) +{ + struct mk_list *head; + struct flb_slist_entry *kname; + struct flb_slist_entry *val; + struct flb_config_map_val *mv; + struct metadata_obj *f; + + if (!ctx->oci_la_metadata) { + return 0; + } + + flb_config_map_foreach(head, mv, ctx->oci_la_metadata) { + kname = mk_list_entry_first(mv->val.list, struct flb_slist_entry, _head); + val = mk_list_entry_last(mv->val.list, struct flb_slist_entry, _head); + + f = flb_malloc(sizeof(struct metadata_obj)); + if (!f) { + flb_errno(); + return -1; + } + + f->key = flb_sds_create(kname->str); + if (!f->key) { + flb_free(f); + return -1; + } + f->val = flb_sds_create(val->str); + if (!f->val) { + flb_free(f); + return -1; + } + + + mk_list_add(&f->_head, &ctx->log_event_metadata_fields); + } + + return 0; +} +struct flb_oci_logan *flb_oci_logan_conf_create(struct flb_output_instance *ins, + struct flb_config *config) { + struct flb_oci_logan *ctx; + struct flb_upstream *upstream; + flb_sds_t host = NULL; + int io_flags = 0, default_port; + const char *tmp; + int ret = 0; + char *protocol = NULL; + char *p_host = NULL; + char *p_port = NULL; + char *p_uri = NULL; + + ctx = flb_calloc(1, sizeof(struct flb_oci_logan)); + if (!ctx) { + flb_errno(); + return NULL; + } + + ctx->ins = ins; + + ret = flb_output_config_map_set(ins, (void *) ctx); + if (ret == -1) { + flb_plg_error(ctx->ins, "configuration error"); + flb_oci_logan_conf_destroy(ctx); + return NULL; + } + + if (ctx->oci_config_in_record == FLB_FALSE) { + if (ctx->oci_la_log_source_name == NULL || + ctx->oci_la_log_group_id == NULL) { + flb_errno(); + flb_plg_error(ctx->ins, + "log source name and log group id are required"); + flb_oci_logan_conf_destroy(ctx); + return NULL; + } + } + if (ctx->oci_la_global_metadata != NULL) { + mk_list_init(&ctx->global_metadata_fields); + ret = global_metadata_fields_create(ctx); + if (ret != 0) { + flb_errno(); + flb_oci_logan_conf_destroy(ctx); + return NULL; + } + } + + if (ctx->oci_la_metadata != NULL) { + mk_list_init(&ctx->log_event_metadata_fields); + ret = log_event_metadata_create(ctx); + if (ret != 0) { + flb_errno(); + flb_oci_logan_conf_destroy(ctx); + return NULL; + } + } + + if (!ctx->config_file_location) { + flb_errno(); + flb_plg_error(ctx->ins, "config file location is required"); + flb_oci_logan_conf_destroy(ctx); + return NULL; + } + + ret = load_oci_credentials(ctx); + if(ret != 0) { + flb_errno(); + flb_oci_logan_conf_destroy(ctx); + return NULL; + } + + if (ins->host.name) { + host = ins->host.name; + } + else { + if (!ctx->region) { + flb_errno(); + flb_plg_error(ctx->ins, "Region is required"); + flb_oci_logan_conf_destroy(ctx); + return NULL; + } + host = flb_sds_create_size(512); + flb_sds_snprintf(&host, flb_sds_alloc(host), "loganalytics.%s.oci.oraclecloud.com", ctx->region); + } + + if (!ctx->uri) { + if (!ctx->namespace) { + flb_errno(); + flb_plg_error(ctx->ins, "Namespace is required"); + flb_oci_logan_conf_destroy(ctx); + return NULL; + } + ctx->uri = flb_sds_create_size(512); + flb_sds_snprintf(&ctx->uri, flb_sds_alloc(ctx->uri), + "/20200601/namespaces/%s/actions/uploadLogEventsFile", + ctx->namespace); + } + + + + if (create_pk_context(ctx->key_file, NULL, ctx) < 0) { + flb_plg_error(ctx->ins, "failed to create pk context"); + flb_oci_logan_conf_destroy(ctx); + return NULL; + } + + + ctx->key_id = flb_sds_create_size(512); + flb_sds_snprintf(&ctx->key_id, flb_sds_alloc(ctx->key_id), + "%s/%s/%s", ctx->tenancy, ctx->user, ctx->key_fingerprint); + + + /* Check if SSL/TLS is enabled */ + io_flags = FLB_IO_TCP; + default_port = 80; + +#ifdef FLB_HAVE_TLS + if (ins->use_tls == FLB_TRUE) { + io_flags = FLB_IO_TLS; + default_port = 443; + } +#endif + + if (ins->host.ipv6 == FLB_TRUE) { + io_flags |= FLB_IO_IPV6; + } + + flb_output_net_default(host, default_port, ins); + flb_sds_destroy(host); + + if (ctx->proxy) { + ret = flb_utils_url_split(tmp, &protocol, &p_host, &p_port, &p_uri); + if (ret == -1) { + flb_plg_error(ctx->ins, "could not parse proxy parameter: '%s'", tmp); + flb_oci_logan_conf_destroy(ctx); + return NULL; + } + + ctx->proxy_host = p_host; + ctx->proxy_port = atoi(p_port); + flb_free(protocol); + flb_free(p_port); + flb_free(p_uri); + flb_free(p_host); + } + + if (ctx->proxy) { + upstream = flb_upstream_create(config, ctx->proxy_host, ctx->proxy_port, + io_flags, ins->tls); + } + else { + /* Prepare an upstream handler */ + upstream = flb_upstream_create(config, ins->host.name, ins->host.port, + io_flags, ins->tls); + } + + if (!upstream) { + flb_plg_error(ctx->ins, "cannot create Upstream context"); + flb_oci_logan_conf_destroy(ctx); + return NULL; + } + ctx->u = upstream; + + /* Set instance flags into upstream */ + flb_output_upstream_set(ctx->u, ins); + + return ctx; +} + +static void metadata_fields_destroy(struct flb_oci_logan *ctx) +{ + struct mk_list *tmp; + struct mk_list *head; + struct metadata_obj *f; + + mk_list_foreach_safe(head, tmp, &ctx->global_metadata_fields) { + f = mk_list_entry(head, struct metadata_obj, _head); + flb_sds_destroy(f->key); + flb_sds_destroy(f->val); + mk_list_del(&f->_head); + flb_free(f); + } + + mk_list_foreach_safe(head, tmp, &ctx->log_event_metadata_fields) { + f = mk_list_entry(head, struct metadata_obj, _head); + flb_sds_destroy(f->key); + flb_sds_destroy(f->val); + mk_list_del(&f->_head); + flb_free(f); + } + +} + +int flb_oci_logan_conf_destroy(struct flb_oci_logan *ctx) { + if(ctx == NULL) { + return 0; + } + + if (ctx->private_key) { + flb_sds_destroy(ctx->private_key); + } + if (ctx->uri) { + flb_sds_destroy(ctx->uri); + } + if (ctx->key_id) { + flb_sds_destroy(ctx->key_id); + } + if (ctx->key_file) { + flb_sds_destroy(ctx->key_file); + } + if(ctx->user) { + flb_sds_destroy(ctx->user); + } + if(ctx->key_fingerprint) { + flb_sds_destroy(ctx->key_fingerprint); + } + if(ctx->tenancy) { + flb_sds_destroy(ctx->tenancy); + } + if(ctx->region) { + flb_sds_destroy(ctx->region); + } + if (ctx->u) { + flb_upstream_destroy(ctx->u); + } + + metadata_fields_destroy(ctx); + + flb_free(ctx); + return 0; +} \ No newline at end of file diff --git a/plugins/out_oracle_log_analytics/oci_logan_conf.h b/plugins/out_oracle_log_analytics/oci_logan_conf.h new file mode 100644 index 00000000000..a11832b0a82 --- /dev/null +++ b/plugins/out_oracle_log_analytics/oci_logan_conf.h @@ -0,0 +1,34 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Fluent Bit + * ========== + * Copyright (C) 2015-2023 The Fluent Bit Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef FLB_OUT_OCI_LOGAN_CONF_H +#define FLB_OUT_OCI_LOGAN_CONF_H + +#include +#include +#include + +#include "oci_logan.h" + +struct flb_oci_logan *flb_oci_logan_conf_create(struct flb_output_instance *ins, + struct flb_config *config); +int flb_oci_logan_conf_destroy(struct flb_oci_logan *ctx); + +#endif From 5610789211d755705f7bb9bc65f9cc330a23fad5 Mon Sep 17 00:00:00 2001 From: Takahiro Yamashita Date: Fri, 22 Sep 2023 11:02:55 +0900 Subject: [PATCH 269/315] engine: add sleep to output logs on init (#7931) Signed-off-by: Takahiro Yamashita --- src/flb_engine.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/flb_engine.c b/src/flb_engine.c index 6bf0a03cd6d..78be8d5ec8d 100644 --- a/src/flb_engine.c +++ b/src/flb_engine.c @@ -597,6 +597,9 @@ int flb_engine_failed(struct flb_config *config) flb_error("[engine] fail to dispatch FAILED message"); } + /* Waiting flushing log */ + sleep(1); + return ret; } From 2356fad02948cd7e19241609576b4378097b9e5d Mon Sep 17 00:00:00 2001 From: DavidKorczynski Date: Sat, 23 Sep 2023 18:15:35 +0100 Subject: [PATCH 270/315] scheduler: use calloc instead of malloc (#7962) This is fixing a use-after-free if multiple schedulers are used in a single run. Fixes: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=60089 Signed-off-by: David Korczynski --- src/flb_scheduler.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/flb_scheduler.c b/src/flb_scheduler.c index 597f6f5776e..91f70682822 100644 --- a/src/flb_scheduler.c +++ b/src/flb_scheduler.c @@ -523,7 +523,7 @@ struct flb_sched *flb_sched_create(struct flb_config *config, struct flb_sched *sched; struct flb_sched_timer *timer; - sched = flb_malloc(sizeof(struct flb_sched)); + sched = flb_calloc(1, sizeof(struct flb_sched)); if (!sched) { flb_errno(); return NULL; From a61088baad531397d75379f23c3a4b06bdfe4d86 Mon Sep 17 00:00:00 2001 From: Hiroshi Hatake Date: Sun, 24 Sep 2023 02:17:40 +0900 Subject: [PATCH 271/315] plugin_proxy: Handle no ingestion case (#7922) This is because the recent version of fluent-bit wants to process the ring buffers when nothing ingested but called in the callback. We need to check whether the logs are ingested or not on that line. Signed-off-by: Hiroshi Hatake --- src/flb_plugin_proxy.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/flb_plugin_proxy.c b/src/flb_plugin_proxy.c index 0097c50ada6..440c545256c 100644 --- a/src/flb_plugin_proxy.c +++ b/src/flb_plugin_proxy.c @@ -84,6 +84,11 @@ static int flb_proxy_input_cb_collect(struct flb_input_instance *ins, flb_trace("[GO] entering go_collect()"); ret = proxy_go_input_collect(ctx->proxy, &data, &len); + if (len == 0) { + flb_trace("[GO] No logs are ingested"); + return -1; + } + if (ret == -1) { flb_errno(); return -1; From 85f1d404719ea4cf1036d7a8777115cc2d3c9cc2 Mon Sep 17 00:00:00 2001 From: Hiroshi Hatake Date: Sun, 24 Sep 2023 02:18:02 +0900 Subject: [PATCH 272/315] input_chunk: Use flb_plg_debug instead of normal printf (#7901) This is because log_level for this line should be handled. Signed-off-by: Hiroshi Hatake --- src/flb_input_chunk.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/flb_input_chunk.c b/src/flb_input_chunk.c index 53ddb6c2905..b851514306f 100644 --- a/src/flb_input_chunk.c +++ b/src/flb_input_chunk.c @@ -1724,8 +1724,8 @@ static int append_to_ring_buffer(struct flb_input_instance *ins, /* append chunk raw context to the ring buffer */ ret = flb_ring_buffer_write(ins->rb, (void *) &cr, sizeof(cr)); if (ret == -1) { - printf("[%s] failed buffer write, retries=%i\n", - flb_input_name(ins), retries); fflush(stdout); + flb_plg_debug(ins, "failed buffer write, retries=%i\n", + retries); /* sleep for 100000 microseconds (100 milliseconds) */ usleep(100000); From 0f1127926c4cd778a746c5e68551d5ae003807b2 Mon Sep 17 00:00:00 2001 From: Takahiro Yamashita Date: Sat, 9 Sep 2023 07:39:26 +0900 Subject: [PATCH 273/315] lua: push flb_null as a nil value Signed-off-by: Takahiro Yamashita --- include/fluent-bit/flb_lua.h | 4 ++++ src/flb_lua.c | 15 +++++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/include/fluent-bit/flb_lua.h b/include/fluent-bit/flb_lua.h index b2787430284..a578b00deae 100644 --- a/include/fluent-bit/flb_lua.h +++ b/include/fluent-bit/flb_lua.h @@ -29,6 +29,9 @@ #include #include +/* global variables in Lua */ +#define FLB_LUA_VAR_FLB_NULL "flb_null" + #define FLB_LUA_L2C_TYPES_NUM_MAX 16 enum flb_lua_l2c_type_enum { @@ -74,5 +77,6 @@ void flb_lua_tompack(lua_State *l, int index, struct flb_lua_l2c_config *l2cc); void flb_lua_dump_stack(FILE *out, lua_State *l); +int flb_lua_enable_flb_null(lua_State *l); #endif diff --git a/src/flb_lua.c b/src/flb_lua.c index a374752326c..3b3af4926b8 100644 --- a/src/flb_lua.c +++ b/src/flb_lua.c @@ -25,6 +25,17 @@ #include #include +int flb_lua_enable_flb_null(lua_State *l) +{ + /* set flb.null */ + lua_pushlightuserdata(l, NULL); + + flb_info("[%s] set %s", __FUNCTION__, FLB_LUA_VAR_FLB_NULL); + lua_setglobal(l, FLB_LUA_VAR_FLB_NULL); + + return 0; +} + void flb_lua_pushtimetable(lua_State *l, struct flb_time *tm) { lua_createtable(l, 0, 2); @@ -63,7 +74,7 @@ int flb_lua_pushmpack(lua_State *l, mpack_reader_t *reader) tag = mpack_read_tag(reader); switch (mpack_tag_type(&tag)) { case mpack_type_nil: - lua_pushnil(l); + lua_getglobal(l, FLB_LUA_VAR_FLB_NULL); break; case mpack_type_bool: lua_pushboolean(l, mpack_tag_bool_value(&tag)); @@ -128,7 +139,7 @@ void flb_lua_pushmsgpack(lua_State *l, msgpack_object *o) switch(o->type) { case MSGPACK_OBJECT_NIL: - lua_pushnil(l); + lua_getglobal(l, FLB_LUA_VAR_FLB_NULL); break; case MSGPACK_OBJECT_BOOLEAN: From de862073335b3fc06d60cd742397350a7b9752e9 Mon Sep 17 00:00:00 2001 From: Takahiro Yamashita Date: Sat, 9 Sep 2023 07:39:53 +0900 Subject: [PATCH 274/315] tests: runtime: lua: test for enable_flb_null Signed-off-by: Takahiro Yamashita --- tests/runtime/filter_lua.c | 71 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/tests/runtime/filter_lua.c b/tests/runtime/filter_lua.c index 9f694377eae..49f64eb8e0c 100644 --- a/tests/runtime/filter_lua.c +++ b/tests/runtime/filter_lua.c @@ -677,6 +677,76 @@ void flb_test_drop_all_records(void) flb_destroy(ctx); } +void flb_test_enable_flb_null(void) +{ + int ret; + flb_ctx_t *ctx; + int in_ffd; + int out_ffd; + int filter_ffd; + char *output = NULL; + char *input = "[0, {\"hello\":null}]"; + char *result; + struct flb_lib_out_cb cb_data; + + char *script_body = "" + "function lua_main(tag, timestamp, record)\n" + " return 1, timestamp, record\n" + "end\n"; + + clear_output(); + + /* Create context, flush every second (some checks omitted here) */ + ctx = flb_create(); + flb_service_set(ctx, "flush", FLUSH_INTERVAL, "grace", "1", NULL); + + /* Prepare output callback context*/ + cb_data.cb = callback_test; + cb_data.data = NULL; + + ret = create_script(script_body, strlen(script_body)); + TEST_CHECK(ret == 0); + /* Filter */ + filter_ffd = flb_filter(ctx, (char *) "lua", NULL); + TEST_CHECK(filter_ffd >= 0); + ret = flb_filter_set(ctx, filter_ffd, + "Match", "*", + "call", "lua_main", + "script", TMP_LUA_PATH, + "enable_flb_null", "true", + NULL); + + /* Input */ + in_ffd = flb_input(ctx, (char *) "lib", NULL); + flb_input_set(ctx, in_ffd, "tag", "test", NULL); + TEST_CHECK(in_ffd >= 0); + + /* Lib output */ + out_ffd = flb_output(ctx, (char *) "lib", (void *)&cb_data); + TEST_CHECK(out_ffd >= 0); + flb_output_set(ctx, out_ffd, + "match", "test", + "format", "json", + NULL); + + ret = flb_start(ctx); + TEST_CHECK(ret==0); + + flb_lib_push(ctx, in_ffd, input, strlen(input)); + wait_with_timeout(2000, &output); + result = strstr(output, "\"hello\":null"); + if(!TEST_CHECK(result != NULL)) { + TEST_MSG("output:%s\n", output); + } + + /* clean up */ + flb_lib_free(output); + delete_script(); + + flb_stop(ctx); + flb_destroy(ctx); +} + /* https://github.com/fluent/fluent-bit/issues/5496 */ void flb_test_split_record(void) { @@ -761,6 +831,7 @@ TEST_LIST = { {"type_array_key", flb_test_type_array_key}, {"array_contains_null", flb_test_array_contains_null}, {"drop_all_records", flb_test_drop_all_records}, + {"enable_flb_null", flb_test_enable_flb_null}, {"split_record", flb_test_split_record}, {NULL, NULL} }; From c864fd3c539796bf146cc6cce4b8c78bfdf8273a Mon Sep 17 00:00:00 2001 From: Takahiro Yamashita Date: Sat, 9 Sep 2023 07:40:19 +0900 Subject: [PATCH 275/315] filter_lua: support enable_flb_null Signed-off-by: Takahiro Yamashita --- plugins/filter_lua/lua.c | 11 +++++++++++ plugins/filter_lua/lua_config.h | 1 + 2 files changed, 12 insertions(+) diff --git a/plugins/filter_lua/lua.c b/plugins/filter_lua/lua.c index a95c87da1fe..bb7bb566ab4 100644 --- a/plugins/filter_lua/lua.c +++ b/plugins/filter_lua/lua.c @@ -61,6 +61,10 @@ static int cb_lua_init(struct flb_filter_instance *f_ins, } ctx->lua = lj; + if (ctx->enable_flb_null) { + flb_lua_enable_flb_null(lj->state); + } + /* Lua script source code */ if (ctx->code) { ret = flb_luajit_load_buffer(ctx->lua, @@ -683,6 +687,13 @@ static struct flb_config_map config_map[] = { "If enabled, Fluent-bit will pass the timestamp as a Lua table " "with keys \"sec\" for seconds since epoch and \"nsec\" for nanoseconds." }, + { + FLB_CONFIG_MAP_BOOL, "enable_flb_null", "false", + 0, FLB_TRUE, offsetof(struct lua_filter, enable_flb_null), + "If enabled, null will be converted to flb_null in Lua. " + "It is useful to prevent removing key/value " + "since nil is a special value to remove key value from map in Lua." + }, {0} }; diff --git a/plugins/filter_lua/lua_config.h b/plugins/filter_lua/lua_config.h index e5cc1a9b4e5..af8d6f12858 100644 --- a/plugins/filter_lua/lua_config.h +++ b/plugins/filter_lua/lua_config.h @@ -35,6 +35,7 @@ struct lua_filter { flb_sds_t buffer; /* json dec buffer */ int protected_mode; /* exec lua function in protected mode */ int time_as_table; /* timestamp as a Lua table */ + int enable_flb_null; /* Use flb_null in Lua */ struct flb_lua_l2c_config l2cc; /* lua -> C config */ struct flb_luajit *lua; /* state context */ struct flb_filter_instance *ins; /* filter instance */ From 60f73cb7d966696d43da354b14fcf54d3edd247c Mon Sep 17 00:00:00 2001 From: Takahiro Yamashita Date: Sun, 30 Jul 2023 07:18:45 +0900 Subject: [PATCH 276/315] upstream: remove unused var Signed-off-by: Takahiro Yamashita --- src/flb_upstream.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/flb_upstream.c b/src/flb_upstream.c index 30c82b7ee11..9ec39b84c68 100644 --- a/src/flb_upstream.c +++ b/src/flb_upstream.c @@ -442,10 +442,6 @@ struct flb_upstream *flb_upstream_create_url(struct flb_config *config, */ static void shutdown_connection(struct flb_connection *u_conn) { - struct flb_upstream *u; - - u = u_conn->upstream; - if (u_conn->fd > 0 && !u_conn->shutdown_flag) { shutdown(u_conn->fd, SHUT_RDWR); From 5c4a7016ae5c9a0d15cd171ddccae75fcce782ff Mon Sep 17 00:00:00 2001 From: Takahiro Yamashita Date: Sun, 30 Jul 2023 07:21:26 +0900 Subject: [PATCH 277/315] input_chunk: remove unused var Signed-off-by: Takahiro Yamashita --- src/flb_input_chunk.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/flb_input_chunk.c b/src/flb_input_chunk.c index b851514306f..c71ae3ef089 100644 --- a/src/flb_input_chunk.c +++ b/src/flb_input_chunk.c @@ -1031,7 +1031,6 @@ static struct flb_input_chunk *input_chunk_get(struct flb_input_instance *in, int new_chunk = FLB_FALSE; size_t out_size; struct flb_input_chunk *ic = NULL; - size_t expected_chunk_size; if (tag_len > FLB_INPUT_CHUNK_TAG_MAX) { flb_plg_warn(in, From a4a04e337837c8381c11201ef95a1b57720daf63 Mon Sep 17 00:00:00 2001 From: Takahiro Yamashita Date: Sat, 2 Sep 2023 09:46:28 +0900 Subject: [PATCH 278/315] tests: runtime: filter_lua: add test for empty array and metatable Signed-off-by: Takahiro Yamashita --- tests/runtime/filter_lua.c | 147 +++++++++++++++++++++++++++++++++++++ 1 file changed, 147 insertions(+) diff --git a/tests/runtime/filter_lua.c b/tests/runtime/filter_lua.c index 49f64eb8e0c..1e3111266d0 100644 --- a/tests/runtime/filter_lua.c +++ b/tests/runtime/filter_lua.c @@ -823,6 +823,151 @@ void flb_test_split_record(void) flb_sds_destroy(outbuf); } +void flb_test_empty_array(void) +{ + int ret; + flb_ctx_t *ctx; + int in_ffd; + int out_ffd; + int filter_ffd; + flb_sds_t outbuf = flb_sds_create(""); + char *input = "[0, {\"key\":[]}]"; + struct flb_lib_out_cb cb_data; + + const char *expected = + "[5.000000,{\"key\":[]}]"; + + char *script_body = "" + "function lua_main(tag, timestamp, record)\n" + " return 1, 5, record\n" + "end\n"; + + clear_output_num(); + + /* Create context, flush every second (some checks omitted here) */ + ctx = flb_create(); + flb_service_set(ctx, "flush", FLUSH_INTERVAL, "grace", "1", NULL); + + /* Prepare output callback context*/ + cb_data.cb = callback_cat; + cb_data.data = &outbuf; + + ret = create_script(script_body, strlen(script_body)); + TEST_CHECK(ret == 0); + /* Filter */ + filter_ffd = flb_filter(ctx, (char *) "lua", NULL); + TEST_CHECK(filter_ffd >= 0); + ret = flb_filter_set(ctx, filter_ffd, + "Match", "*", + "call", "lua_main", + "script", TMP_LUA_PATH, + NULL); + + /* Input */ + in_ffd = flb_input(ctx, (char *) "lib", NULL); + flb_input_set(ctx, in_ffd, "tag", "test", NULL); + TEST_CHECK(in_ffd >= 0); + + /* Lib output */ + out_ffd = flb_output(ctx, (char *) "lib", (void *)&cb_data); + TEST_CHECK(out_ffd >= 0); + flb_output_set(ctx, out_ffd, + "match", "test", + "format", "json", + NULL); + + ret = flb_start(ctx); + TEST_CHECK(ret==0); + + flb_lib_push(ctx, in_ffd, input, strlen(input)); + wait_with_timeout(2000, &output); + if (!TEST_CHECK(!strcmp(outbuf, expected))) { + TEST_MSG("expected:\n%s\ngot:\n%s\n", expected, outbuf); + } + + /* clean up */ + flb_lib_free(output); + delete_script(); + + flb_stop(ctx); + flb_destroy(ctx); + flb_sds_destroy(outbuf); +} + +void flb_test_invalid_metatable(void) +{ + int ret; + flb_ctx_t *ctx; + int in_ffd; + int out_ffd; + int unused = 0; + int filter_ffd; + char *output = NULL; + char *input = "[0, {\"key\":\"val\"}]"; + struct flb_lib_out_cb cb_data; + + char *script_body = "" + "function lua_main(tag, timestamp, record)\n" + " meta = getmetatable(record)\n" + " meta[10] = \"hoge\"\n" + " return 1, timestamp, record\n" + "end\n"; + + clear_output_num(); + + /* Create context, flush every second (some checks omitted here) */ + ctx = flb_create(); + flb_service_set(ctx, "flush", FLUSH_INTERVAL, "grace", "1", NULL); + + /* Prepare output callback context*/ + cb_data.cb = cb_count_msgpack_events; + cb_data.data = &unused; + + ret = create_script(script_body, strlen(script_body)); + TEST_CHECK(ret == 0); + /* Filter */ + filter_ffd = flb_filter(ctx, (char *) "lua", NULL); + TEST_CHECK(filter_ffd >= 0); + ret = flb_filter_set(ctx, filter_ffd, + "Match", "*", + "call", "lua_main", + "script", TMP_LUA_PATH, + NULL); + + /* Input */ + in_ffd = flb_input(ctx, (char *) "lib", NULL); + flb_input_set(ctx, in_ffd, "tag", "test", NULL); + TEST_CHECK(in_ffd >= 0); + + /* Lib output */ + out_ffd = flb_output(ctx, (char *) "lib", (void *)&cb_data); + TEST_CHECK(out_ffd >= 0); + flb_output_set(ctx, out_ffd, + "match", "test", + NULL); + + ret = flb_start(ctx); + TEST_CHECK(ret==0); + + ret = flb_lib_push(ctx, in_ffd, input, strlen(input)); + if (!TEST_CHECK(ret != -1)) { + TEST_MSG("flb_lib_push error"); + } + flb_time_msleep(1500); /* waiting flush */ + + ret = get_output_num(); + if (!TEST_CHECK(ret > 0)) { + TEST_MSG("error. no output"); + } + + /* clean up */ + flb_lib_free(output); + delete_script(); + + flb_stop(ctx); + flb_destroy(ctx); +} + TEST_LIST = { {"hello_world", flb_test_helloworld}, {"append_tag", flb_test_append_tag}, @@ -833,5 +978,7 @@ TEST_LIST = { {"drop_all_records", flb_test_drop_all_records}, {"enable_flb_null", flb_test_enable_flb_null}, {"split_record", flb_test_split_record}, + {"empty_array", flb_test_empty_array}, + {"invalid_metatable", flb_test_invalid_metatable}, {NULL, NULL} }; From 51723c93a4678456c817ddb5eb6664c8261e3732 Mon Sep 17 00:00:00 2001 From: Takahiro Yamashita Date: Sun, 3 Sep 2023 08:30:03 +0900 Subject: [PATCH 279/315] lua: support metatable to save table type Signed-off-by: Takahiro Yamashita --- include/fluent-bit/flb_lua.h | 24 ++- src/flb_lua.c | 275 +++++++++++++++++++++++++++-------- 2 files changed, 239 insertions(+), 60 deletions(-) diff --git a/include/fluent-bit/flb_lua.h b/include/fluent-bit/flb_lua.h index a578b00deae..ada88dbca5b 100644 --- a/include/fluent-bit/flb_lua.h +++ b/include/fluent-bit/flb_lua.h @@ -36,7 +36,8 @@ enum flb_lua_l2c_type_enum { FLB_LUA_L2C_TYPE_INT, - FLB_LUA_L2C_TYPE_ARRAY + FLB_LUA_L2C_TYPE_ARRAY, + FLB_LUA_L2C_TYPE_MAP }; struct flb_lua_l2c_type { @@ -50,6 +51,27 @@ struct flb_lua_l2c_config { struct mk_list l2c_types; /* data types (lua -> C) */ }; + +/* + * Metatable for Lua table. + * https://www.lua.org/manual/5.1/manual.html#2.8 + */ +struct flb_lua_metadata { + int initialized; + int data_type; /* Map or Array */ +}; + +static inline int flb_lua_metadata_init(struct flb_lua_metadata *meta) +{ + if (meta == NULL) { + return -1; + } + meta->initialized = FLB_TRUE; + meta->data_type = -1; + + return 0; +} + /* convert from negative index to positive index */ static inline int flb_lua_absindex(lua_State *l , int index) { diff --git a/src/flb_lua.c b/src/flb_lua.c index 3b3af4926b8..e4df896c515 100644 --- a/src/flb_lua.c +++ b/src/flb_lua.c @@ -64,12 +64,35 @@ int flb_lua_is_valid_func(lua_State *lua, flb_sds_t func) return ret; } +static int flb_lua_setmetatable(lua_State *l, struct flb_lua_metadata *meta, int index) +{ + int abs_index; + + if (meta->initialized != FLB_TRUE) { + return -1; + } + abs_index = flb_lua_absindex(l, index); + + lua_createtable(l, 0, 1); + + /* data type */ + lua_pushlstring(l, "type", 4); + lua_pushinteger(l, meta->data_type); + lua_settable(l, -3); /* point created table */ + + lua_setmetatable(l, abs_index); + + return 0; +} + int flb_lua_pushmpack(lua_State *l, mpack_reader_t *reader) { int ret = 0; mpack_tag_t tag; uint32_t length; uint32_t i; + int index; + struct flb_lua_metadata meta; tag = mpack_read_tag(reader); switch (mpack_tag_type(&tag)) { @@ -99,8 +122,12 @@ int flb_lua_pushmpack(lua_State *l, mpack_reader_t *reader) reader->data += length; break; case mpack_type_array: + flb_lua_metadata_init(&meta); + meta.data_type = FLB_LUA_L2C_TYPE_ARRAY; + length = mpack_tag_array_count(&tag); lua_createtable(l, length, 0); + index = lua_gettop(l); /* save index of created table */ for (i = 0; i < length; i++) { ret = flb_lua_pushmpack(l, reader); if (ret) { @@ -108,10 +135,16 @@ int flb_lua_pushmpack(lua_State *l, mpack_reader_t *reader) } lua_rawseti(l, -2, i+1); } + flb_lua_setmetatable(l, &meta, index); + break; case mpack_type_map: + flb_lua_metadata_init(&meta); + meta.data_type = FLB_LUA_L2C_TYPE_MAP; + length = mpack_tag_map_count(&tag); lua_createtable(l, length, 0); + index = lua_gettop(l); /* save index of created table */ for (i = 0; i < length; i++) { ret = flb_lua_pushmpack(l, reader); if (ret) { @@ -123,6 +156,8 @@ int flb_lua_pushmpack(lua_State *l, mpack_reader_t *reader) } lua_settable(l, -3); } + flb_lua_setmetatable(l, &meta, index); + break; default: return -1; @@ -134,6 +169,8 @@ void flb_lua_pushmsgpack(lua_State *l, msgpack_object *o) { int i; int size; + int index; + struct flb_lua_metadata meta; lua_checkstack(l, 3); @@ -172,28 +209,38 @@ void flb_lua_pushmsgpack(lua_State *l, msgpack_object *o) break; case MSGPACK_OBJECT_ARRAY: + flb_lua_metadata_init(&meta); + meta.data_type = FLB_LUA_L2C_TYPE_ARRAY; + size = o->via.array.size; lua_createtable(l, size, 0); + index = lua_gettop(l); /* save index of created table */ if (size != 0) { msgpack_object *p = o->via.array.ptr; for (i = 0; i < size; i++) { flb_lua_pushmsgpack(l, p+i); - lua_rawseti (l, -2, i+1); + lua_rawseti (l, index, i+1); } } + flb_lua_setmetatable(l, &meta, index); break; case MSGPACK_OBJECT_MAP: + flb_lua_metadata_init(&meta); + meta.data_type = FLB_LUA_L2C_TYPE_MAP; + size = o->via.map.size; lua_createtable(l, 0, size); + index = lua_gettop(l); /* save index of created table */ if (size != 0) { msgpack_object_kv *p = o->via.map.ptr; for (i = 0; i < size; i++) { flb_lua_pushmsgpack(l, &(p+i)->key); flb_lua_pushmsgpack(l, &(p+i)->val); - lua_settable(l, -3); + lua_settable(l, index); } } + flb_lua_setmetatable(l, &meta, index); break; } } @@ -288,10 +335,10 @@ int flb_lua_arraylength(lua_State *l, int index) return max; } -static void lua_toarray(lua_State *l, - msgpack_packer *pck, - int index, - struct flb_lua_l2c_config *l2cc) +static void lua_toarray_msgpack(lua_State *l, + msgpack_packer *pck, + int index, + struct flb_lua_l2c_config *l2cc) { int len; int i; @@ -330,7 +377,6 @@ static void lua_toarray_mpack(lua_State *l, static void try_to_convert_data_type(lua_State *l, msgpack_packer *pck, - int index, struct flb_lua_l2c_config *l2cc) { size_t len; @@ -362,7 +408,7 @@ static void try_to_convert_data_type(lua_State *l, l2c = mk_list_entry(head, struct flb_lua_l2c_type, _head); if (!strncmp(l2c->key, tmp, len) && l2c->type == FLB_LUA_L2C_TYPE_ARRAY) { flb_lua_tomsgpack(l, pck, -1, l2cc); - lua_toarray(l, pck, 0, l2cc); + lua_toarray_msgpack(l, pck, 0, l2cc); return; } } @@ -375,7 +421,6 @@ static void try_to_convert_data_type(lua_State *l, static void try_to_convert_data_type_mpack(lua_State *l, mpack_writer_t *writer, - int index, struct flb_lua_l2c_config *l2cc) { size_t len; @@ -418,6 +463,89 @@ static void try_to_convert_data_type_mpack(lua_State *l, flb_lua_tompack(l, writer, 0, l2cc); } +static int flb_lua_getmetatable(lua_State *l, int index, struct flb_lua_metadata *meta) +{ + int lua_ret; + int abs_index; + const char *str; + size_t len; + + if (meta->initialized != FLB_TRUE) { + return -1; + } + + lua_ret = lua_getmetatable(l, index); + if (lua_ret == 0) { + /* no metadata */ + return -1; + } + else if (lua_type(l, -1) != LUA_TTABLE) { + /* invalid metatable? */ + lua_pop(l, 1); + return -1; + } + + lua_pushnil(l); + abs_index = flb_lua_absindex(l, -2); + while (lua_next(l, abs_index) != 0) { + if (lua_type(l, -2) != LUA_TSTRING) { + /* key is not a string */ + flb_debug("key is not a string"); + lua_pop(l, 1); + continue; + } + + str = lua_tolstring(l, -2, &len); /* key */ + + if (len == 4 && strncmp(str, "type", 4) == 0) { + /* data_type */ + if (lua_type(l, -1) != LUA_TNUMBER) { + /* value is not data type */ + flb_debug("type is not num. type=%s", lua_typename(l, lua_type(l, -1))); + lua_pop(l, 1); + continue; + } + meta->data_type = (int)lua_tointeger(l, -1); + } + lua_pop(l, 1); + } + lua_pop(l, 1); /* pop metatable */ + + return 0; +} + +static void lua_tomap_mpack(lua_State *l, + mpack_writer_t *writer, + int index, + struct flb_lua_l2c_config *l2cc) +{ + int len; + + len = 0; + lua_pushnil(l); + while (lua_next(l, -2) != 0) { + lua_pop(l, 1); + len++; + } + mpack_write_tag(writer, mpack_tag_map(len)); + + lua_pushnil(l); + + if (l2cc->l2c_types_num > 0) { + /* type conversion */ + while (lua_next(l, -2) != 0) { + try_to_convert_data_type_mpack(l, writer, l2cc); + lua_pop(l, 1); + } + } else { + while (lua_next(l, -2) != 0) { + flb_lua_tompack(l, writer, -1, l2cc); + flb_lua_tompack(l, writer, 0, l2cc); + lua_pop(l, 1); + } + } +} + void flb_lua_tompack(lua_State *l, mpack_writer_t *writer, int index, @@ -425,6 +553,8 @@ void flb_lua_tompack(lua_State *l, { int len; int i; + int use_metatable = FLB_FALSE; + struct flb_lua_metadata meta; switch (lua_type(l, -1 + index)) { case LUA_TSTRING: @@ -456,6 +586,23 @@ void flb_lua_tompack(lua_State *l, mpack_write_false(writer); break; case LUA_TTABLE: + flb_lua_metadata_init(&meta); + if (flb_lua_getmetatable(l, -1 + index, &meta) == 0 && + meta.data_type >= 0) { + use_metatable = FLB_TRUE; + } + if (use_metatable) { + if (meta.data_type == FLB_LUA_L2C_TYPE_ARRAY) { + /* array */ + lua_toarray_mpack(l, writer, 0, l2cc); + } + else { + /* map */ + lua_tomap_mpack(l, writer, -1 + index, l2cc); + } + break; + } + len = flb_lua_arraylength(l, -1 + index); if (len > 0) { mpack_write_tag(writer, mpack_tag_array(len)); @@ -464,31 +611,9 @@ void flb_lua_tompack(lua_State *l, flb_lua_tompack(l, writer, 0, l2cc); lua_pop(l, 1); } - } else - { - len = 0; - lua_pushnil(l); - while (lua_next(l, -2) != 0) { - lua_pop(l, 1); - len++; - } - mpack_write_tag(writer, mpack_tag_map(len)); - - lua_pushnil(l); - - if (l2cc->l2c_types_num > 0) { - /* type conversion */ - while (lua_next(l, -2) != 0) { - try_to_convert_data_type_mpack(l, writer, index, l2cc); - lua_pop(l, 1); - } - } else { - while (lua_next(l, -2) != 0) { - flb_lua_tompack(l, writer, -1, l2cc); - flb_lua_tompack(l, writer, 0, l2cc); - lua_pop(l, 1); - } - } + } + else { + lua_tomap_mpack(l, writer, -1 + index, l2cc); } break; case LUA_TNIL: @@ -508,6 +633,41 @@ void flb_lua_tompack(lua_State *l, } } +static inline void lua_tomap_msgpack(lua_State *l, + msgpack_packer *pck, + int index, + struct flb_lua_l2c_config *l2cc) +{ + int len; + int abs_index; + + abs_index = flb_lua_absindex(l, index); + + len = 0; + lua_pushnil(l); + while (lua_next(l, abs_index) != 0) { + lua_pop(l, 1); + len++; + } + msgpack_pack_map(pck, len); + + lua_pushnil(l); + + if (l2cc->l2c_types_num > 0) { + /* type conversion */ + while (lua_next(l, abs_index) != 0) { + try_to_convert_data_type(l, pck, l2cc); + lua_pop(l, 1); + } + } else { + while (lua_next(l, abs_index) != 0) { + flb_lua_tomsgpack(l, pck, -1, l2cc); + flb_lua_tomsgpack(l, pck, 0, l2cc); + lua_pop(l, 1); + } + } +} + void flb_lua_tomsgpack(lua_State *l, msgpack_packer *pck, int index, @@ -515,6 +675,8 @@ void flb_lua_tomsgpack(lua_State *l, { int len; int i; + int use_metatable = FLB_FALSE; + struct flb_lua_metadata meta; switch (lua_type(l, -1 + index)) { case LUA_TSTRING: @@ -547,6 +709,23 @@ void flb_lua_tomsgpack(lua_State *l, msgpack_pack_false(pck); break; case LUA_TTABLE: + flb_lua_metadata_init(&meta); + if (flb_lua_getmetatable(l, -1 + index, &meta) == 0 && + meta.data_type >= 0) { + use_metatable = FLB_TRUE; + } + if (use_metatable) { + if (meta.data_type == FLB_LUA_L2C_TYPE_ARRAY) { + /* array */ + lua_toarray_msgpack(l, pck, 0, l2cc); + } + else { + /* map */ + lua_tomap_msgpack(l, pck, -1 + index, l2cc); + } + break; + } + len = flb_lua_arraylength(l, -1 + index); if (len > 0) { msgpack_pack_array(pck, len); @@ -555,31 +734,9 @@ void flb_lua_tomsgpack(lua_State *l, flb_lua_tomsgpack(l, pck, 0, l2cc); lua_pop(l, 1); } - } else - { - len = 0; - lua_pushnil(l); - while (lua_next(l, -2) != 0) { - lua_pop(l, 1); - len++; - } - msgpack_pack_map(pck, len); - - lua_pushnil(l); - - if (l2cc->l2c_types_num > 0) { - /* type conversion */ - while (lua_next(l, -2) != 0) { - try_to_convert_data_type(l, pck, index, l2cc); - lua_pop(l, 1); - } - } else { - while (lua_next(l, -2) != 0) { - flb_lua_tomsgpack(l, pck, -1, l2cc); - flb_lua_tomsgpack(l, pck, 0, l2cc); - lua_pop(l, 1); - } - } + } + else { + lua_tomap_msgpack(l, pck, -1 + index, l2cc); } break; case LUA_TNIL: From 43ebe0872e9f325ad25adb49bddb45ad937e22fb Mon Sep 17 00:00:00 2001 From: Markus Meyer Date: Sat, 23 Sep 2023 19:36:28 +0200 Subject: [PATCH 280/315] filter_log_to_metrics: Add setting "label" (#7739) --------- Signed-off-by: Markus Meyer --- .../filter_log_to_metrics/log_to_metrics.c | 127 ++++++++++++------ .../filter_log_to_metrics/log_to_metrics.h | 1 + tests/runtime/filter_log_to_metrics.c | 79 ++++++++++- 3 files changed, 159 insertions(+), 48 deletions(-) diff --git a/plugins/filter_log_to_metrics/log_to_metrics.c b/plugins/filter_log_to_metrics/log_to_metrics.c index 147832b626c..5db50a4f33e 100644 --- a/plugins/filter_log_to_metrics/log_to_metrics.c +++ b/plugins/filter_log_to_metrics/log_to_metrics.c @@ -39,7 +39,7 @@ #include -static char kubernetes_label_keys[NUMBER_OF_KUBERNETES_LABELS][16] = +static char kubernetes_label_keys[NUMBER_OF_KUBERNETES_LABELS][16] = { "namespace_name", "pod_name", "container_name", @@ -77,9 +77,15 @@ static int log_to_metrics_destroy(struct log_to_metrics_ctx *ctx) if (ctx->cmt) { cmt_destroy(ctx->cmt); } - + delete_rules(ctx); + if (ctx->label_accessors != NULL) { + for (i = 0; i < MAX_LABEL_COUNT; i++) { + flb_free(ctx->label_accessors[i]); + } + flb_free(ctx->label_accessors); + } if (ctx->label_keys != NULL) { for (i = 0; i < MAX_LABEL_COUNT; i++) { flb_free(ctx->label_keys[i]); @@ -224,13 +230,17 @@ static inline int grep_filter_data(msgpack_object map, } static int set_labels(struct log_to_metrics_ctx *ctx, - char **label_keys, - int *label_counter, + char **label_accessors, + char **label_keys, + int *label_counter, struct flb_filter_instance *f_ins) { struct mk_list *head; - struct flb_kv *kv; + struct mk_list *split; + flb_sds_t tmp; + struct flb_kv *kv; + struct flb_split_entry *sentry; int counter = 0; int i; if (MAX_LABEL_COUNT < NUMBER_OF_KUBERNETES_LABELS){ @@ -238,8 +248,8 @@ static int set_labels(struct log_to_metrics_ctx *ctx, return -1; } if (ctx->kubernetes_mode){ - for (i = 0; i < NUMBER_OF_KUBERNETES_LABELS; i++){ - snprintf(label_keys[i], MAX_LABEL_LENGTH - 1, "%s", + for (i = 0; i < NUMBER_OF_KUBERNETES_LABELS; i++){ + snprintf(label_keys[i], MAX_LABEL_LENGTH - 1, "%s", kubernetes_label_keys[i]); } counter = NUMBER_OF_KUBERNETES_LABELS; @@ -249,14 +259,39 @@ static int set_labels(struct log_to_metrics_ctx *ctx, mk_list_foreach(head, &f_ins->properties) { kv = mk_list_entry(head, struct flb_kv, _head); - if (strcasecmp(kv->key, "label_field") != 0) { - continue; - } - if (counter >= MAX_LABEL_COUNT) { return MAX_LABEL_COUNT; } - snprintf(label_keys[counter++], MAX_LABEL_LENGTH - 1, "%s", kv->val); + + if (strcasecmp(kv->key, "label_field") == 0) { + snprintf(label_accessors[counter], MAX_LABEL_LENGTH - 1, "%s", kv->val); + snprintf(label_keys[counter], MAX_LABEL_LENGTH - 1, "%s", kv->val); + counter++; + } + else if (strcasecmp(kv->key, "label") == 0) { + split = flb_utils_split(kv->val, ' ', 1); + if (mk_list_size(split) != 2) { + flb_plg_error(ctx->ins, "invalid label, expected name and key"); + flb_utils_split_free(split); + return -1; + } + + sentry = mk_list_entry_first(split, struct flb_split_entry, _head); + tmp = flb_sds_create_len(sentry->value, sentry->len); + snprintf(label_keys[counter], MAX_LABEL_LENGTH - 1, "%s", tmp); + flb_sds_destroy(tmp); + + sentry = mk_list_entry_last(split, struct flb_split_entry, _head); + tmp = flb_sds_create_len(sentry->value, sentry->len); + snprintf(label_accessors[counter], MAX_LABEL_LENGTH - 1, "%s", tmp); + flb_sds_destroy(tmp); + counter++; + + flb_utils_split_free(split); + } + else { + continue; + } } *label_counter = counter; return counter; @@ -346,7 +381,7 @@ static int set_buckets(struct log_to_metrics_ctx *ctx, static int fill_labels(struct log_to_metrics_ctx *ctx, char **label_values, char kubernetes_label_values [NUMBER_OF_KUBERNETES_LABELS][MAX_LABEL_LENGTH], - char **label_keys, int label_counter, msgpack_object map) + char **label_accessors, int label_counter, msgpack_object map) { int label_iterator_start = 0; int i; @@ -365,14 +400,14 @@ static int fill_labels(struct log_to_metrics_ctx *ctx, char **label_values, if (kubernetes_label_keys[i] == NULL){ return -1; } - snprintf(label_values[i], MAX_LABEL_LENGTH - 1, "%s", + snprintf(label_values[i], MAX_LABEL_LENGTH - 1, "%s", kubernetes_label_values[i]); } label_iterator_start = NUMBER_OF_KUBERNETES_LABELS; } for (i = label_iterator_start; i < label_counter; i++){ - ra = flb_ra_create(label_keys[i], FLB_TRUE); + ra = flb_ra_create(label_accessors[i], FLB_TRUE); if (!ra) { flb_warn("invalid record accessor key, aborting"); break; @@ -383,15 +418,15 @@ static int fill_labels(struct log_to_metrics_ctx *ctx, char **label_values, /* Set value to empty string, so the value will be dropped in Cmetrics*/ label_values[i][0] = '\0'; } else if (rval->type == FLB_RA_STRING) { - snprintf(label_values[i], MAX_LABEL_LENGTH - 1, "%s", + snprintf(label_values[i], MAX_LABEL_LENGTH - 1, "%s", rval->val.string); } else if (rval->type == FLB_RA_FLOAT) { - snprintf(label_values[i], MAX_LABEL_LENGTH - 1, "%f", + snprintf(label_values[i], MAX_LABEL_LENGTH - 1, "%f", rval->val.f64); } else if (rval->type == FLB_RA_INT) { - snprintf(label_values[i], MAX_LABEL_LENGTH - 1, "%ld", + snprintf(label_values[i], MAX_LABEL_LENGTH - 1, "%ld", (long)rval->val.i64); } else { @@ -460,6 +495,11 @@ static int cb_log_to_metrics_init(struct flb_filter_instance *f_ins, return -1; } + ctx->label_accessors = NULL; + ctx->label_accessors = (char **) flb_malloc(MAX_LABEL_COUNT * sizeof(char *)); + for (i = 0; i < MAX_LABEL_COUNT; i++) { + ctx->label_accessors[i] = flb_malloc(MAX_LABEL_LENGTH * sizeof(char)); + } /* Set label keys */ ctx->label_keys = NULL; ctx->label_keys = (char **) flb_malloc(MAX_LABEL_COUNT * sizeof(char *)); @@ -468,7 +508,7 @@ static int cb_log_to_metrics_init(struct flb_filter_instance *f_ins, } ctx->label_counter = NULL; ctx->label_counter = flb_malloc(sizeof(int)); - label_count = set_labels(ctx, ctx->label_keys, ctx->label_counter, f_ins); + label_count = set_labels(ctx, ctx->label_accessors, ctx->label_keys, ctx->label_counter, f_ins); if (label_count < 0){ log_to_metrics_destroy(ctx); return -1; @@ -482,7 +522,7 @@ static int cb_log_to_metrics_init(struct flb_filter_instance *f_ins, } /* Check property metric mode */ - ctx->mode = 0; + ctx->mode = 0; tmp = (char *)flb_filter_get_property("metric_mode", f_ins); if (tmp != NULL) { if (strcasecmp(tmp, FLB_LOG_TO_METRICS_COUNTER_STR) == 0) { @@ -534,7 +574,7 @@ static int cb_log_to_metrics_init(struct flb_filter_instance *f_ins, log_to_metrics_destroy(ctx); return -1; } - snprintf(value_field, sizeof(value_field) - 1, "%s", + snprintf(value_field, sizeof(value_field) - 1, "%s", ctx->value_field); } @@ -563,12 +603,12 @@ static int cb_log_to_metrics_init(struct flb_filter_instance *f_ins, switch (ctx->mode) { case FLB_LOG_TO_METRICS_COUNTER: ctx->c = cmt_counter_create(ctx->cmt, "log_metric", "counter", - metric_name, metric_description, + metric_name, metric_description, label_count, ctx->label_keys); break; case FLB_LOG_TO_METRICS_GAUGE: ctx->g = cmt_gauge_create(ctx->cmt, "log_metric", "gauge", - metric_name, metric_description, + metric_name, metric_description, label_count, ctx->label_keys); break; case FLB_LOG_TO_METRICS_HISTOGRAM: @@ -619,7 +659,7 @@ static int cb_log_to_metrics_init(struct flb_filter_instance *f_ins, } static int cb_log_to_metrics_filter(const void *data, size_t bytes, - const char *tag, int tag_len, + const char *tag, int tag_len, void **out_buf, size_t *out_size, struct flb_filter_instance *f_ins, struct flb_input_instance *i_ins, void *context, @@ -691,7 +731,7 @@ static int cb_log_to_metrics_filter(const void *data, size_t bytes, break; } else { - snprintf(kubernetes_label_values[i], + snprintf(kubernetes_label_values[i], MAX_LABEL_LENGTH - 1, "%s", rval->val.string); } if (rval){ @@ -708,12 +748,12 @@ static int cb_log_to_metrics_filter(const void *data, size_t bytes, /* Fill optional labels */ label_values = flb_malloc(MAX_LABEL_COUNT * sizeof(char *)); for (i = 0; i < MAX_LABEL_COUNT; i++) { - label_values[i] = flb_malloc(MAX_LABEL_LENGTH * + label_values[i] = flb_malloc(MAX_LABEL_LENGTH * sizeof(char)); } - - label_count = fill_labels(ctx, label_values, - kubernetes_label_values, ctx->label_keys, + + label_count = fill_labels(ctx, label_values, + kubernetes_label_values, ctx->label_accessors, *ctx->label_counter, map); if (label_count != *ctx->label_counter){ label_count = 0; @@ -723,7 +763,7 @@ static int cb_log_to_metrics_filter(const void *data, size_t bytes, /* Calculating and setting metric depending on the mode */ switch (ctx->mode) { case FLB_LOG_TO_METRICS_COUNTER: - ret = cmt_counter_inc(ctx->c, ts, label_count, + ret = cmt_counter_inc(ctx->c, ts, label_count, label_values); break; @@ -750,11 +790,11 @@ static int cb_log_to_metrics_filter(const void *data, size_t bytes, gauge_value = (double)rval->val.i64; } else { - flb_plg_error(f_ins, + flb_plg_error(f_ins, "cannot convert given value to metric"); break; } - + ret = cmt_gauge_set(ctx->g, ts, gauge_value, label_count, label_values); if (rval) { @@ -811,13 +851,13 @@ static int cb_log_to_metrics_filter(const void *data, size_t bytes, log_to_metrics_destroy(ctx); return -1; } - + ret = flb_input_metrics_append(ctx->input_ins, ctx->tag, strlen(ctx->tag), ctx->cmt); if (ret != 0) { flb_plg_error(ctx->ins, "could not append metrics"); } - + /* Cleanup */ msgpack_unpacked_destroy(&result); if (label_values != NULL){ @@ -850,38 +890,38 @@ static int cb_log_to_metrics_exit(void *data, struct flb_config *config) static struct flb_config_map config_map[] = { { - FLB_CONFIG_MAP_STR, "regex", NULL, + FLB_CONFIG_MAP_STR, "regex", NULL, FLB_CONFIG_MAP_MULT, FLB_FALSE, 0, "Optional filter for records in which the content of KEY " "matches the regular expression." }, { - FLB_CONFIG_MAP_STR, "exclude", NULL, + FLB_CONFIG_MAP_STR, "exclude", NULL, FLB_CONFIG_MAP_MULT, FLB_FALSE, 0, "Optional filter for records in which the content of KEY " "does not matches the regular expression." }, { - FLB_CONFIG_MAP_STR, "metric_mode", "counter", + FLB_CONFIG_MAP_STR, "metric_mode", "counter", FLB_FALSE, FLB_TRUE, offsetof(struct log_to_metrics_ctx, mode), "Mode selector. Values counter, gauge," " or histogram. Summary is not supported" }, { - FLB_CONFIG_MAP_STR, "value_field", NULL, + FLB_CONFIG_MAP_STR, "value_field", NULL, FLB_FALSE, FLB_TRUE, offsetof(struct log_to_metrics_ctx, value_field), "Numeric field to use for gauge or histogram" }, { - FLB_CONFIG_MAP_STR, "metric_name", NULL, + FLB_CONFIG_MAP_STR, "metric_name", NULL, FLB_FALSE, FLB_TRUE, offsetof(struct log_to_metrics_ctx, metric_name), "Name of metric" }, { - FLB_CONFIG_MAP_STR, "metric_description", NULL, + FLB_CONFIG_MAP_STR, "metric_description", NULL, FLB_FALSE, FLB_TRUE, offsetof(struct log_to_metrics_ctx, metric_description), "Help text for metric" @@ -892,7 +932,12 @@ static struct flb_config_map config_map[] = { "Enable kubernetes log metric fields" }, { - FLB_CONFIG_MAP_STR, "label_field", NULL, + FLB_CONFIG_MAP_STR, "label", NULL, + FLB_CONFIG_MAP_MULT, FLB_FALSE, 0, + "Specify message field that should be included in the metric" + }, + { + FLB_CONFIG_MAP_STR, "label_field", NULL, FLB_CONFIG_MAP_MULT, FLB_FALSE, 0, "Specify message field that should be included in the metric" }, diff --git a/plugins/filter_log_to_metrics/log_to_metrics.h b/plugins/filter_log_to_metrics/log_to_metrics.h index b2ba4949064..6edb5ab305e 100644 --- a/plugins/filter_log_to_metrics/log_to_metrics.h +++ b/plugins/filter_log_to_metrics/log_to_metrics.h @@ -63,6 +63,7 @@ struct log_to_metrics_ctx struct cmt_gauge *g; struct cmt_histogram *h; struct cmt_histogram_buckets *histogram_buckets; + char **label_accessors; char **label_keys; int *label_counter; bool kubernetes_mode; diff --git a/tests/runtime/filter_log_to_metrics.c b/tests/runtime/filter_log_to_metrics.c index ccd564847bd..b8c8dba1dc2 100644 --- a/tests/runtime/filter_log_to_metrics.c +++ b/tests/runtime/filter_log_to_metrics.c @@ -62,6 +62,7 @@ void flb_test_log_to_metrics_gauge(void); void flb_test_log_to_metrics_histogram(void); void flb_test_log_to_metrics_reg(void); void flb_test_log_to_metrics_empty_label_keys_regex(void); +void flb_test_log_to_metrics_label(void); /* Test data */ @@ -122,6 +123,7 @@ TEST_LIST = { {"histogram", flb_test_log_to_metrics_histogram }, {"counter_regex", flb_test_log_to_metrics_reg }, {"regex_empty_label_keys", flb_test_log_to_metrics_empty_label_keys_regex }, + {"label", flb_test_log_to_metrics_label }, {NULL, NULL} }; @@ -138,7 +140,7 @@ int callback_test(void* data, size_t size, void* cb_data) flb_debug("[test_filter_log_to_metrics] received message: %s", (char*)data); pthread_mutex_lock(&result_mutex); strncat(output, data, size); - data_size = size; + data_size = size; pthread_mutex_unlock(&result_mutex); } flb_free(data); @@ -199,7 +201,7 @@ void flb_test_log_to_metrics_counter_k8s(void) "\"def456\",\"red\",\"right\"]"; ctx = flb_create(); - flb_service_set(ctx, "Flush", "0.200000000", "Grace", "1", "Log_Level", + flb_service_set(ctx, "Flush", "0.200000000", "Grace", "1", "Log_Level", "error", NULL); cb_data.cb = callback_test; @@ -260,7 +262,7 @@ void flb_test_log_to_metrics_counter(void) const char *expected = "\"value\":5.0,\"labels\":[\"red\",\"right\"]"; ctx = flb_create(); - flb_service_set(ctx, "Flush", "0.200000000", "Grace", "1", "Log_Level", + flb_service_set(ctx, "Flush", "0.200000000", "Grace", "1", "Log_Level", "error", NULL); cb_data.cb = callback_test; @@ -326,7 +328,7 @@ void flb_test_log_to_metrics_counter_k8s_two_tuples(void) ctx = flb_create(); - flb_service_set(ctx, "Flush", "0.200000000", "Grace", "1", "Log_Level", + flb_service_set(ctx, "Flush", "0.200000000", "Grace", "1", "Log_Level", "error", NULL); cb_data.cb = callback_test; @@ -394,7 +396,7 @@ void flb_test_log_to_metrics_gauge(void) const char *expected = "\"value\":20.0,\"labels\":[\"red\",\"right\"]"; ctx = flb_create(); - flb_service_set(ctx, "Flush", "0.200000000", "Grace", "1", "Log_Level", + flb_service_set(ctx, "Flush", "0.200000000", "Grace", "1", "Log_Level", "error", NULL); cb_data.cb = callback_test; @@ -522,7 +524,7 @@ void flb_test_log_to_metrics_reg(void) ctx = flb_create(); - flb_service_set(ctx, "Flush", "0.200000000", "Grace", "1", "Log_Level", + flb_service_set(ctx, "Flush", "0.200000000", "Grace", "1", "Log_Level", "error", NULL); cb_data.cb = callback_test; @@ -587,7 +589,7 @@ void flb_test_log_to_metrics_empty_label_keys_regex(void) ctx = flb_create(); - flb_service_set(ctx, "Flush", "0.200000000", "Grace", "1", "Log_Level", + flb_service_set(ctx, "Flush", "0.200000000", "Grace", "1", "Log_Level", "error", NULL); cb_data.cb = callback_test; @@ -631,3 +633,66 @@ void flb_test_log_to_metrics_empty_label_keys_regex(void) filter_test_destroy(ctx); } + +void flb_test_log_to_metrics_label(void) +{ + int ret; + int i; + flb_ctx_t *ctx; + int in_ffd; + int filter_ffd; + int out_ffd; + char *result = NULL; + struct flb_lib_out_cb cb_data; + char *input = JSON_MSG1; + char finalString[32768] = ""; + const char *expected_label_name = ",\"labels\":[\"pod_name\"],"; + const char *expected_label_value = "\"value\":2.0,\"labels\":[\"testpod\"]"; + + ctx = flb_create(); + flb_service_set(ctx, "Flush", "0.200000000", "Grace", "1", "Log_Level", + "error", NULL); + + cb_data.cb = callback_test; + cb_data.data = NULL; + + in_ffd = flb_input(ctx, (char *) "lib", NULL); + TEST_CHECK(in_ffd >= 0); + flb_input_set(ctx, in_ffd, "tag", "test", NULL); + + filter_ffd = flb_filter(ctx, (char *) "log_to_metrics", NULL); + TEST_CHECK(filter_ffd >= 0); + ret = flb_filter_set(ctx, filter_ffd, + "Match", "*", + "Tag", "test_metric", + "metric_mode", "counter", + "metric_name", "test", + "metric_description", "Counts messages", + "kubernetes_mode", "off", + "label", "pod_name $kubernetes['pod_name']", + NULL); + + out_ffd = flb_output(ctx, (char *) "lib", (void *)&cb_data); + TEST_CHECK(out_ffd >= 0); + flb_output_set(ctx, out_ffd, + "match", "*", + "format", "json", + NULL); + ret = flb_start(ctx); + TEST_CHECK(ret == 0); + + for (i = 0; i < 2; i++){ + flb_lib_push(ctx, in_ffd, input, strlen(input)); + } + wait_with_timeout(500, finalString); + result = strstr(finalString, expected_label_name); + if (!TEST_CHECK(result != NULL)) { + TEST_MSG("expected substring:\n%s\ngot:\n%s\n", expected_label_name, finalString); + } + result = strstr(finalString, expected_label_value); + if (!TEST_CHECK(result != NULL)) { + TEST_MSG("expected substring:\n%s\ngot:\n%s\n", expected_label_value, finalString); + } + filter_test_destroy(ctx); + +} From ab626d0a646719ee6e71ec8bb9a4435d02b2e27f Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Sat, 23 Sep 2023 11:45:12 -0600 Subject: [PATCH 281/315] filter_log_to_metrics: rename 'label' option to 'add_label' (#7964) Signed-off-by: Eduardo Silva --- plugins/filter_log_to_metrics/log_to_metrics.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/filter_log_to_metrics/log_to_metrics.c b/plugins/filter_log_to_metrics/log_to_metrics.c index 5db50a4f33e..cb7f285d882 100644 --- a/plugins/filter_log_to_metrics/log_to_metrics.c +++ b/plugins/filter_log_to_metrics/log_to_metrics.c @@ -932,9 +932,9 @@ static struct flb_config_map config_map[] = { "Enable kubernetes log metric fields" }, { - FLB_CONFIG_MAP_STR, "label", NULL, + FLB_CONFIG_MAP_STR, "add_label", NULL, FLB_CONFIG_MAP_MULT, FLB_FALSE, 0, - "Specify message field that should be included in the metric" + "Add a label to the metric by supporting record accessor pattern" }, { FLB_CONFIG_MAP_STR, "label_field", NULL, From d2021f788d1320c7caac04252426aa8eefd32da6 Mon Sep 17 00:00:00 2001 From: Kushal Azim Ekram Date: Sat, 23 Sep 2023 10:49:04 -0700 Subject: [PATCH 282/315] out_azure: improvement: add table prefix support for Azure Log Analytics plugin (#7663) --------- Signed-off-by: Kushal Azim Ekram --- plugins/out_azure/azure.c | 45 +++++++++++++++++++++++++++++++--- plugins/out_azure/azure.h | 3 +++ plugins/out_azure/azure_conf.c | 20 +++++++++++++++ 3 files changed, 65 insertions(+), 3 deletions(-) diff --git a/plugins/out_azure/azure.c b/plugins/out_azure/azure.c index 905e23f90f9..d4322fb6591 100644 --- a/plugins/out_azure/azure.c +++ b/plugins/out_azure/azure.c @@ -26,6 +26,8 @@ #include #include #include +#include +#include #include #include "azure.h" @@ -47,6 +49,7 @@ static int cb_azure_init(struct flb_output_instance *ins, } static int azure_format(const void *in_buf, size_t in_bytes, + flb_sds_t tag, flb_sds_t *tag_val_out, char **out_buf, size_t *out_size, struct flb_azure *ctx) { @@ -68,6 +71,7 @@ static int azure_format(const void *in_buf, size_t in_bytes, int len; struct flb_log_event_decoder log_decoder; struct flb_log_event log_event; + flb_sds_t tmp = NULL; int ret; /* Count number of items */ @@ -97,6 +101,23 @@ static int azure_format(const void *in_buf, size_t in_bytes, map = *log_event.body; map_size = map.via.map.size; + if (ctx->log_type_key) { + tmp = flb_ra_translate(ctx->ra_prefix_key, + tag, flb_sds_len(tag), + map, NULL); + if (!tmp) { + flb_plg_error(ctx->ins, "Tagged record translation failed!"); + } + else if (flb_sds_is_empty(tmp)) { + flb_plg_warn(ctx->ins, "Record accessor key not matched"); + flb_sds_destroy(tmp); + } + else { + /* tag_val_out must be destroyed by the caller */ + *tag_val_out = tmp; + } + } + msgpack_pack_map(&mp_pck, map_size + 1); /* Append the time key */ @@ -160,6 +181,7 @@ static int azure_format(const void *in_buf, size_t in_bytes, } static int build_headers(struct flb_http_client *c, + flb_sds_t log_type, size_t content_length, struct flb_azure *ctx) { @@ -238,7 +260,7 @@ static int build_headers(struct flb_http_client *c, /* Append headers */ flb_http_add_header(c, "User-Agent", 10, "Fluent-Bit", 10); flb_http_add_header(c, "Log-Type", 8, - ctx->log_type, flb_sds_len(ctx->log_type)); + log_type, flb_sds_len(log_type)); flb_http_add_header(c, "Content-Type", 12, "application/json", 16); flb_http_add_header(c, "x-ms-date", 9, rfc1123date, flb_sds_len(rfc1123date)); @@ -283,6 +305,7 @@ static void cb_azure_flush(struct flb_event_chunk *event_chunk, struct flb_connection *u_conn; struct flb_http_client *c; flb_sds_t payload; + flb_sds_t final_log_type = NULL; (void) i_ins; (void) config; @@ -294,7 +317,12 @@ static void cb_azure_flush(struct flb_event_chunk *event_chunk, /* Convert binary logs into a JSON payload */ ret = azure_format(event_chunk->data, event_chunk->size, - &buf_data, &buf_size, ctx); + event_chunk->tag, &final_log_type, &buf_data, &buf_size, ctx); + /* If cannot get matching record using log_type_prefix, use log_type directly */ + if (!final_log_type) { + final_log_type = ctx->log_type; + } + if (ret == -1) { flb_upstream_conn_release(u_conn); FLB_OUTPUT_RETURN(FLB_ERROR); @@ -307,7 +335,7 @@ static void cb_azure_flush(struct flb_event_chunk *event_chunk, flb_http_buffer_size(c, FLB_HTTP_DATA_SIZE_MAX); /* Append headers and Azure signature */ - ret = build_headers(c, flb_sds_len(payload), ctx); + ret = build_headers(c, final_log_type, flb_sds_len(payload), ctx); if (ret == -1) { flb_plg_error(ctx->ins, "error composing signature"); flb_sds_destroy(payload); @@ -339,6 +367,9 @@ static void cb_azure_flush(struct flb_event_chunk *event_chunk, } /* Cleanup */ + if (final_log_type != ctx->log_type) { + flb_sds_destroy(final_log_type); + } flb_http_client_destroy(c); flb_sds_destroy(payload); flb_upstream_conn_release(u_conn); @@ -380,6 +411,14 @@ static struct flb_config_map config_map[] = { "The name of the event type." }, + { + FLB_CONFIG_MAP_STR, "log_type_key", NULL, + 0, FLB_TRUE, offsetof(struct flb_azure, log_type_key), + "If included, the value for this key will be looked upon in the record " + "and if present, will over-write the `log_type`. If the key/value " + "is not found in the record then the `log_type` option will be used. " + }, + { FLB_CONFIG_MAP_STR, "time_key", FLB_AZURE_TIME_KEY, 0, FLB_TRUE, offsetof(struct flb_azure, time_key), diff --git a/plugins/out_azure/azure.h b/plugins/out_azure/azure.h index c696d39f71b..192d41ac8ea 100644 --- a/plugins/out_azure/azure.h +++ b/plugins/out_azure/azure.h @@ -30,11 +30,13 @@ #include #include #include +#include struct flb_azure { /* account setup */ flb_sds_t customer_id; flb_sds_t log_type; + flb_sds_t log_type_key; flb_sds_t shared_key; flb_sds_t dec_shared_key; @@ -45,6 +47,7 @@ struct flb_azure { /* records */ flb_sds_t time_key; + struct flb_record_accessor *ra_prefix_key; /* time_generated: on/off */ int time_generated; diff --git a/plugins/out_azure/azure_conf.c b/plugins/out_azure/azure_conf.c index d93cac9dc9d..9f8f8a05f92 100644 --- a/plugins/out_azure/azure_conf.c +++ b/plugins/out_azure/azure_conf.c @@ -20,6 +20,8 @@ #include #include #include +#include +#include #include "azure.h" #include "azure_conf.h" @@ -33,6 +35,7 @@ struct flb_azure *flb_azure_conf_create(struct flb_output_instance *ins, const char *tmp; struct flb_upstream *upstream; struct flb_azure *ctx; + struct flb_record_accessor *ra_prefix_key = NULL; /* Allocate config context */ ctx = flb_calloc(1, sizeof(struct flb_azure)); @@ -84,6 +87,20 @@ struct flb_azure *flb_azure_conf_create(struct flb_output_instance *ins, } flb_sds_len_set(ctx->dec_shared_key, olen); + /* config: 'log_type_key' */ + if (ctx->log_type_key) { + ra_prefix_key = flb_ra_create(ctx->log_type_key, FLB_TRUE); + + if (!ra_prefix_key) { + flb_plg_error(ctx->ins, "invalid log_type_key pattern '%s'", ctx->log_type_key); + flb_azure_conf_destroy(ctx); + return NULL; + } + else { + ctx->ra_prefix_key = ra_prefix_key; + } + } + /* Validate hostname given by command line or 'Host' property */ if (!ins->host.name && !ctx->customer_id) { flb_plg_error(ctx->ins, "property 'customer_id' is not defined"); @@ -190,6 +207,9 @@ int flb_azure_conf_destroy(struct flb_azure *ctx) if (ctx->uri) { flb_sds_destroy(ctx->uri); } + if (ctx->ra_prefix_key) { + flb_ra_destroy(ctx->ra_prefix_key); + } if (ctx->u) { flb_upstream_destroy(ctx->u); } From 566eb09057ec859cbff08bfb6eb1c3e092828d99 Mon Sep 17 00:00:00 2001 From: DavidKorczynski Date: Sat, 23 Sep 2023 19:05:06 +0100 Subject: [PATCH 283/315] out_logdna: remove unused store (#7629) --- plugins/out_logdna/logdna.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/plugins/out_logdna/logdna.c b/plugins/out_logdna/logdna.c index 798159f6d40..e3ab9f56fa9 100644 --- a/plugins/out_logdna/logdna.c +++ b/plugins/out_logdna/logdna.c @@ -305,21 +305,22 @@ static struct flb_logdna *logdna_config_create(struct flb_output_instance *ins, tmp = NULL; hostname = (char *) flb_env_get(config->env, "HOSTNAME"); if (hostname) { - len = strlen(hostname); ctx->_hostname = flb_sds_create(hostname); } else { ctx->_hostname = flb_sds_create("unknown"); } - if (!ctx->_hostname) { - flb_free(ctx); - return NULL; - } } else { ctx->_hostname = flb_sds_create(ctx->hostname); } + /* Bail if unsuccessful hostname creation */ + if (!ctx->_hostname) { + flb_free(ctx); + return NULL; + } + /* Create Upstream connection context */ upstream = flb_upstream_create(config, ctx->logdna_host, From 6657dc9ae97c91bd538a83cb93b4d794ddeca7e5 Mon Sep 17 00:00:00 2001 From: DavidKorczynski Date: Sat, 23 Sep 2023 19:06:15 +0100 Subject: [PATCH 284/315] out_azure_logs_ingestion: fix NULL dereference (#7624) The code checks if `ctx` is NULL, and if it is' NULL proceeds to dereference `ctx` by way of `ctx->ins`. As such, there will always be a NULL dereference if the condition `if (!ctx)` is true. This fixes it by removing the dereference. --- plugins/out_azure_logs_ingestion/azure_logs_ingestion.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/out_azure_logs_ingestion/azure_logs_ingestion.c b/plugins/out_azure_logs_ingestion/azure_logs_ingestion.c index 90504537627..9b839ef7e01 100644 --- a/plugins/out_azure_logs_ingestion/azure_logs_ingestion.c +++ b/plugins/out_azure_logs_ingestion/azure_logs_ingestion.c @@ -43,7 +43,7 @@ static int cb_azure_logs_ingestion_init(struct flb_output_instance *ins, /* Allocate and initialize a context from configuration */ ctx = flb_az_li_ctx_create(ins, config); if (!ctx) { - flb_plg_error(ctx->ins, "configuration failed"); + flb_plg_error(ins, "configuration failed"); return -1; } From 95d3df1184bc199e8e4ff22bc539c2dbb954f9be Mon Sep 17 00:00:00 2001 From: DavidKorczynski Date: Sat, 23 Sep 2023 19:06:45 +0100 Subject: [PATCH 285/315] tests: internal: fuzzers: add fstore fuzzer (#6465) Signed-off-by: David Korczynski --- tests/internal/fuzzers/CMakeLists.txt | 1 + tests/internal/fuzzers/fstore_fuzzer.c | 69 ++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 tests/internal/fuzzers/fstore_fuzzer.c diff --git a/tests/internal/fuzzers/CMakeLists.txt b/tests/internal/fuzzers/CMakeLists.txt index b3c4ce9bb42..e76be548a20 100644 --- a/tests/internal/fuzzers/CMakeLists.txt +++ b/tests/internal/fuzzers/CMakeLists.txt @@ -12,6 +12,7 @@ set(UNIT_TESTS_FILES flb_json_fuzzer.c flb_mp_fuzzer.c filter_stdout_fuzzer.c + fstore_fuzzer.c parser_fuzzer.c parse_json_fuzzer.c parse_logfmt_fuzzer.c diff --git a/tests/internal/fuzzers/fstore_fuzzer.c b/tests/internal/fuzzers/fstore_fuzzer.c new file mode 100644 index 00000000000..dd7a6cf8b96 --- /dev/null +++ b/tests/internal/fuzzers/fstore_fuzzer.c @@ -0,0 +1,69 @@ +/* Fluent Bit + * ========== + * Copyright (C) 2019-2022 The Fluent Bit Authors + * Copyright (C) 2015-2018 Treasure Data Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include + + +#define FSF_STORE_PATH "/tmp/flb-fstore" + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + int ret; + void *out_buf; + size_t out_size; + struct stat st_data; + struct flb_fstore *fs; + struct flb_fstore_stream *st; + struct flb_fstore_file *fsf; + + cio_utils_recursive_delete(FSF_STORE_PATH); + fs = flb_fstore_create(FSF_STORE_PATH, FLB_FSTORE_FS); + st = flb_fstore_stream_create(fs, "abc"); + if (st != NULL) { + fsf = flb_fstore_file_create(fs, st, "example.txt", size); + + if (fsf != NULL) { + ret = flb_fstore_file_append(fsf, data, size); + if (ret == 0) { + ret = flb_fstore_file_content_copy(fs, fsf, &out_buf, &out_size); + if (ret == 0) { + assert(memcmp(out_buf, data, size) == 0); + } + flb_free(out_buf); + } + } + } + + flb_fstore_dump(fs); + flb_fstore_destroy(fs); + return 0; +} From 3a4df5395f960b64b091e48d887f0e71c82498a8 Mon Sep 17 00:00:00 2001 From: Takahiro Yamashita Date: Sun, 24 Sep 2023 03:07:59 +0900 Subject: [PATCH 286/315] log_event_encoder: fix typo (#7646) Signed-off-by: Takahiro Yamashita --- src/flb_log_event_encoder.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/flb_log_event_encoder.c b/src/flb_log_event_encoder.c index 1574b697d4a..bb6507b8cbe 100644 --- a/src/flb_log_event_encoder.c +++ b/src/flb_log_event_encoder.c @@ -376,7 +376,7 @@ const char *flb_log_event_encoder_get_error_description(int error_code) break; case FLB_EVENT_ENCODER_ERROR_SERIALIZATION_FAILURE: - ret = "Serializatoin failure"; + ret = "Serialization failure"; break; case FLB_EVENT_ENCODER_ERROR_INVALID_VALUE_TYPE: From 2a0b25cf4af6e506dd992047035ecea4876e7397 Mon Sep 17 00:00:00 2001 From: Takahiro Yamashita Date: Sun, 24 Sep 2023 03:08:21 +0900 Subject: [PATCH 287/315] in_systemd: init last_tag to fix valgrind warning (#7247) Signed-off-by: Takahiro Yamashita --- plugins/in_systemd/systemd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/in_systemd/systemd.c b/plugins/in_systemd/systemd.c index fbb2293fdf9..02f81144b78 100644 --- a/plugins/in_systemd/systemd.c +++ b/plugins/in_systemd/systemd.c @@ -94,7 +94,7 @@ static int in_systemd_collect(struct flb_input_instance *ins, #endif char *tag = NULL; char new_tag[PATH_MAX]; - char last_tag[PATH_MAX]; + char last_tag[PATH_MAX] = {0}; size_t tag_len; size_t last_tag_len = 0; const void *data; From 859987b42d14a901ee140955f9359de75ce0136b Mon Sep 17 00:00:00 2001 From: Takahiro Yamashita Date: Sun, 5 Mar 2023 16:11:18 +0900 Subject: [PATCH 288/315] config: support sp.convert_from_str_to_num Signed-off-by: Takahiro Yamashita --- include/fluent-bit/flb_config.h | 2 ++ src/flb_config.c | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/include/fluent-bit/flb_config.h b/include/fluent-bit/flb_config.h index a00ac48bf55..a5955908b88 100644 --- a/include/fluent-bit/flb_config.h +++ b/include/fluent-bit/flb_config.h @@ -245,6 +245,7 @@ struct flb_config { #ifdef FLB_HAVE_STREAM_PROCESSOR char *stream_processor_file; /* SP configuration file */ void *stream_processor_ctx; /* SP context */ + int stream_processor_str_conv; /* SP enable converting from string to number */ /* * Temporal list to hold tasks defined before the SP context is created @@ -322,6 +323,7 @@ enum conf_type { #define FLB_CONF_STR_PARSERS_FILE "Parsers_File" #define FLB_CONF_STR_PLUGINS_FILE "Plugins_File" #define FLB_CONF_STR_STREAMS_FILE "Streams_File" +#define FLB_CONF_STR_STREAMS_STR_CONV "sp.convert_from_str_to_num" #define FLB_CONF_STR_CONV_NAN "json.convert_nan_to_null" /* FLB_HAVE_HTTP_SERVER */ diff --git a/src/flb_config.c b/src/flb_config.c index 34a4e727b0e..882a93c7c1c 100644 --- a/src/flb_config.c +++ b/src/flb_config.c @@ -168,6 +168,9 @@ struct flb_service_config service_configs[] = { {FLB_CONF_STR_STREAMS_FILE, FLB_CONF_TYPE_STR, offsetof(struct flb_config, stream_processor_file)}, + {FLB_CONF_STR_STREAMS_STR_CONV, + FLB_CONF_TYPE_BOOL, + offsetof(struct flb_config, stream_processor_str_conv)}, #endif #ifdef FLB_HAVE_CHUNK_TRACE @@ -289,6 +292,7 @@ struct flb_config *flb_config_init() #ifdef FLB_HAVE_STREAM_PROCESSOR flb_slist_create(&config->stream_processor_tasks); + config->stream_processor_str_conv = FLB_TRUE; #endif flb_slist_create(&config->external_plugins); From a3aa6e1a0da4ac64a005a42b4308d23b9bdfa33b Mon Sep 17 00:00:00 2001 From: Takahiro Yamashita Date: Sun, 12 Mar 2023 08:49:23 +0900 Subject: [PATCH 289/315] sp: prevent converting from string to num if config is set Signed-off-by: Takahiro Yamashita --- include/fluent-bit/stream_processor/flb_sp.h | 2 +- src/stream_processor/flb_sp.c | 19 +++++++++++-------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/include/fluent-bit/stream_processor/flb_sp.h b/include/fluent-bit/stream_processor/flb_sp.h index eacc929fe35..455909ab1d3 100644 --- a/include/fluent-bit/stream_processor/flb_sp.h +++ b/include/fluent-bit/stream_processor/flb_sp.h @@ -171,7 +171,7 @@ int sp_process_data(const char *tag, int tag_len, int sp_process_data_aggr(const char *buf_data, size_t buf_size, const char *tag, int tag_len, struct flb_sp_task *task, - struct flb_sp *sp); + struct flb_sp *sp, int convert_str_to_num); void package_results(const char *tag, int tag_len, char **out_buf, size_t *out_size, struct flb_sp_task *task); diff --git a/src/stream_processor/flb_sp.c b/src/stream_processor/flb_sp.c index 26f9d75865d..00eb2f18b78 100644 --- a/src/stream_processor/flb_sp.c +++ b/src/stream_processor/flb_sp.c @@ -349,7 +349,8 @@ static int string_to_number(const char *str, int len, int64_t *i, double *d) * * This function aims to take care of strings representing a value too. */ -static int object_to_number(msgpack_object obj, int64_t *i, double *d) +static int object_to_number(msgpack_object obj, int64_t *i, double *d, + int convert_str_to_num) { int ret; int64_t i_out; @@ -366,7 +367,7 @@ static int object_to_number(msgpack_object obj, int64_t *i, double *d) *d = obj.via.f64; return FLB_STR_FLOAT; } - else if (obj.type == MSGPACK_OBJECT_STR) { + else if (obj.type == MSGPACK_OBJECT_STR && convert_str_to_num == FLB_TRUE) { /* A numeric representation of a string should not exceed 19 chars */ if (obj.via.str.size > 19) { return -1; @@ -1230,7 +1231,8 @@ void package_results(const char *tag, int tag_len, } static struct aggregate_node * sp_process_aggregate_data(struct flb_sp_task *task, - msgpack_object map) + msgpack_object map, + int convert_str_to_num) { int i; int ret; @@ -1289,7 +1291,7 @@ static struct aggregate_node * sp_process_aggregate_data(struct flb_sp_task *tas values_found++; /* Convert string to number if that is possible */ - ret = object_to_number(sval->o, &ival, &dval); + ret = object_to_number(sval->o, &ival, &dval, convert_str_to_num); if (ret == -1) { if (sval->o.type == MSGPACK_OBJECT_STR) { gb_nums[key_id].type = FLB_SP_STRING; @@ -1386,7 +1388,8 @@ static struct aggregate_node * sp_process_aggregate_data(struct flb_sp_task *tas int sp_process_data_aggr(const char *buf_data, size_t buf_size, const char *tag, int tag_len, struct flb_sp_task *task, - struct flb_sp *sp) + struct flb_sp *sp, + int convert_str_to_num) { int i; int ok; @@ -1444,7 +1447,7 @@ int sp_process_data_aggr(const char *buf_data, size_t buf_size, } } - aggr_node = sp_process_aggregate_data(task, map); + aggr_node = sp_process_aggregate_data(task, map, convert_str_to_num); if (!aggr_node) { continue; @@ -1497,7 +1500,7 @@ int sp_process_data_aggr(const char *buf_data, size_t buf_size, ival = 0; dval = 0.0; if (ckey->aggr_func != FLB_SP_NOP) { - ret = object_to_number(sval->o, &ival, &dval); + ret = object_to_number(sval->o, &ival, &dval, convert_str_to_num); if (ret == -1) { /* Value cannot be represented as a number */ key_id++; @@ -1987,7 +1990,7 @@ int flb_sp_do(struct flb_sp *sp, struct flb_input_instance *in, if (task->aggregate_keys == FLB_TRUE) { ret = sp_process_data_aggr(buf_data, buf_size, tag, tag_len, - task, sp); + task, sp, in->config->stream_processor_str_conv); if (ret == -1) { flb_error("[sp] error processing records for '%s'", From fa30a2b1ef932095a268b7e3fdbfb835a950dee8 Mon Sep 17 00:00:00 2001 From: Takahiro Yamashita Date: Sun, 19 Mar 2023 08:52:28 +0900 Subject: [PATCH 290/315] tests: internal: sp: add test case for conv_from_str_to_num Signed-off-by: Takahiro Yamashita --- tests/internal/stream_processor.c | 139 +++++++++++++++++++++++++++++- 1 file changed, 136 insertions(+), 3 deletions(-) diff --git a/tests/internal/stream_processor.c b/tests/internal/stream_processor.c index 64679027862..c9e59f50407 100644 --- a/tests/internal/stream_processor.c +++ b/tests/internal/stream_processor.c @@ -23,10 +23,12 @@ #include #include #include +#include #include #include #include #include +#include #include "flb_tests_internal.h" #include "include/sp_invalid_queries.h" @@ -107,7 +109,7 @@ int flb_sp_do_test(struct flb_sp *sp, struct flb_sp_task *task, if (task->aggregate_keys == FLB_TRUE) { ret = sp_process_data_aggr(data_buf->buffer, data_buf->size, tag, tag_len, - task, sp); + task, sp, FLB_TRUE); if (ret == -1) { flb_error("[sp] error error processing records for '%s'", task->name); @@ -119,8 +121,7 @@ int flb_sp_do_test(struct flb_sp *sp, struct flb_sp_task *task, task->name); return -1; } - - if (task->window.type == FLB_SP_WINDOW_DEFAULT) { + if (task->window.type == FLB_SP_WINDOW_DEFAULT || task->window.type == FLB_SP_WINDOW_TUMBLING) { package_results(tag, tag_len, &out_buf->buffer, &out_buf->size, task); } @@ -751,11 +752,143 @@ static void test_snapshot() #endif } +static void test_conv_from_str_to_num() +{ + struct flb_config *config = NULL; + struct flb_sp *sp = NULL; + struct flb_sp_task *task = NULL; + struct sp_buffer out_buf; + struct sp_buffer data_buf; + msgpack_sbuffer sbuf; + msgpack_packer pck; + msgpack_unpacked result; + size_t off = 0; + char json[4096] = {0}; + int ret; + +#ifdef _WIN32 + WSADATA wsa_data; + + WSAStartup(0x0201, &wsa_data); +#endif + out_buf.buffer = NULL; + + config = flb_config_init(); + config->evl = mk_event_loop_create(256); + + ret = flb_storage_create(config); + if (!TEST_CHECK(ret == 0)) { + TEST_MSG("flb_storage_create failed"); + flb_config_exit(config); + return; + } + + sp = flb_sp_create(config); + if (!TEST_CHECK(sp != NULL)) { + TEST_MSG("[sp test] cannot create stream processor context"); + goto test_conv_from_str_to_num_end; + } + + task = flb_sp_task_create(sp, "tail.0", "CREATE STREAM test WITH (tag=\'test\') AS SELECT word, num, COUNT(*) FROM STREAM:tail.0 WINDOW TUMBLING (1 SECOND) GROUP BY word, num;"); + if (!TEST_CHECK(task != NULL)) { + TEST_MSG("[sp test] wrong check 'conv', fix it!"); + goto test_conv_from_str_to_num_end; + } + + /* Create input data */ + msgpack_sbuffer_init(&sbuf); + msgpack_packer_init(&pck, &sbuf, msgpack_sbuffer_write); + msgpack_pack_array(&pck, 2); + flb_pack_time_now(&pck); + msgpack_pack_map(&pck, 2); + + msgpack_pack_str(&pck, 4); + msgpack_pack_str_body(&pck, "word", 4); + msgpack_pack_str(&pck, 4); + msgpack_pack_str_body(&pck, "hoge", 4); + + msgpack_pack_str(&pck, 3); + msgpack_pack_str_body(&pck, "num", 3); + msgpack_pack_str(&pck, 6); + msgpack_pack_str_body(&pck, "123456", 6); + + data_buf.buffer = sbuf.data; + data_buf.size = sbuf.size; + + out_buf.buffer = NULL; + out_buf.size = 0; + + /* Exec stream processor */ + ret = flb_sp_do_test(sp, task, "tail.0", strlen("tail.0"), &data_buf, &out_buf); + if (!TEST_CHECK(ret == 0)) { + TEST_MSG("flb_sp_do_test failed"); + msgpack_sbuffer_destroy(&sbuf); + goto test_conv_from_str_to_num_end; + } + + if (!TEST_CHECK(out_buf.size > 0)) { + TEST_MSG("out_buf size is 0"); + msgpack_sbuffer_destroy(&sbuf); + goto test_conv_from_str_to_num_end; + } + + + /* Check output buffer. It should contain a number 123456 not a string "123456" */ + + msgpack_unpacked_init(&result); + ret = msgpack_unpack_next(&result, out_buf.buffer, out_buf.size, &off); + if (!TEST_CHECK(ret == MSGPACK_UNPACK_SUCCESS)) { + TEST_MSG("failed to unpack ret=%d", ret); + msgpack_unpacked_destroy(&result); + msgpack_sbuffer_destroy(&sbuf); + goto test_conv_from_str_to_num_end; + } + + ret = flb_msgpack_to_json(&json[0], sizeof(json), &result.data); + if (!TEST_CHECK(ret > 0)) { + TEST_MSG("flb_msgpack_to_json failed"); + msgpack_unpacked_destroy(&result); + msgpack_sbuffer_destroy(&sbuf); + goto test_conv_from_str_to_num_end; + } + + if (!TEST_CHECK(strstr(json,"123456") != NULL)) { + TEST_MSG("number not found"); + msgpack_unpacked_destroy(&result); + msgpack_sbuffer_destroy(&sbuf); + goto test_conv_from_str_to_num_end; + } + if (!TEST_CHECK(strstr(json,"\"123456\"") == NULL)) { + TEST_MSG("output should be number type"); + msgpack_unpacked_destroy(&result); + msgpack_sbuffer_destroy(&sbuf); + goto test_conv_from_str_to_num_end; + } + + msgpack_unpacked_destroy(&result); + msgpack_sbuffer_destroy(&sbuf); + + test_conv_from_str_to_num_end: + if (out_buf.buffer != NULL) { + flb_free(out_buf.buffer); + } + +#ifdef _WIN32 + WSACleanup(); +#endif + if (sp != NULL) { + flb_sp_destroy(sp); + } + flb_storage_destroy(config); + flb_config_exit(config); +} + TEST_LIST = { { "invalid_queries", invalid_queries}, { "select_keys", test_select_keys}, { "select_subkeys", test_select_subkeys}, { "window", test_window}, { "snapshot", test_snapshot}, + { "conv_from_str_to_num", test_conv_from_str_to_num}, { NULL } }; From 3b6d9030edbd87359a3e69ac5867bf2d576ad736 Mon Sep 17 00:00:00 2001 From: Takahiro Yamashita Date: Sat, 17 Sep 2022 08:57:39 +0900 Subject: [PATCH 291/315] out_es: check if host contains port number Some cloud id format is "$:$" . e.g. https://github.com/elastic/beats/blob/v8.4.1/libbeat/cloudid/cloudid_test.go#L60 This patch is to check if a port number is contained or not. Signed-off-by: Takahiro Yamashita --- plugins/out_es/es_conf.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/plugins/out_es/es_conf.c b/plugins/out_es/es_conf.c index 450a3482bdc..48c8c3e2516 100644 --- a/plugins/out_es/es_conf.c +++ b/plugins/out_es/es_conf.c @@ -44,6 +44,7 @@ static flb_sds_t extract_cloud_host(struct flb_elasticsearch *ctx, char *colon; char *region; char *host; + char *port = NULL; char buf[256] = {0}; char cloud_host_buf[256] = {0}; const char dollar[2] = "$"; @@ -71,9 +72,27 @@ static flb_sds_t extract_cloud_host(struct flb_elasticsearch *ctx, if (host == NULL) { return NULL; } + + /* + * Some cloud id format is "$:$" . + * e.g. https://github.com/elastic/beats/blob/v8.4.1/libbeat/cloudid/cloudid_test.go#L60 + * + * It means the variable "host" can contains ':' and port number. + */ + colon = strchr(host, ':'); + if (colon != NULL) { + /* host contains host number */ + *colon = '\0'; /* remove port number from host */ + port = colon+1; + } + strcpy(cloud_host_buf, host); strcat(cloud_host_buf, "."); strcat(cloud_host_buf, region); + if (port != NULL) { + strcat(cloud_host_buf, ":"); + strcat(cloud_host_buf, port); + } return flb_sds_create(cloud_host_buf); } From df1ad29fcd7216132a82e4ad1a1a87ec31d5c484 Mon Sep 17 00:00:00 2001 From: Hiroshi Hatake Date: Fri, 28 Jul 2023 00:13:33 +0900 Subject: [PATCH 292/315] tests: internal: input_chunk: Use the different storage.path per tests This is because different storage.paths should be used per test. Sometimes this cause failure for retrieving the file contents to prepare the data for input_chunk test cases: ```log Test input_chunk_exceed_limit... [ FAILED ] input_chunk.c:91: Check getting output file content: ~/GitHub/fluent-bit/tests/internal/data/input_chunk/out/a_thousand_plus_one_bytes.out... failed [2023/07/28 00:03:09] [error] [~/GitHub/fluent-bit/tests/internal/input_chunk.c:56 errno=0] Success ``` After splitting the storage.path per test case, this error won't happen. Signed-off-by: Hiroshi Hatake --- tests/internal/input_chunk.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/internal/input_chunk.c b/tests/internal/input_chunk.c index 757e3b4cc0c..7154b324baf 100644 --- a/tests/internal/input_chunk.c +++ b/tests/internal/input_chunk.c @@ -162,6 +162,7 @@ void do_test(char *system, const char *target, ...) int out_ffd; char path[PATH_MAX]; struct tail_test_result result = {0}; + char storage_path[PATH_MAX]; result.nMatched = 0; result.target = target; @@ -175,10 +176,12 @@ void do_test(char *system, const char *target, ...) ctx = flb_create(); + snprintf(storage_path, sizeof(storage_path) - 1, "/tmp/input-chunk-test-%s", target); + /* create chunks in /tmp folder */ ret = flb_service_set(ctx, "Parsers_File", DPATH "parser.conf", - "storage.path", "/tmp/input-chunk-test/", + "storage.path", storage_path, "Log_Level", "error", NULL); TEST_CHECK_(ret == 0, "setting service options"); From 6bb2a1230691f15a104ea74482d043cef7b62f66 Mon Sep 17 00:00:00 2001 From: David Korczynski Date: Tue, 26 Sep 2023 05:57:33 +0100 Subject: [PATCH 293/315] tests: fuzzers: fix fstore div-by-zero Signed-off-by: David Korczynski --- tests/internal/fuzzers/fstore_fuzzer.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/internal/fuzzers/fstore_fuzzer.c b/tests/internal/fuzzers/fstore_fuzzer.c index dd7a6cf8b96..92ecf5d7a2d 100644 --- a/tests/internal/fuzzers/fstore_fuzzer.c +++ b/tests/internal/fuzzers/fstore_fuzzer.c @@ -45,6 +45,20 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) struct flb_fstore_stream *st; struct flb_fstore_file *fsf; + /* Set flb_malloc_mod to be fuzzer-data dependent */ + if (size < 4) { + return 0; + } + flb_malloc_p = 0; + flb_malloc_mod = *(int*)data; + data += 4; + size -= 4; + + /* Avoid division by zero for modulo operations */ + if (flb_malloc_mod == 0) { + flb_malloc_mod = 1; + } + cio_utils_recursive_delete(FSF_STORE_PATH); fs = flb_fstore_create(FSF_STORE_PATH, FLB_FSTORE_FS); st = flb_fstore_stream_create(fs, "abc"); From 183f0d4ed26d49efa481724b3072531161e15db1 Mon Sep 17 00:00:00 2001 From: Phillip Whelan Date: Mon, 25 Sep 2023 16:39:43 -0300 Subject: [PATCH 294/315] filter_log_to_metrics: process the 'add_label' property, which was renamed from 'label'. Signed-off-by: Phillip Whelan --- plugins/filter_log_to_metrics/log_to_metrics.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/filter_log_to_metrics/log_to_metrics.c b/plugins/filter_log_to_metrics/log_to_metrics.c index cb7f285d882..a61e4827f34 100644 --- a/plugins/filter_log_to_metrics/log_to_metrics.c +++ b/plugins/filter_log_to_metrics/log_to_metrics.c @@ -268,7 +268,7 @@ static int set_labels(struct log_to_metrics_ctx *ctx, snprintf(label_keys[counter], MAX_LABEL_LENGTH - 1, "%s", kv->val); counter++; } - else if (strcasecmp(kv->key, "label") == 0) { + else if (strcasecmp(kv->key, "add_label") == 0) { split = flb_utils_split(kv->val, ' ', 1); if (mk_list_size(split) != 2) { flb_plg_error(ctx->ins, "invalid label, expected name and key"); From 10e4d87aaa862938b9efeb0a179b2a0dab3a1a99 Mon Sep 17 00:00:00 2001 From: Phillip Whelan Date: Mon, 25 Sep 2023 16:40:13 -0300 Subject: [PATCH 295/315] filter_log_to_metrics: fix label test to use 'add_label'. Signed-off-by: Phillip Whelan --- tests/runtime/filter_log_to_metrics.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/runtime/filter_log_to_metrics.c b/tests/runtime/filter_log_to_metrics.c index b8c8dba1dc2..eb38af61ce4 100644 --- a/tests/runtime/filter_log_to_metrics.c +++ b/tests/runtime/filter_log_to_metrics.c @@ -669,7 +669,7 @@ void flb_test_log_to_metrics_label(void) "metric_name", "test", "metric_description", "Counts messages", "kubernetes_mode", "off", - "label", "pod_name $kubernetes['pod_name']", + "add_label", "pod_name $kubernetes['pod_name']", NULL); out_ffd = flb_output(ctx, (char *) "lib", (void *)&cb_data); From ea3c0832ea72d9adce428aabac8f36e66a41d7f8 Mon Sep 17 00:00:00 2001 From: Leonardo Alminana Date: Tue, 26 Sep 2023 10:15:14 +0200 Subject: [PATCH 296/315] tests: internal: stream_processor: fixed memory leak Signed-off-by: Leonardo Alminana --- tests/internal/stream_processor.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/tests/internal/stream_processor.c b/tests/internal/stream_processor.c index c9e59f50407..6e9b631713c 100644 --- a/tests/internal/stream_processor.c +++ b/tests/internal/stream_processor.c @@ -517,6 +517,13 @@ static void test_window() usleep(800000); } + if (out_buf.buffer != NULL) { + flb_free(out_buf.buffer); + + out_buf.buffer = NULL; + out_buf.size = 0; + } + flb_sp_fd_event_test(task->window.fd, task, &out_buf); flb_info("[sp test] id=%i, SQL => '%s'", check->id, check->exec); @@ -560,13 +567,26 @@ static void test_window() /* Hopping event */ if ((t + 1) % check->window_hop_sec == 0) { + if (out_buf.buffer != NULL) { + flb_free(out_buf.buffer); + + out_buf.buffer = NULL; + out_buf.size = 0; + } + flb_sp_fd_event_test(task->window.fd_hop, task, &out_buf); } /* Window event */ if ((t + 1) % check->window_size_sec == 0 || (t + 1 > check->window_size_sec && (t + 1 - check->window_size_sec) % check->window_hop_sec == 0)) { - flb_free(out_buf.buffer); + if (out_buf.buffer != NULL) { + flb_free(out_buf.buffer); + + out_buf.buffer = NULL; + out_buf.size = 0; + } + flb_sp_fd_event_test(task->window.fd, task, &out_buf); } flb_free(data_buf.buffer); From 9c53a796f1ba2f0e3cf5f59f060996bb9614aed8 Mon Sep 17 00:00:00 2001 From: Leonardo Alminana Date: Tue, 26 Sep 2023 10:45:56 +0200 Subject: [PATCH 297/315] tests: internal: stream_processor: fixed memory leak Signed-off-by: Leonardo Alminana --- tests/internal/stream_processor.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/internal/stream_processor.c b/tests/internal/stream_processor.c index 6e9b631713c..44e983a0689 100644 --- a/tests/internal/stream_processor.c +++ b/tests/internal/stream_processor.c @@ -503,6 +503,13 @@ static void test_window() /* We ingest the buffer every second */ for (t = 0; t < check->window_size_sec; t++) { + if (out_buf.buffer != NULL) { + flb_free(out_buf.buffer); + + out_buf.buffer = NULL; + out_buf.size = 0; + } + ret = flb_sp_do_test(sp, task, "samples", strlen("samples"), &data_buf, &out_buf); From 32379cbc9834bfe6a1d7a56aa153ef38e7f73eab Mon Sep 17 00:00:00 2001 From: Leonardo Alminana Date: Mon, 25 Sep 2023 17:28:08 +0200 Subject: [PATCH 298/315] tests: internal: sp: added environment initialization calls Signed-off-by: Leonardo Alminana --- tests/internal/stream_processor.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/internal/stream_processor.c b/tests/internal/stream_processor.c index 44e983a0689..9afda0bf545 100644 --- a/tests/internal/stream_processor.c +++ b/tests/internal/stream_processor.c @@ -18,6 +18,7 @@ * limitations under the License. */ +#include #include #include #include @@ -200,6 +201,8 @@ static void invalid_queries() struct flb_sp *sp; struct flb_sp_task *task; + flb_init_env(); + /* Total number of checks for invalid queries */ checks = sizeof(invalid_query_checks) / sizeof(char *); @@ -244,6 +247,8 @@ static void test_select_keys() WSADATA wsa_data; #endif + flb_init_env(); + config = flb_calloc(1, sizeof(struct flb_config)); if (!config) { flb_errno(); @@ -330,6 +335,8 @@ static void test_select_subkeys() WSADATA wsa_data; #endif + flb_init_env(); + config = flb_calloc(1, sizeof(struct flb_config)); if (!config) { flb_errno(); @@ -458,6 +465,8 @@ static void test_window() WSADATA wsa_data; #endif + flb_init_env(); + config = flb_calloc(1, sizeof(struct flb_config)); if (!config) { flb_errno(); @@ -639,6 +648,8 @@ static void test_snapshot() WSADATA wsa_data; #endif + flb_init_env(); + config = flb_calloc(1, sizeof(struct flb_config)); if (!config) { flb_errno(); @@ -800,6 +811,8 @@ static void test_conv_from_str_to_num() #endif out_buf.buffer = NULL; + flb_init_env(); + config = flb_config_init(); config->evl = mk_event_loop_create(256); From 23d8bfc3412a448f82086ec41b24422b0aa04e66 Mon Sep 17 00:00:00 2001 From: David Korczynski Date: Fri, 22 Sep 2023 21:29:39 +0100 Subject: [PATCH 299/315] config_format: fix memory leak There can be multiple states needing to be popped in the event of errors. Fixes: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=61733 Signed-off-by: David Korczynski --- src/config_format/flb_cf_yaml.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/config_format/flb_cf_yaml.c b/src/config_format/flb_cf_yaml.c index 5fc42bdcb1d..2a571e59ea9 100644 --- a/src/config_format/flb_cf_yaml.c +++ b/src/config_format/flb_cf_yaml.c @@ -2039,7 +2039,9 @@ static int read_config(struct flb_cf *conf, struct local_ctx *ctx, } yaml_parser_delete(&parser); - state_pop(ctx); + + /* free all remaining states */ + while (state = state_pop(ctx)); fclose(fh); ctx->level--; From 95e9e39e61d41e38567e915072b6642d9139eabb Mon Sep 17 00:00:00 2001 From: David Korczynski Date: Tue, 26 Sep 2023 06:17:57 +0100 Subject: [PATCH 300/315] config_format: adjust leak fix Signed-off-by: David Korczynski --- src/config_format/flb_cf_yaml.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/config_format/flb_cf_yaml.c b/src/config_format/flb_cf_yaml.c index 2a571e59ea9..289760ec7c0 100644 --- a/src/config_format/flb_cf_yaml.c +++ b/src/config_format/flb_cf_yaml.c @@ -2041,7 +2041,12 @@ static int read_config(struct flb_cf *conf, struct local_ctx *ctx, yaml_parser_delete(&parser); /* free all remaining states */ - while (state = state_pop(ctx)); + if (code == -1) { + while (state = state_pop(ctx)); + } + else { + state = state_pop(ctx); + } fclose(fh); ctx->level--; From c7319533abd52a286bd94f84757f671aac801d4b Mon Sep 17 00:00:00 2001 From: David Korczynski Date: Tue, 26 Sep 2023 17:32:47 +0100 Subject: [PATCH 301/315] tests: fuzzers: fix possible NULL deref We need to check for NULL here since we can cause mallocs to fail. Signed-off-by: David Korczynski --- tests/internal/fuzzers/fstore_fuzzer.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/internal/fuzzers/fstore_fuzzer.c b/tests/internal/fuzzers/fstore_fuzzer.c index 92ecf5d7a2d..e2a95106be3 100644 --- a/tests/internal/fuzzers/fstore_fuzzer.c +++ b/tests/internal/fuzzers/fstore_fuzzer.c @@ -61,6 +61,9 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) cio_utils_recursive_delete(FSF_STORE_PATH); fs = flb_fstore_create(FSF_STORE_PATH, FLB_FSTORE_FS); + if (fs == NULL) { + return 0; + } st = flb_fstore_stream_create(fs, "abc"); if (st != NULL) { fsf = flb_fstore_file_create(fs, st, "example.txt", size); From 46748f79d5255acf166ec0398c0fbd7e1d6640bf Mon Sep 17 00:00:00 2001 From: Leonardo Alminana Date: Mon, 25 Sep 2023 18:52:58 +0200 Subject: [PATCH 302/315] log_event_encoder: switched data size type to overcome msvc issue Signed-off-by: Leonardo Alminana --- include/fluent-bit/flb_log_event_encoder.h | 24 +++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/include/fluent-bit/flb_log_event_encoder.h b/include/fluent-bit/flb_log_event_encoder.h index e55cc154349..61095944098 100644 --- a/include/fluent-bit/flb_log_event_encoder.h +++ b/include/fluent-bit/flb_log_event_encoder.h @@ -75,36 +75,46 @@ #define FLB_LOG_EVENT_APPEND_UNTIL_TERMINATOR -1 +/* Note: all of the size_t casts have been replaced with + * size_t pointer casts because there is an issue + * with msvc where it doesn't honor the type promotion + * when a small constant integer is hard-coded. + * + * This should not be a problem because according to + * the standard a size_t should be as large as the + * native register size just like pointers. + */ + #define FLB_LOG_EVENT_VALUE_LIST_TERMINATOR() \ (int) FLB_LOG_EVENT_APPEND_TERMINATOR_VALUE_TYPE #define FLB_LOG_EVENT_STRING_LENGTH_VALUE(length) \ (int) FLB_LOG_EVENT_STRING_LENGTH_VALUE_TYPE, \ - (size_t) length + (size_t *) length #define FLB_LOG_EVENT_STRING_BODY_VALUE(buffer, length) \ (int) FLB_LOG_EVENT_STRING_BODY_VALUE_TYPE, \ (char *) buffer, \ - (size_t) length + (size_t *) length #define FLB_LOG_EVENT_BINARY_LENGTH_VALUE(length) \ (int) FLB_LOG_EVENT_BINARY_LENGTH_VALUE_TYPE, \ - (size_t) length + (size_t *) length #define FLB_LOG_EVENT_BINARY_BODY_VALUE(buffer, length) \ (int) FLB_LOG_EVENT_BINARY_BODY_VALUE_TYPE, \ (char *) buffer, \ - (size_t) length + (size_t *) length #define FLB_LOG_EVENT_EXT_LENGTH_VALUE(type_, length) \ (int) FLB_LOG_EVENT_EXT_LENGTH_VALUE_TYPE, \ (int) type_, \ - (size_t) length + (size_t *) length #define FLB_LOG_EVENT_EXT_BODY_VALUE(buffer, length) \ (int) FLB_LOG_EVENT_EXT_BODY_VALUE_TYPE, \ (char *) buffer, \ - (size_t) length + (size_t *) length #define FLB_LOG_EVENT_TIMESTAMP_VALUE(value) \ (int) FLB_LOG_EVENT_TIMESTAMP_VALUE_TYPE, \ @@ -176,7 +186,7 @@ #define FLB_LOG_EVENT_MSGPACK_RAW_VALUE(buffer, length) \ (int) FLB_LOG_EVENT_MSGPACK_RAW_VALUE_TYPE, \ (char *) buffer, \ - (size_t) length + (size_t *) length #define FLB_LOG_EVENT_STRING_VALUE(buffer, length) \ FLB_LOG_EVENT_STRING_LENGTH_VALUE(length), \ From 1e04bae6ce3b03f9ca784dec3c850aaec1ee1b2b Mon Sep 17 00:00:00 2001 From: Leonardo Alminana Date: Tue, 26 Sep 2023 21:07:19 +0200 Subject: [PATCH 303/315] log_event_encoder: switched data size type to overcome msvc issue Signed-off-by: Leonardo Alminana --- include/fluent-bit/flb_log_event_encoder.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/fluent-bit/flb_log_event_encoder.h b/include/fluent-bit/flb_log_event_encoder.h index 61095944098..8bca0b832ea 100644 --- a/include/fluent-bit/flb_log_event_encoder.h +++ b/include/fluent-bit/flb_log_event_encoder.h @@ -153,7 +153,7 @@ #define FLB_LOG_EVENT_INT64_VALUE(value) \ (int) FLB_LOG_EVENT_INT64_VALUE_TYPE, \ - (int64_t) value + (int64_t *) value #define FLB_LOG_EVENT_UINT8_VALUE(value) \ (int) FLB_LOG_EVENT_UINT8_VALUE_TYPE, \ @@ -169,7 +169,7 @@ #define FLB_LOG_EVENT_UINT64_VALUE(value) \ (int) FLB_LOG_EVENT_UINT64_VALUE_TYPE, \ - (uint64_t) value + (uint64_t *) value #define FLB_LOG_EVENT_DOUBLE_VALUE(value) \ (int) FLB_LOG_EVENT_DOUBLE_VALUE_TYPE, \ From 2060c092bb69091b095f1757bed96d5928142919 Mon Sep 17 00:00:00 2001 From: Leonardo Alminana Date: Wed, 27 Sep 2023 16:17:21 +0200 Subject: [PATCH 304/315] log_event_encoder: fixed 64 bit integer corner case Signed-off-by: Leonardo Alminana --- include/fluent-bit/flb_log_event_encoder.h | 65 +++++++++++++++------- 1 file changed, 46 insertions(+), 19 deletions(-) diff --git a/include/fluent-bit/flb_log_event_encoder.h b/include/fluent-bit/flb_log_event_encoder.h index 8bca0b832ea..6979634ac4c 100644 --- a/include/fluent-bit/flb_log_event_encoder.h +++ b/include/fluent-bit/flb_log_event_encoder.h @@ -28,6 +28,43 @@ #include +/* Note: + * 64 bit Windows : + * All of the size_t casts have been replaced with + * size_t pointer casts because there is an issue + * with msvc where it doesn't honor the type promotion + * when a small constant integer is hard-coded. + * + * This should not be a problem because according to + * the standard a size_t should be as large as the + * native register size just like pointers. + * + * 32 bit Windows : + * 64 bit integers are still defined as their specific + * types because the compiler handles them properly. + * + * Additionally, even though it would be preferrable to be + * able to use the optimize pragma to selectively disable + * the problematic optimizations it doesn't seem to work + * as expected. + */ + +#ifdef FLB_SYSTEM_WINDOWS +#ifdef _WIN64 +typedef size_t * flb_log_event_encoder_size_t; +typedef size_t * flb_log_event_encoder_int64_t; +typedef size_t * flb_log_event_encoder_uint64_t; +#else +typedef size_t * flb_log_event_encoder_size_t; +typedef int64_t flb_log_event_encoder_int64_t; +typedef uint64_t flb_log_event_encoder_uint64_t; +#endif +#else +typedef size_t flb_log_event_encoder_size_t; +typedef int64_t flb_log_event_encoder_int64_t; +typedef uint64_t flb_log_event_encoder_uint64_t; +#endif + #define FLB_EVENT_ENCODER_SUCCESS 0 #define FLB_EVENT_ENCODER_ERROR_UNSPECIFIED -1 #define FLB_EVENT_ENCODER_ERROR_ALLOCATION_ERROR -2 @@ -75,46 +112,36 @@ #define FLB_LOG_EVENT_APPEND_UNTIL_TERMINATOR -1 -/* Note: all of the size_t casts have been replaced with - * size_t pointer casts because there is an issue - * with msvc where it doesn't honor the type promotion - * when a small constant integer is hard-coded. - * - * This should not be a problem because according to - * the standard a size_t should be as large as the - * native register size just like pointers. - */ - #define FLB_LOG_EVENT_VALUE_LIST_TERMINATOR() \ (int) FLB_LOG_EVENT_APPEND_TERMINATOR_VALUE_TYPE #define FLB_LOG_EVENT_STRING_LENGTH_VALUE(length) \ (int) FLB_LOG_EVENT_STRING_LENGTH_VALUE_TYPE, \ - (size_t *) length + (flb_log_event_encoder_size_t) length #define FLB_LOG_EVENT_STRING_BODY_VALUE(buffer, length) \ (int) FLB_LOG_EVENT_STRING_BODY_VALUE_TYPE, \ (char *) buffer, \ - (size_t *) length + (flb_log_event_encoder_size_t) length #define FLB_LOG_EVENT_BINARY_LENGTH_VALUE(length) \ (int) FLB_LOG_EVENT_BINARY_LENGTH_VALUE_TYPE, \ - (size_t *) length + (flb_log_event_encoder_size_t) length #define FLB_LOG_EVENT_BINARY_BODY_VALUE(buffer, length) \ (int) FLB_LOG_EVENT_BINARY_BODY_VALUE_TYPE, \ (char *) buffer, \ - (size_t *) length + (flb_log_event_encoder_size_t) length #define FLB_LOG_EVENT_EXT_LENGTH_VALUE(type_, length) \ (int) FLB_LOG_EVENT_EXT_LENGTH_VALUE_TYPE, \ (int) type_, \ - (size_t *) length + (flb_log_event_encoder_size_t) length #define FLB_LOG_EVENT_EXT_BODY_VALUE(buffer, length) \ (int) FLB_LOG_EVENT_EXT_BODY_VALUE_TYPE, \ (char *) buffer, \ - (size_t *) length + (flb_log_event_encoder_size_t) length #define FLB_LOG_EVENT_TIMESTAMP_VALUE(value) \ (int) FLB_LOG_EVENT_TIMESTAMP_VALUE_TYPE, \ @@ -153,7 +180,7 @@ #define FLB_LOG_EVENT_INT64_VALUE(value) \ (int) FLB_LOG_EVENT_INT64_VALUE_TYPE, \ - (int64_t *) value + (flb_log_event_encoder_int64_t) value #define FLB_LOG_EVENT_UINT8_VALUE(value) \ (int) FLB_LOG_EVENT_UINT8_VALUE_TYPE, \ @@ -169,7 +196,7 @@ #define FLB_LOG_EVENT_UINT64_VALUE(value) \ (int) FLB_LOG_EVENT_UINT64_VALUE_TYPE, \ - (uint64_t *) value + (flb_log_event_encoder_uint64_t) value #define FLB_LOG_EVENT_DOUBLE_VALUE(value) \ (int) FLB_LOG_EVENT_DOUBLE_VALUE_TYPE, \ @@ -186,7 +213,7 @@ #define FLB_LOG_EVENT_MSGPACK_RAW_VALUE(buffer, length) \ (int) FLB_LOG_EVENT_MSGPACK_RAW_VALUE_TYPE, \ (char *) buffer, \ - (size_t *) length + (flb_log_event_encoder_size_t) length #define FLB_LOG_EVENT_STRING_VALUE(buffer, length) \ FLB_LOG_EVENT_STRING_LENGTH_VALUE(length), \ From 17dc3531c32a157f162088a007bccdf16f4b6366 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 28 Sep 2023 09:00:22 +0100 Subject: [PATCH 305/315] release: update to 2.1.11 (#7987) * release: update to 2.1.11 Signed-off-by: GitHub * Apply suggestions from code review Signed-off-by: Pat --------- Signed-off-by: GitHub Signed-off-by: Pat Co-authored-by: edsiper Co-authored-by: Pat --- CMakeLists.txt | 2 +- dockerfiles/Dockerfile | 2 +- fluent-bit-2.1.10.bb => fluent-bit-2.1.11.bb | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename fluent-bit-2.1.10.bb => fluent-bit-2.1.11.bb (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index b67b93659a7..21c469dfc62 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,7 @@ set(CMAKE_POLICY_DEFAULT_CMP0069 NEW) # Fluent Bit Version set(FLB_VERSION_MAJOR 2) set(FLB_VERSION_MINOR 1) -set(FLB_VERSION_PATCH 10) +set(FLB_VERSION_PATCH 11) set(FLB_VERSION_STR "${FLB_VERSION_MAJOR}.${FLB_VERSION_MINOR}.${FLB_VERSION_PATCH}") set(CMAKE_POSITION_INDEPENDENT_CODE ON) diff --git a/dockerfiles/Dockerfile b/dockerfiles/Dockerfile index bc0c06c5517..eca36af7dcd 100644 --- a/dockerfiles/Dockerfile +++ b/dockerfiles/Dockerfile @@ -11,7 +11,7 @@ # docker buildx build --platform "linux/amd64,linux/arm64,linux/arm/v7" -f ./dockerfiles/Dockerfile.multiarch --build-arg FLB_TARBALL=https://github.com/fluent/fluent-bit/archive/v1.8.11.tar.gz ./dockerfiles/ # Set this to the current release version: it gets done so as part of the release. -ARG RELEASE_VERSION=2.1.10 +ARG RELEASE_VERSION=2.1.11 # For multi-arch builds - assumption is running on an AMD64 host FROM multiarch/qemu-user-static:x86_64-arm as qemu-arm32 diff --git a/fluent-bit-2.1.10.bb b/fluent-bit-2.1.11.bb similarity index 100% rename from fluent-bit-2.1.10.bb rename to fluent-bit-2.1.11.bb From 7973154b017a940c6a589436ed44bae30b314cb5 Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Thu, 28 Sep 2023 11:41:42 +0200 Subject: [PATCH 306/315] build: bump to v2.2.0 Signed-off-by: Eduardo Silva --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 21c469dfc62..26842d80cbe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,8 +7,8 @@ set(CMAKE_POLICY_DEFAULT_CMP0069 NEW) # Fluent Bit Version set(FLB_VERSION_MAJOR 2) -set(FLB_VERSION_MINOR 1) -set(FLB_VERSION_PATCH 11) +set(FLB_VERSION_MINOR 2) +set(FLB_VERSION_PATCH 0) set(FLB_VERSION_STR "${FLB_VERSION_MAJOR}.${FLB_VERSION_MINOR}.${FLB_VERSION_PATCH}") set(CMAKE_POSITION_INDEPENDENT_CODE ON) From 8aecfc850f99379b6c5659ce8432d5cc810a3687 Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Thu, 28 Sep 2023 11:43:36 +0200 Subject: [PATCH 307/315] bitbake: bump to v2.2.0 Signed-off-by: Eduardo Silva --- fluent-bit-2.2.0.bb | 57 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 fluent-bit-2.2.0.bb diff --git a/fluent-bit-2.2.0.bb b/fluent-bit-2.2.0.bb new file mode 100644 index 00000000000..82de646b68a --- /dev/null +++ b/fluent-bit-2.2.0.bb @@ -0,0 +1,57 @@ +# Fluent Bit - Yocto / Bitbake +# ============================ +# The following Bitbake package the latest Fluent Bit stable release. + +SUMMARY = "Fast Log processor and Forwarder" +DESCRIPTION = "Fluent Bit is a data collector, processor and \ +forwarder for Linux. It supports several input sources and \ +backends (destinations) for your data. \ +" + +HOMEPAGE = "http://fluentbit.io" +BUGTRACKER = "https://github.com/fluent/fluent-bit/issues" + +LICENSE = "Apache-2.0" +LIC_FILES_CHKSUM = "file://LICENSE;md5=2ee41112a44fe7014dce33e26468ba93" +SECTION = "net" + +PR = "r0" +PV = "2.2.0" + +SRCREV = "v${PV}" +SRC_URI = "git://github.com/fluent/fluent-bit.git;nobranch=1" + +S = "${WORKDIR}/git" +DEPENDS = "zlib bison-native flex-native" +INSANE_SKIP_${PN}-dev += "dev-elf" + +# Use CMake 'Unix Makefiles' generator +OECMAKE_GENERATOR ?= "Unix Makefiles" + +# Fluent Bit build options +# ======================== + +# Host related setup +EXTRA_OECMAKE += "-DGNU_HOST=${HOST_SYS} " + +# Disable LuaJIT and filter_lua support +EXTRA_OECMAKE += "-DFLB_LUAJIT=Off -DFLB_FILTER_LUA=Off " + +# Disable Library and examples +EXTRA_OECMAKE += "-DFLB_SHARED_LIB=Off -DFLB_EXAMPLES=Off " + +# Systemd support (optional) +DEPENDS += "systemd" +EXTRA_OECMAKE += "-DFLB_IN_SYSTEMD=On " + +# Kafka Output plugin (disabled by default): note that when +# enabling Kafka output plugin, the backend library librdkafka +# requires 'openssl' as a dependency. +# +# DEPENDS += "openssl " +# EXTRA_OECMAKE += "-DFLB_OUT_KAFKA=On " + +inherit cmake systemd + +SYSTEMD_SERVICE_${PN} = "fluent-bit.service" +TARGET_CC_ARCH_append = " ${SELECTED_OPTIMIZATION}" From aff8811faafa8ff8715d750cf967a8b657610e21 Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Thu, 28 Sep 2023 11:44:37 +0200 Subject: [PATCH 308/315] dockerfile: bump to v2.2.0 Signed-off-by: Eduardo Silva --- dockerfiles/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dockerfiles/Dockerfile b/dockerfiles/Dockerfile index eca36af7dcd..322734377fd 100644 --- a/dockerfiles/Dockerfile +++ b/dockerfiles/Dockerfile @@ -11,7 +11,7 @@ # docker buildx build --platform "linux/amd64,linux/arm64,linux/arm/v7" -f ./dockerfiles/Dockerfile.multiarch --build-arg FLB_TARBALL=https://github.com/fluent/fluent-bit/archive/v1.8.11.tar.gz ./dockerfiles/ # Set this to the current release version: it gets done so as part of the release. -ARG RELEASE_VERSION=2.1.11 +ARG RELEASE_VERSION=2.2.0 # For multi-arch builds - assumption is running on an AMD64 host FROM multiarch/qemu-user-static:x86_64-arm as qemu-arm32 From 639bc240c9901c4002b885a8c1961ec259011396 Mon Sep 17 00:00:00 2001 From: Hiroshi Hatake Date: Thu, 28 Sep 2023 14:25:55 +0900 Subject: [PATCH 309/315] bin: windows: Restore Ctrl-C behavior on windows After supporting fleet management on Windows, Ctrl-C events won't be caught up. This commit re-enables for the behavior. Windows' ctrl event handlers stolen signals which are overlapped ones. So, we need to handle Ctrl-C events on the newly added event handler for Windows. In Windows, SIGINT and SIGBREAK are valid ctrl events on their terminal. This is why we only need to handle CTRL_C_EVENT and CTRL_BREAK_EVENT events on console handler. Signed-off-by: Hiroshi Hatake --- src/fluent-bit.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/fluent-bit.c b/src/fluent-bit.c index 51b814cfd02..141839dbbe9 100644 --- a/src/fluent-bit.c +++ b/src/fluent-bit.c @@ -550,7 +550,7 @@ static void flb_signal_exit(int signal) }; } -static void flb_signal_handler(int signal) +static void flb_signal_handler_status_line() { int len; char ts[32]; @@ -573,6 +573,12 @@ static void flb_signal_handler(int signal) /* write signal number */ write(STDERR_FILENO, ts, len); write(STDERR_FILENO, s, sizeof(s) - 1); +} + +static void flb_signal_handler(int signal) +{ + flb_signal_handler_status_line(); + switch (signal) { flb_print_signal(SIGINT); #ifndef FLB_SYSTEM_WINDOWS @@ -632,6 +638,15 @@ void flb_console_handler_set_ctx(flb_ctx_t *ctx, struct flb_cf *cf_opts) static BOOL WINAPI flb_console_handler(DWORD evType) { switch(evType) { + case 0 /* CTRL_C_EVENT_0 */: + flb_signal_handler_status_line(); + write (STDERR_FILENO, "SIGINT)\n", sizeof("SIGINT)\n")-1); + /* signal the main loop to execute reload even if CTRL_C event. + * This is necessary because all signal handlers in win32 + * are executed on their own thread. + */ + handler_signal = 2; + break; case 1 /* CTRL_BREAK_EVENT_1 */: if (flb_bin_restarting == FLB_RELOAD_IDLE) { flb_bin_restarting = FLB_RELOAD_IN_PROGRESS; @@ -1366,6 +1381,10 @@ int flb_main(int argc, char **argv) handler_signal = 0; flb_reload(ctx, cf_opts); } + else if (handler_signal == 2){ + handler_signal = 0; + break; + } #endif /* set the context again before checking the status again */ From e8579a92cb2c088de2df1bc3f984bfa2b999e4bd Mon Sep 17 00:00:00 2001 From: Hiroshi Hatake Date: Thu, 28 Sep 2023 16:40:31 +0900 Subject: [PATCH 310/315] bin: Fix build on non-Windows Signed-off-by: Hiroshi Hatake --- src/fluent-bit.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/fluent-bit.c b/src/fluent-bit.c index 141839dbbe9..e4ee6c5ca64 100644 --- a/src/fluent-bit.c +++ b/src/fluent-bit.c @@ -550,7 +550,7 @@ static void flb_signal_exit(int signal) }; } -static void flb_signal_handler_status_line() +static void flb_signal_handler_status_line(struct flb_cf *cf_opts) { int len; char ts[32]; @@ -558,7 +558,6 @@ static void flb_signal_handler_status_line() time_t now; struct tm *cur; flb_ctx_t *ctx = flb_context_get(); - struct flb_cf *cf_opts = flb_cf_context_get(); now = time(NULL); cur = localtime(&now); @@ -577,7 +576,8 @@ static void flb_signal_handler_status_line() static void flb_signal_handler(int signal) { - flb_signal_handler_status_line(); + struct flb_cf *cf_opts = flb_cf_context_get(); + flb_signal_handler_status_line(cf_opts); switch (signal) { flb_print_signal(SIGINT); @@ -637,9 +637,12 @@ void flb_console_handler_set_ctx(flb_ctx_t *ctx, struct flb_cf *cf_opts) static BOOL WINAPI flb_console_handler(DWORD evType) { + struct flb_cf *cf_opts; + switch(evType) { case 0 /* CTRL_C_EVENT_0 */: - flb_signal_handler_status_line(); + cf_opts = flb_cf_context_get(); + flb_signal_handler_status_line(cf_opts); write (STDERR_FILENO, "SIGINT)\n", sizeof("SIGINT)\n")-1); /* signal the main loop to execute reload even if CTRL_C event. * This is necessary because all signal handlers in win32 From e2e617567f592c02a40b77b56eea5b94f6e22910 Mon Sep 17 00:00:00 2001 From: Erik Bledsoe Date: Tue, 3 Oct 2023 08:48:31 -0400 Subject: [PATCH 311/315] documentation: update users graphic (#7999) Added Intel logo as requested in issue #7620 Signed-off-by: Erik Bledsoe --- documentation/fluentbit_users.png | Bin 93439 -> 108970 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/documentation/fluentbit_users.png b/documentation/fluentbit_users.png index b5c43dacba9b0af9de6b20cf6a678f736e93d4e7..c16785507ae81fd317bb84b4d863a0b8c1763ded 100644 GIT binary patch literal 108970 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

    VLh3>`J`8%y5>FR_76K9a9V(=i^x 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 WJ5`I36Or6$$7N&7i&cim+y4PVL@Lz) From 7427038b4208fb4f1df2bffe7e2017e7d36c4ed8 Mon Sep 17 00:00:00 2001 From: Leonardo Alminana Date: Thu, 5 Oct 2023 09:12:39 +0200 Subject: [PATCH 312/315] file: fixed a typo Signed-off-by: Leonardo Alminana --- src/flb_file_unix.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/flb_file_unix.c b/src/flb_file_unix.c index d8e48840eb3..37e6cedaac7 100644 --- a/src/flb_file_unix.c +++ b/src/flb_file_unix.c @@ -43,7 +43,7 @@ static char *expand_tilde(const char *path, struct passwd *uinfo = NULL; if (expansion_attempted != NULL) { - expansion_attempted = FLB_TRUE; + *expansion_attempted = FLB_TRUE; } if (path[0] == '~') { @@ -112,7 +112,7 @@ static char *expand_tilde(const char *path, int *expansion_attempted) { if (expansion_attempted != NULL) { - expansion_attempted = FLB_FALSE; + *expansion_attempted = FLB_FALSE; } return flb_strdup(path); From 13ca67a4c0c78d8fce2c53c3542bf30317366431 Mon Sep 17 00:00:00 2001 From: Leonardo Alminana Date: Thu, 5 Oct 2023 09:17:34 +0200 Subject: [PATCH 313/315] out_oracle_log_analytics: updated file read function name Signed-off-by: Leonardo Alminana --- plugins/out_oracle_log_analytics/oci_logan_conf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/out_oracle_log_analytics/oci_logan_conf.c b/plugins/out_oracle_log_analytics/oci_logan_conf.c index a3980318465..c113fa2cd30 100644 --- a/plugins/out_oracle_log_analytics/oci_logan_conf.c +++ b/plugins/out_oracle_log_analytics/oci_logan_conf.c @@ -103,7 +103,7 @@ static int load_oci_credentials(struct flb_oci_logan *ctx) char* key = NULL; char* val; - content = flb_file_read(ctx->config_file_location); + content = flb_file_read_contents(ctx->config_file_location); if (content == NULL || flb_sds_len(content) == 0) { return -1; From 53cd3cad5a2167404e2bc56df5de71dc0aa9a92d Mon Sep 17 00:00:00 2001 From: Leonardo Alminana Date: Thu, 5 Oct 2023 13:28:05 +0200 Subject: [PATCH 314/315] in_node_exporter_metrics: reverted an accidental regression Signed-off-by: Leonardo Alminana --- plugins/in_node_exporter_metrics/ne_textfile_linux.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/plugins/in_node_exporter_metrics/ne_textfile_linux.c b/plugins/in_node_exporter_metrics/ne_textfile_linux.c index 8d66bc58fec..05f5f82a210 100644 --- a/plugins/in_node_exporter_metrics/ne_textfile_linux.c +++ b/plugins/in_node_exporter_metrics/ne_textfile_linux.c @@ -144,6 +144,13 @@ static int textfile_update(struct flb_ne *ctx) entry = mk_list_entry(head, struct flb_slist_entry, _head); /* Update metrics from text file */ contents = flb_file_read_contents(entry->str); + + if (contents == NULL) { + flb_plg_debug(ctx->ins, "skip invalid file of prometheus: %s", + entry->str); + continue; + } + if (flb_sds_len(contents) == 0) { flb_plg_debug(ctx->ins, "skip empty payload of prometheus: %s", entry->str); From 5a5bf9f3608a077ec5775ebf38bb2ce4a6f80d53 Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Fri, 6 Jun 2025 16:54:21 -0600 Subject: [PATCH 315/315] file_unix: allocate path from the heap Signed-off-by: Eduardo Silva --- src/flb_file_unix.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/flb_file_unix.c b/src/flb_file_unix.c index 37e6cedaac7..85b55e291a7 100644 --- a/src/flb_file_unix.c +++ b/src/flb_file_unix.c @@ -78,7 +78,7 @@ static char *expand_tilde(const char *path, else { dir = getenv("HOME"); if (!dir) { - return path; + return flb_strdup(path); } }

1. Download a simple runtime (build for ubuntu 20.04 64 bits, other platforms please build - from the source code) + from the source code)